Handle complex POST/PATCH requests in RESTful API
-
Upload
fightmaster -
Category
Documents
-
view
5.929 -
download
3
description
Transcript of 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 productions1 hour of downtime ~ 25 000$
Product Fulfillment and Information Tracking
RESTful API
Dmitry Petrov
~ 60 entity~100 API endpointsComplex business logic
RESTful API for ProFIT
Dmitry Petrov
GET /api/orders/12/items/fg45sf54The 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/12The 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/associationsThe server response:[
{
"id": 1,
"product": "business_cards",
"quantity": 1000
},
......
]
GET /api/machines/KARAT+1/hot-foldersThe server response:[
{
"path":"/home/somepath/",
"types": [
"34-f-Type",
"33-S-Type",
......
]
},
......
]
GET /api/press-sheets/134/labelThe server response:{
"label": "epl string"
}
RESTful API, examples GET
Dmitry Petrov
POST http://localhost/api/press-sheets/12/transitionBody of the request:{
"transition": "start:printing:front",
"note": null
}
POST http://localhost/api/orders,PUT http://localhost/api/orders/12Body 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/12Body of the request:{
"client": {
"email": "",
"phone": null
}
}
PATCH http://localhost/api/orders/12Body 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
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/12The 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 queriesIndependence from API"Makes you think"
The benefits of using DTO pattern
Dmitry Petrov
FOSRestBundleJMSSerializerBundle LiipHelloBundleFOSCommentBundle
Popular bundles and examples
Dmitry Petrov
GET /api/orders/12The 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
$this->deserialize($request, 'Rest\OrderDTO', 'json');
JMSSerializerBundle
Dmitry Petrov
PATCH /api/orders/12Request:{
"client": {
"email": "",
"phone": null }
}
JMSSerializerBundle & PATCH method
Problems / Disadvantages
Dmitry Petrov
GET - serialization of null valuesPATCH - deserialized into an objectPATCH - merge null valuesMERGE - a lot of useless code
RESTful API, JMSSerializerBundle
Dmitry Petrov
SimpleThingsFormSerializerBundle
July 15, 2012
SimpleThingsFormSerializerBundle
Dmitry Petrov
GET /api/orders/12The 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 stringLack of support PATCH method (v. 2.0)
The ideological aversionThe dirty mix *Type and *DTO
SimpleThingsFormSerializerBundle
Requirements
Dmitry Petrov
(Un)Serialization of objectsPreservation of the type in dataMetadata cache
Reinvent the wheel
Assumptions
Dmitry Petrov
The output format is jsonMetadata is stored in ymlThere are get/set methods
Reinvent the wheel
After 36 hours...train Saratov - Kiev is comming 30 hours
Dmitry Petrov
SimpleSerializerSimpleSerializerBundle
Details can be found on the habr
Reinvent the wheel
Benefits
Dmitry Petrov
This is librarySeparation of serialization rules and formatAbsence voiced disadvantages"Inteligent" deserialization
SimpleSerializer
What? Where? When?
Dmitry Petrov
Parameters of requestsData transfer objectsBusiness logic
RESTful API, validation
Parameters of requests
Dmitry Petrov
/api/orders/12/api/boxes/BOX-1-1/api/orders?valid=true
RESTful API, validation
Dmitry Petrov
PATCH /api/orders/12Body 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/transitionBody of the request:{
"transition": "start:printing:front",
"note": null,
"comment": "I'm hacker"}
POST /api/press-sheets/12/transitionBody 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
ConventionalismDuplication 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
Behat, PHPUnit
Dmitry Petrov
Controllers
Data access layerService layer
RESTful API, testing
Problems
Dmitry Petrov
Run time:Behat ~ 90 minutesPHPUnit ~ 5 minutes
RESTful API, testing
WSSE
Dmitry Petrov
Atom AuthenticationHow to create a custom Authentication ProviderEscapeWSSEAuthenticationBundle (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
Any questions?
Dmitry Petrov
@old_fightmaster
RESTful API
https://github.com/opensofthttps://github.com/fightmaster
Special thanks to ProFIT team