Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Обработка сложных POST/PATCH запросов в RESTfu API
Search
Dmitry Petrov
December 03, 2012
1
470
Обработка сложных POST/PATCH запросов в RESTfu API
Доклад с выступления на sfcampua 2012
Dmitry Petrov
December 03, 2012
Tweet
Share
More Decks by Dmitry Petrov
See All by Dmitry Petrov
Handle complex POST/PATCH requests in RESTful API
fightmaster
1
160
Featured
See All Featured
Writing Fast Ruby
sferik
626
60k
Build The Right Thing And Hit Your Dates
maggiecrowley
31
2.3k
Designing for Performance
lara
604
68k
Designing Experiences People Love
moore
138
23k
The Cost Of JavaScript in 2023
addyosmani
43
5.9k
Navigating Team Friction
lara
183
14k
Side Projects
sachag
452
42k
Documentation Writing (for coders)
carmenintech
65
4.4k
Building a Scalable Design System with Sketch
lauravandoore
459
33k
A Tale of Four Properties
chriscoyier
156
22k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.6k
Unsuck your backbone
ammeep
668
57k
Transcript
Dmitry Petrov
[email protected]
Обработка сложных POST/PATCH запросов в RESTful API
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
Dmitry Petrov Призадумались . . .
DTO Dmitry Petrov Data Transfer Object DTO attribute1: String attribute2:
String Assembler createDTO updateDomainObject serialize 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 FOSRestBundle JMSSerializerBundle LiipHelloBundle FOSCommentBundle Популярные бандлы и примеры
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 JMSSerializerBundle & PATCH метод
Dmitry Petrov $this->deserialize($request, 'Rest\OrderDTO', 'json'); JMSSerializerBundle
MERGE Dmitry Petrov $this->merge($oldDTO, $newDTO); JMSSerializerBundle
Dmitry Petrov Сливание DTO
Dmitry Petrov PATCH /api/orders/12 Request: { "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 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 Отпуск
Dmitry Petrov Отпуск
Требования Dmitry Petrov (Де)Сериализация объектов Сохранение типа у данных Кеширование
метаданных Изобретаем велосипед
Допущения Dmitry Petrov Выходной формат json Метадата хранится в yml
Всегда есть get/set методы Изобретаем велосипед
Через 36 часов... поезд Саратов - Киев идет 30 часов
Dmitry Petrov SimpleSerializer SimpleSerializerBundle Подробности можно прочитать на хабре Изобретаем велосипед
Преимущества Dmitry Petrov Библиотека Разделение правил сериализации от формата Отсутствие
озвученных минусов "Интеллектуальная" десериализация SimpleSerializer
Dmitry Petrov SimpleSerializer & POST / PATCH
Dmitry Petrov SimpleSerializer & POST метод
Что? Где? Когда? Dmitry Petrov Параметры запросов Объекты передачи данных
Бизнес-логика RESTful API, валидация
Параметры запросов Dmitry Petrov /api/orders/12 /api/boxes/BOX-1-1 /api/orders?valid=true RESTful API, валидация
Routing requirements Dmitry Petrov RESTful API, валидация
Dmitry Petrov ParameterChecker RESTful API, валидация
Dmitry Petrov RESTful API, валидация
Dmitry Petrov RESTful API, валидация
Dmitry Petrov AbstractRestController 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
Dmitry Petrov RESTful API, обработка DTO
Dmitry Petrov RESTful API, обработка объекта
Behat, PHPUnit Dmitry Petrov Контроллеры Data access layer Service layer
RESTful API, тестирование
Dmitry Petrov RESTful API, пример Behat сценария
Проблемы Dmitry Petrov Время выполнения: Behat ~ 90 минут PHPUnit
~ 5 минут RESTful API, тестирование
WSSE Dmitry Petrov Atom Authentication How to create a custom
Authentication Provider EscapeWSSEAuthenticationBundle (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 RESTful API, The End
Вопросы? Dmitry Petrov @old_fightmaster RESTful API https://github.com/opensoft https://github.com/fightmaster Отдельное спасибо
команде ProFIT