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
Handle complex POST/PATCH requests in RESTful API
Search
Dmitry Petrov
December 12, 2012
1
180
Handle complex POST/PATCH requests in RESTful API
Report with a speech on the 2012 sfcampua
Dmitry Petrov
December 12, 2012
Tweet
Share
More Decks by Dmitry Petrov
See All by Dmitry Petrov
Обработка сложных POST/PATCH запросов в RESTfu API
fightmaster
1
520
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.5k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
The Language of Interfaces
destraynor
162
25k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.9k
Six Lessons from altMBA
skipperchong
28
4k
4 Signs Your Business is Dying
shpigford
185
22k
Optimizing for Happiness
mojombo
379
70k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
9
590
Navigating Team Friction
lara
190
15k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
Transcript
Dmitry Petrov
[email protected]
Handle Complex POST/PATCH requests in RESTful API
ProFIT Dmitry Petrov The system of process control printing Product
Fulfillment and Information Tracking
ProFIT Dmitry Petrov Daily: ~ 1 000 orders ~1 000
000 print productions 1 hour of downtime ~ 25 000$ Product Fulfillment and Information Tracking
RESTful API Dmitry Petrov ~ 60 entity ~100 API endpoints
Complex business logic RESTful API for ProFIT
Dmitry Petrov GET /api/orders/12/items/fg45sf54 The server response: { "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 The server response: { "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, examples GET
Dmitry Petrov GET /api/product-box-types/12-type/associations The server response: [ { "id":
1, "product": "business_cards", "quantity": 1000 }, ...... ] GET /api/machines/KARAT+1/hot-folders The server response: [ { "path":"/home/somepath/", "types": [ "34-f-Type", "33-S-Type", ...... ] }, ...... ] GET /api/press-sheets/134/label The server response: { "label": "epl string" } RESTful API, examples GET
Dmitry Petrov POST http://localhost/api/press-sheets/12/transition Body of the request: { "transition":
"start:printing:front", "note": null } POST http://localhost/api/orders, PUT http://localhost/api/orders/12 Body of the request: { "id": 12, "client": { "firstname": "Dmitry", "lastname": "Petrov", "email": "", "phone": null, "address": { "country": "Russia", "city": "Saratov", "zip": 123456, "street": "Vavilova", "residentional": false } } } RESTful API, examples POST / PUT
Dmitry Petrov PATCH http://localhost/api/orders/12 Body of the request: { "client":
{ "email": "", "phone": null } } PATCH http://localhost/api/orders/12 Body of the request: { "client": { "email": "" }, "address": { "street": "Vavilova", "residentional": true } } Object: { "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, examples PATCH
Dmitry Petrov Become thoughtful . . .
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 The server response: { "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 } } } Examples of DTO
Dmitry Petrov { "transition": "start:printing:front", "note": null } { "label":
"epl string" } [ { "path":"/home/somepath/", "types": [ "34-f-Type", ...... ] }, ...... ] Examples of DTO
Dmitry Petrov Reducing the number of queries Independence from API
"Makes you think" The benefits of using DTO pattern
Dmitry Petrov FOSRestBundle JMSSerializerBundle LiipHelloBundle FOSCommentBundle Popular bundles and examples
Dmitry Petrov GET /api/orders/12 The server response: { "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 method
Dmitry Petrov POST /api/orders, Body of the request: { "id":
12, "client": { "firstname": "Dmitry", "lastname": "Petrov", "email": "", "phone": null, "address": { "country": "Russia", "city": "Saratov", "zip": 123456, "street": "Vavilova", "residentional": false } } } JMSSerializerBundle & POST method
Dmitry Petrov JMSSerializerBundle & PATCH method
Dmitry Petrov $this->deserialize($request, 'Rest\OrderDTO', 'json'); JMSSerializerBundle
MERGE Dmitry Petrov $this->merge($oldDTO, $newDTO); JMSSerializerBundle
Dmitry Petrov Merging DTO
Dmitry Petrov PATCH /api/orders/12 Request: { "client": { "email": "",
"phone": null } } JMSSerializerBundle & PATCH method
Problems / Disadvantages Dmitry Petrov GET - serialization of null
values PATCH - deserialized into an object PATCH - merge null values MERGE - a lot of useless code RESTful API, JMSSerializerBundle
Dmitry Petrov SimpleThingsFormSerializerBundle July 15, 2012 SimpleThingsFormSerializerBundle
Dmitry Petrov SimpleThingsFormSerializerBundle
Dmitry Petrov GET /api/orders/12 The server response: { "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
Problems / Disadvantages Dmitry Petrov Converting data into string Lack
of support PATCH method (v. 2.0) The ideological aversion The dirty mix *Type and *DTO SimpleThingsFormSerializerBundle
Dmitry Petrov Отпуск
Dmitry Petrov Отпуск
Dmitry Petrov Отпуск
Requirements Dmitry Petrov (Un)Serialization of objects Preservation of the type
in data Metadata cache Reinvent the wheel
Assumptions Dmitry Petrov The output format is json Metadata is
stored in yml There are get/set methods Reinvent the wheel
After 36 hours... train Saratov - Kiev is comming 30
hours Dmitry Petrov SimpleSerializer SimpleSerializerBundle Details can be found on the habr Reinvent the wheel
Benefits Dmitry Petrov This is library Separation of serialization rules
and format Absence voiced disadvantages "Inteligent" deserialization SimpleSerializer
Dmitry Petrov SimpleSerializer & POST / PATCH
Dmitry Petrov SimpleSerializer & POST method
What? Where? When? Dmitry Petrov Parameters of requests Data transfer
objects Business logic RESTful API, validation
Parameters of requests Dmitry Petrov /api/orders/12 /api/boxes/BOX-1-1 /api/orders?valid=true RESTful API,
validation
Routing requirements Dmitry Petrov RESTful API, validation
Dmitry Petrov ParameterChecker RESTful API, validation
Dmitry Petrov RESTful API, validation
Dmitry Petrov RESTful API, validation
Dmitry Petrov AbstractRestController RESTful API, validation
Dmitry Petrov PATCH /api/orders/12 Body of the request: { "client":
{ "email": "", "comment": "I'm hacker" } } Object: { "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, validation
Dmitry Petrov POST /api/press-sheets/12/transition Body of the request: { "transition":
"start:printing:front", "note": null, "comment": "I'm hacker" } POST /api/press-sheets/12/transition Body of the request: { "transition": "start:printing:front", "comment": "I'm hacker" } Object: { "transition": "start:printing:front", "note": null } RESTful API, validation
Dmitry Petrov How, where and when to handle these situations?
RESTful API, validation
Dmitry Petrov REST APIs with Symfony2: The Right Way
Dmitry Petrov Disadvantages Conventionalism Duplication of code Only works as
filter REST APIs with Symfony2: The Right Way
Dmitry Petrov "Inteligent" deserialization 3 modes of deserialization: Strict, Medium
strict, Non-strict + Support groups SimpleSerializer
Dmitry Petrov RESTful API, handle of DTO
Dmitry Petrov RESTful API, handle of domain object
Behat, PHPUnit Dmitry Petrov Controllers Data access layer Service layer
RESTful API, testing
Dmitry Petrov RESTful API, Behat scenario
Problems Dmitry Petrov Run time: Behat ~ 90 minutes PHPUnit
~ 5 minutes RESTful API, testing
WSSE Dmitry Petrov Atom Authentication How to create a custom
Authentication Provider EscapeWSSEAuthenticationBundle (v. 2.0) MopaWSSEAuthenticationBundle (v. 2.1) RESTful API, authentication
WSSE Header Dmitry Petrov X-WSSE: UsernameToken Username="bob", PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=", Nonce="d36e316282959a9ed4c89851497a717f", Created="2003-12-15T14:43:07Z"
RESTful API, authentication
Password digest Dmitry Petrov Base64 (SHA1 (Nonce + CreationTimestamp +
Password)) RESTful API, authentication
Dmitry Petrov RESTful API, The End
Any questions? Dmitry Petrov @old_fightmaster RESTful API https://github.com/opensoft https://github.com/fightmaster Special
thanks to ProFIT team