Pull to refresh

Comments 31

Чем Вам не подошел какой либо PHP RESTful микрофреймворк (Slim, Lumen, Silex, etc.), или вообще можно взять Yii Framework 2 где из коробки есть возможность сгенерировать RESTFul контроллеры для любых моделек?

ИМХО. Исходя из поста создалось впечатление что его название должны было выглядеть так — «PHP и OData: пересаживаемся с PHP RESTful-фреймворка на велосипед от Microsoft»
Я пользовался Yii2 RESTful. Это отличный инструмент. Но столкнулся с тем, что приходится делать вещи, которые можно было бы не делать. Например, понадобилась произвольная фильтрация. В OData можно сделать условие типа такого
$filter=((weight ge 100 or weight le 10) and price le 15)
И оно будет работать без какого-либо дополнительного программирования.
Возможно я не совсем понял, но если эти фильтры задаются клиентом — ((weight ge 100 or weight le 10) and price le 15) то выходит как-то не кошерно, особенно если у нас будет get запрос.

А если на сервере, то как бы в Yii2 это тоже решается в одну строку, добавлением простого where —
$query->where( [ [ 'or', 'weight<100',  'weight>10' ], 'and', 'price>1' ] ) 
В случае с OData не надо ничего писать для извлечения данных, если действовать как описано в статье. Yii2 дает готовый инструмент только на уровне контроллеров, при этом надо самому делать валидацию, защиту от SQL инъекций. Например, так просто нельзя ведь написать, 'weight<100'. Надо как минимум проверить, что пришедший с клиента weight это колонка, а не что-то вроде '; drop table ... --'.
POData дает готовый инструмент не только на уровне контроллеров, но и сам делает валидацию, помогает в извлечении данных. А если использовать стандартный грид с поддержкой OData (типа OpenUI5), то о том, как будет выглядеть GET запрос, можно даже не заботиться, грид сформирует запрос за вас.
1. Нет ничего страшного в weight === '; drop table… --', если вы правильно работаете с базой.
2. Довольно опасно давать клиенту делать любые запросы к базе — он с лёгкостью может устроить вам DOS сделав запрос по непроиндексированным полям в большой таблице.
Насчет 1, дело в том, что валидировать надо не только значения, но и названия колонок, по которым выполняется фильтрация, если это название получено с клеинта.
По поводу 2, замечание совершенно замечательное. Такие вещи можно обрабатывать в обертке над QueryProvider, делать дополнительную проверку для нужных таблиц, чтобы было такое-то условие. Это может быть не всегда просто в реализации, но делать это действительно стоит.
Названия колонок тоже нужно экранировать в SQL запросе.
Можно пример? Мне приходит на ум только сопоставление названий со схемой базы. Но в любом случае для этого надо сперва распарсить условие. Либо передавать условие от клиента сразу в виде дерева. Помимо этого и операторы тоже надо валидировать. На мой взгляд в итоге получается громоздко и это надо писать самому. Либо можно взять готовое и использовать OData как вариант.
а если с клиента пришло вместо where:
where`=1; drop table ... --?
Ну вот, вы ожидаете, что пришел например id и делаете запрос
select * from `account` where `id` = 1;
а пришел не id, а ` = 1; select 1; --
Тогда вы сгенеририуете такой sql:
select * from `account` where `id` = 1; select 1; -- ` = 1
Он выполнится без exception. Вместо select 1 можно указать что угодно.
Поэтому стоит сравнивать названия колонок со схемой, да и условия >=, < и т.д. тоже валидировать.
Для биндинга значений
то есть вы хотите сказать, что биндинг, встроенный в pdo (используемый в yii2), не защитит в данном случае от инъекции?
Вы экранирование забыли:
select * from `account` where `id\` = 1; select 1; -- ` = 1


С экранированием да, лучше. Но опять же, надо парсить самостоятельно запрос от клиента. А можно этого не делать, а взять готовый инструмент.
odata.svc/Products?&$format=json&$filter=id le 5&$orderby=id desc,
Да ну нафиг такое парсить :-) Лучше такое:

/product.id<5.^id.json
надо самому делать валидацию, защиту от SQL инъекций

Не надо ничего делать самому, там же PDO, просто написать не weight<100, а передать параметром — weight<:weight и забиндить значения, передавая в тот же where дополнительный массив со значениями, а PDO сам все сделает.

стандартный грид с поддержкой OData (типа OpenUI5)

В yii есть же GridView
Да и вообще для любого RESTFul фреймворка можно использовать любой RESTFul грид, которых много в сети.

Не хочу холиварить, но просто мне Ваш пост показался как будь-то Вы нашли панацею, но на самом деле очередной велосипед.
При чем исходя из поста кода Вам пришлось дописать в разы больше чем если бы Вы использовали другие решения.
'weight<:weight'

Само слово weight, полученное с клиента надо тоже валидировать, я об этом, не о значении 100.
пришлось дописать в разы больше

Ну не в разы, но много писать самому пришлось, я об этом упомянул. Но надо учесть, что я как-то уже реализовывал универсальный механизм и видел, как коллеги делали универсальный механизм для фильтрации данных — там кода было куда больше. А если не делать универсальный механизм, то придется много писать кода под конкретные случаи, что будет путаться с бизнес-логикой, это труднее на мой взгляд поддерживать.
GridView штука хорошая, но и в ней к сожалению есть ограничения. OData дает больше возможностей, меня это и привлекает. Не панацея, но инструмент на мой взгляд действительно достойный.
Как в OData конкурентно добавлять значения в коллекции?
В настоящий момент в POData добавление не реализовано, только GET. Если мне понадобится в процессе добавление, редактирование, удаление, буду реализовывать. Насчет конкурентно добавлять уточните, пожалуйста, что имеете ввиду — вариант обернуть запросы в транзакцию подходит?
Что значит «если»? У вас ридонли апи, что ли? :-)
Конкурентно — это два пользователя, например, одновременно добавляют в коллекцию каждый своё значение. Как строятся их запросы, чтобы приславший запрос вторым не затёр изменения внесённые первым?
В библиотеке реализовано чтение данных. Запись можно реализовать самому. В целях POData автор форка ставил реализацию INSERT, UPDATE, DELETE, но до сих пор это не сделано. В принципе, при реализации можно и учесть моменты с конкурентными запросами, хотя это не всегда надо. Скажите для примера, где это хорошо учтено?
В моём велосипеде передаётся диф изменений. В OData как-то не нашёл ничего подобного. Это вообще беда многих апи, а от «стандарта» ожидаешь, что детских болезней там не будет.
А что, хороший вариант
пагинацию

пейджинацию тогда уж. А лучше по-русски — постраничное представление.
Мы то же рассматривали OData, благо серверный стек — WebApi, но решили отказаться по следующим причинам:
1. Хранилища данных не всегда поддершивают одну и ту же модель данных. Например различаются свойства объектов, операции фильтрации, которые можно над ними совершать. Затягивать весь объем данных — просто нереально. Или например джоины данных в памяти.
2. Запросы прекрасны до тех пор, пока вы контролируете клиентов этого апи. Если вы их не контролируетет, то выдавать такой широкий спектр фильтров — опасно, так как могут возникнуть очень жуткие головняки с обратной совместимостью.

Из всего этого просто сделали Hypermedia Based Api по типу Collection+Json.
Нет, ну ладно Вам не угодил Yii2, ладно микрофреймворки. А какие преимущества у OData перед Apigility? Мне кажется, вы испытали НАМНОГО больше боли при попытке построения REST, чем должны были. А потом еще выяснилось, что POST/PUT/UPDATE и DELETE там вообще не реализованы.
Для чего мне понадобилась OData. У меня проект на Yii2. Проект представляет собой REST API. Для него мне понадобился инструмент для произвольных выборок из базы, чтобы внутренние клиенты компании могли вести разработку своих проектов не ожидая, пока наша команда реализует для них очередной метод для отдачи чего-либо. POData дает именно то, что надо — готовый инструмент для произвольных выборок, поэтому лично меня не смущает на данный момент поддержка только GET.
Другие инструменты мне тоже интересны. Как в Apigility реализована фильтрация по произвольным условиям? Я по докам вижу только то, что можно задать набор строгих равенств, которые будут объединены только через логическое И: что-то вроде localhost:8000/books?title=php&sort=year
Ну и OData — стандарт и под него подстроились некоторые UI библиотеки, что тоже на мой взгляд очень привлекательно.
Sign up to leave a comment.

Articles