Обработка сложных post/patch запросов в restful api
DESCRIPTION
Доклад с sfcampua 2012TRANSCRIPT
ProFIT
Dmitry Petrov
Система управления производственными
процессами типографии
Product Fulfillment and Information Tracking
ProFIT
Dmitry Petrov
Ежедневно:~ 1 000 заказов~1 000 000 печатной продукции1 час простоя ~ 25 000$
Product Fulfillment and Information Tracking
RESTful API
Dmitry Petrov
~ 60 entity~100 API endpointsСложная бизнес логика
RESTful API для ProFIT
Dmitry Petrov
GET /api/orders/12/items/fg45sf54Ответ сервера:{
"id": "fg45sf54",
"url": "http://localhost/api/orders/12/items/fg45sf54",
"product": "business cards",
"quantity": 1000,
"previews": {
"front": {
"large": "http://localhost/large/front.jpg",
"medium": "http://localhost/medium/front.jpg",
"small": "http://localhost/small/front.jpg",
},
"back": {
"large": "http://localhost/large/back.jpg",
"medium": "http://localhost/medium/back.jpg",
"small": "http://localhost/small/back.jpg",
}
}
}
GET /api/orders/12Ответ сервера:{
"id": 12,
"url": "http://localhost/api/orders/12",
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": null,
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
RESTful API, примеры GET
Dmitry Petrov
GET /api/product-box-types/12-type/associationsОтвет сервера:[
{
"id": 1,
"product": "business_cards",
"quantity": 1000
},
......
]
GET /api/machines/KARAT+1/hot-foldersОтвет сервера:[
{
"path":"/home/somepath/",
"types": [
"34-f-Type",
"33-S-Type",
......
]
},
......
]
GET /api/press-sheets/134/labelОтвет сервера:{
"label": "epl string"
}
RESTful API, примеры GET
Dmitry Petrov
POST http://localhost/api/press-sheets/12/transitionТело запроса:{
"transition": "start:printing:front",
"note": null
}
POST http://localhost/api/orders,PUT http://localhost/api/orders/12Тело запроса:{
"id": 12,
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": null,
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
RESTful API, примеры POST / PUT
Dmitry Petrov
PATCH http://localhost/api/orders/12Тело запроса:{
"client": {
"email": "",
"phone": null
}
}
PATCH http://localhost/api/orders/12Тело запроса:{
"client": {
"email": ""
},
"address": {
"street": "Vavilova",
"residentional": true
}
}
Объект:{
"id": 12,
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "[email protected]",
"phone": "8-888-999",
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
RESTful API, примеры PATCH
DTO
Dmitry Petrov
Data Transfer Object
DTO
attribute1: String
attribute2: String
Assembler
createDTO
updateDomainObjectserialize
deserialize
DomainObject1
attribute1: String
DomainObject2
attribute2: String
Dmitry Petrov
GET /api/orders/12Ответ сервера:{
"id": 12,
"url": "http://localhost/orders/12",
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": null,
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
Примеры DTO
Dmitry Petrov
{
"transition": "start:printing:front",
"note": null
}
{
"label": "epl string"
}
[
{
"path":"/home/somepath/",
"types": [
"34-f-Type",
......
]
},
......
]
Примеры DTO
Dmitry Petrov
Уменьшение количества запросовНезависимость от API"Заставляет думать"
Преимущества паттерна DTO
Dmitry Petrov
FOSRestBundleJMSSerializerBundle LiipHelloBundleFOSCommentBundle
Популярные бандлы и примеры
Dmitry Petrov
GET /api/orders/12Ответ сервера:{
"id": 12,
"url": "http://localhost/api/orders/12",
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": null, "address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
JMSSerializerBundle & GET метод
Dmitry Petrov
POST /api/orders,Тело запроса:{
"id": 12,
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": null,
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
JMSSerializerBundle & POST метод
Dmitry Petrov
$this->deserialize($request, 'Rest\OrderDTO', 'json');
JMSSerializerBundle
Dmitry Petrov
PATCH /api/orders/12Request:{
"client": {
"email": "",
"phone": null }
}
JMSSerializerBundle & PATCH метод
Проблемы / Минусы
Dmitry Petrov
GET - сериализация null значенийPATCH - десериализация в объектPATCH - merge null значенийMERGE - много бесполезного кода
RESTful API, JMSSerializerBundle
Dmitry Petrov
SimpleThingsFormSerializerBundle
15 июля 2012
SimpleThingsFormSerializerBundle
Dmitry Petrov
GET /api/orders/12Ответ сервера:{
"id": "12",
"url": "http://localhost/orders/12",
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "",
"phone": "",
"address": {
"country": "Russia",
"city": "Saratov",
"zip": "123456",
"street": "Vavilova",
"residentional": "false"
}
}
}
SimpleThingsFormSerializerBundle
Проблемы / Минусы
Dmitry Petrov
Конвертирование данных в stringОтсутствие поддержки PATCH (v. 2.0)
Идеологическая неприязньГрязная смесь *Type и *DTO
SimpleThingsFormSerializerBundle
Требования
Dmitry Petrov
(Де)Сериализация объектовСохранение типа у данныхКеширование метаданных
Изобретаем велосипед
Допущения
Dmitry Petrov
Выходной формат jsonМетадата хранится в ymlВсегда есть get/set методы
Изобретаем велосипед
Через 36 часов...поезд Саратов - Киев идет 30 часов
Dmitry Petrov
SimpleSerializerSimpleSerializerBundle
Подробности можно прочитать на хабре
Изобретаем велосипед
Преимущества
Dmitry Petrov
БиблиотекаРазделение правил сериализации от форматаОтсутствие озвученных минусов"Интеллектуальная" десериализация
SimpleSerializer
Что? Где? Когда?
Dmitry Petrov
Параметры запросовОбъекты передачи данныхБизнес-логика
RESTful API, валидация
Параметры запросов
Dmitry Petrov
/api/orders/12/api/boxes/BOX-1-1/api/orders?valid=true
RESTful API, валидация
Dmitry Petrov
PATCH /api/orders/12Тело запроса:{
"client": {
"email": "",
"comment": "I'm hacker" }
}
Объект:{
"id": 12,
"client": {
"firstname": "Dmitry",
"lastname": "Petrov",
"email": "[email protected]",
"phone": "8-888-999",
"address": {
"country": "Russia",
"city": "Saratov",
"zip": 123456,
"street": "Vavilova",
"residentional": false
}
}
}
RESTful API, валидация
Dmitry Petrov
POST /api/press-sheets/12/transitionТело запроса:{
"transition": "start:printing:front",
"note": null,
"comment": "I'm hacker"}
POST /api/press-sheets/12/transitionТело запроса:{
"transition": "start:printing:front",
"comment": "I'm hacker"}
Объект:{
"transition": "start:printing:front",
"note": null
}
RESTful API, валидация
Dmitry Petrov
Как, где и когда обрабатывать эти ситуации?
RESTful API, валидация
Dmitry Petrov
REST APIs with Symfony2: The Right Way
Dmitry Petrov
Недостатки
РутиностьДублирование кода Работает лишь как фильтр
REST APIs with Symfony2: The Right Way
Dmitry Petrov
"Интеллектуальная"
десериализация3 режима десериализации:
Strict, Medium strict, Non-strict+
Поддержка групп
SimpleSerializer
Behat, PHPUnit
Dmitry Petrov
Контроллеры
Data access layerService layer
RESTful API, тестирование
Проблемы
Dmitry Petrov
Время выполнения:Behat ~ 90 минутPHPUnit ~ 5 минут
RESTful API, тестирование
WSSE
Dmitry Petrov
Atom AuthenticationHow to create a custom Authentication ProviderEscapeWSSEAuthenticationBundle (v. 2.0)
MopaWSSEAuthenticationBundle (v. 2.1)
RESTful API, аутентификация
WSSE Header
Dmitry Petrov
X-WSSE: UsernameToken Username="bob",
PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=",
Nonce="d36e316282959a9ed4c89851497a717f",
Created="2003-12-15T14:43:07Z"
RESTful API, аутентификация
Password digest
Dmitry Petrov
Base64 (SHA1 (Nonce + CreationTimestamp + Password))
RESTful API, аутентификация
Вопросы?
Dmitry Petrov
@old_fightmaster
RESTful API
https://github.com/opensofthttps://github.com/fightmaster
Отдельное спасибо команде ProFIT