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
510
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
19
1.2k
BBQ
matthewcrist
88
9.6k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.8k
Thoughts on Productivity
jonyablonski
69
4.6k
Automating Front-end Workflow
addyosmani
1370
200k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
We Have a Design System, Now What?
morganepeng
52
7.6k
Side Projects
sachag
453
42k
Code Review Best Practice
trishagee
68
18k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.2k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
420
Writing Fast Ruby
sferik
628
61k
Transcript
Dmitry Petrov old.fightmaster@gmail.com 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": "old.fightmaster@gmail.com", "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": "old.fightmaster@gmail.com", "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