+ All Categories
Home > Technology > The dark side of the app

The dark side of the app

Date post: 12-Apr-2017
Category:
Upload: simone-di-maulo
View: 503 times
Download: 0 times
Share this document with a friend
85
Transcript

THE DARK SIDE OF THE APP

WHO ARE WE

?

SIMONE DI MAULO

Backend Developer @Kataskopeo.com

aka @toretto460

Pugger since 2012

CLAUDIO D’ALICANDRO

Backend developer @Chupamobile.com

@ClaudioSThought on twitter

Pugger since 2013

PUG ROMA

Monthly Meetings

TECH TALKS

PHP Fast API by @toretto460

ZendFramework by @lorenzoferrara

Laravel by @malatestafra

MongoDB by @kekko

… take a look at http://roma.grusp.org/

PROJECTS

https://github.com/PUGX

THE DARK SIDE OF THE APP

androidiOS

APIs

i have a producti have a service

i need APIs

DURABLE

EASY TO EVOLVE

SCALABLE

Booking Engine APIs

Booking engine requirements

● A user should be able to find a hotel so that he can

check the availability.

● A user should be able to show a list of room with

details so that he can choose one of them.

● A user should be able to find a hotel for the given

check-in/check-out date so that he can make a

reservation by choosing a free room.

Booking engine APIs

● Check the hotel availability

● Show the room detail

● Book a room

● Check the room availability

● Modify a booking

● Cancel a booking

RPCExposing the booking

functionality as function calls that accept parameters.

RPC - Style

POST /booking-engine

Host: my-hotel.com

{

"action": "findHotelsByCity",

"args": {

"city": "Todi",

"order_by": "distance"

}

}

RPC - StyleHTTP/1.1 200 OK

{

"hotels": [

{

"id": "dahu5942hfki58-fjaau7645-lo987",

"name": "Hotel Europa",

"coordinates": { "lat": ..., "long": ...}

},

{

"id": "dr594dahty71013-jfuh628fh47ft37",

"name": "Hotel Asia",

"coordinates": { "lat": ..., "long": ...}

}

]

}

RPC - Style

POST /booking-engine

Host: my-hotel.com

{

"action": "getAvailability",

"args": {

"interval": {

"checkin": "2015-09-26",

"checkout": "2015-09-27"

},

"hotel_id": "dahu5942hfki58-fjaau7645-lo987"

}

}

There is no contract between client and server

Hard to evolve

Hard to cache

too much lacks!

SOAP is the key

● a structured definition - WSDL ✓

● Transactions ✓

● WS-Security ✓

SOAP - Request

POST /FindHotelByCity.asmx HTTP/1.1

Host: my-hotel.com

Content-Type: text/xml; charset=utf-8

SOAPAction: "http://my-hotel.com/FindHotelByCity"

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://my-

hotel.com/">

<SOAP-ENV:Body>

<ns1:HotelsToFind>

<ns1:City>Todi</ns1:City>

</ns1:HotelsToFind>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

SOAP - ResponseHTTP/1.1 200 OK

Cache-Control: private, max-age=0

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.

org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soap:Body>

<HotelList>

<Hotel id="w3dhfu8272dlo-ldo8364j">

<Name>Hotel Europa</Name>

<Coordinates lat=".." lon=".."><Coordinates>

</Hotel>

<Hotel id="w3dhfu8272dlo-ldo8364j">

<Name>Hotel Europa</Name>

<Coordinates lat=".." lon=".."><Coordinates>

</Hotel>

</HotelList>

</soap:Body>

</soap:Envelope>

is SOAP the key ?

● Documentation NOT SO READABLE

● Tunneling over HTTP POST BAD

● Non standard Errors BAD

● Impossible to CACHE REALLY BAD

Use a contractdon’t expose the

domain logic

scalable

decoupled

IS SOAP THE KEY?

MAYBE NOT

REST

RESTis an architectural style

RESTgives a coordinated set of

constraints

REST Constraints

● Client-Server model

● Stateless

● Cacheable

● Layered System

● Uniform Interface

○ Identification of resources

○ Manipulation of resources through these

representations

○ Hypermedia as the engine of application state

Identification of RESOURCES

We are talking about RESOURCES

Well designed URIs

RESOURCES

/api/booking-engine

/api/hotels

/api/hotels?city=Todi

/api/hotels/12356/rooms

Booking engine APIs

● Check the hotel availability

● Show the room detail

● Book a room

● Check the room availability

● Modify a booking

● Cancel a booking

Check the Hotel availability - RPC

POST /booking-engine-api

{

"action": "findRoom",

"params": {

"hotel": 12456,

"interval": {

"checkin": "2015-10-01",

"checkout": "2015-10-09"

},

"pax": 3

}

}

HTTP/1.1 200 OK

Date: Sun, 27 Sep 2015 10:00:45 GMT

Cache-Control: max-age=0, no-cache, no-store

Pragma: no-cache

{

"rooms": [

{

"id": 567,

"beds": ["single", "double"],

"amenities": [...]

},

...

]

}

Check the Hotel availability - REST

GET /api/hotels/12456/rooms?checkin=2015-

10-01&checkout=2015-10-09&pax=3

HTTP/1.1 200 OK

Date: Sun, 27 Sep 2015 10:00:45 GMT

{

"rooms": [

{

"id": 567,

"beds": ["single", "double"],

"amenities": [...]

},

...

]

}

Does not change until next booking

LET’S CACHE

HTTP CACHE

HTTP/1.1 200 OK

Date: Sun, 27 Sep 2015 10:00:45 GMT

Cache-Control: public, max-age=600

ETag: db87ju95dgtyg-12348765209

Expiration modelValidation model

I CAN’T CACHE IT

POST /booking-engine-api

{

"action": "findRoom",

"params": {

"interval": {

"checkin": "2015-10-01",

"checkout": "2015-10-09"

},

"pax": 3

}

"hotel": 12456

}

VERBS

What’s the difference

between GET and POST ?

GETHEAD

PUT

POST PATCH

OPTIONSDELETE

VERBS

GETHEAD

PUT

POST PATCH

OPTIONSDELETE

SAFE

GETHEAD

PUT

POST PATCH

OPTIONSDELETE

IDEMPOTENT

ERROR HANDLING

Check the Hotel availability

GET /api/hotels/12456/rooms?checkin=2015-10-01&checkout=2015-10-09&pax=3

HTTP/1.1 200 OK

Date: Sun, 27 Sep 2015 10:00:45 GMT

{

"error": "Hotel Not Found"

}

STATUS CODES 100 HTTP CONTINUE 101 HTTP SWITCHING PROTOCOLS 102 HTTP PROCESSING 201 HTTP CREATED 202 HTTP ACCEPTED 203 HTTP NON AUTHORITATIVE INFORMATION 204 HTTP NO CONTENT 205 HTTP RESET CONTENT 206 HTTP PARTIAL CONTENT 207 HTTP MULTI STATUS 208 HTTP ALREADY REPORTED 226 HTTP IM USED 300 HTTP MULTIPLE CHOICES 301 HTTP MOVED PERMANENTLY 302 HTTP FOUND 303 HTTP SEE OTHER 304 HTTP NOT MODIFIED 305 HTTP USE PROXY 306 HTTP RESERVED 307 HTTP TEMPORARY REDIRECT 308 HTTP PERMANENTLY REDIRECT 400 HTTP BAD REQUEST 401 HTTP UNAUTHORIZED 402 HTTP PAYMENT REQUIRED 403 HTTP FORBIDDEN 404 HTTP NOT FOUND 405 HTTP METHOD NOT ALLOWED 406 HTTP NOT ACCEPTABLE

407 HTTP PROXY AUTHENTICATION REQUIRED 408 HTTP REQUEST TIMEOUT 409 HTTP CONFLICT 410 HTTP GONE 411 HTTP LENGTH REQUIRED 412 HTTP PRECONDITION FAILED 413 HTTP REQUEST ENTITY TOO LARGE 414 HTTP REQUEST URI TOO LONG 415 HTTP UNSUPPORTED MEDIA TYPE 416 HTTP REQUESTED RANGE NOT SATISFIABLE 417 HTTP EXPECTATION FAILED 418 HTTP I AM A TEAPOT 422 HTTP UNPROCESSABLE ENTITY 423 HTTP LOCKED 424 HTTP FAILED DEPENDENCY 425 HTTP RESERVED FOR WEBDAV ADVANCED … 426 HTTP UPGRADE REQUIRED 428 HTTP PRECONDITION REQUIRED 429 HTTP TOO MANY REQUESTS 431 HTTP REQUEST HEADER FIELDS TOO LARGE 500 HTTP INTERNAL SERVER ERROR 501 HTTP NOT IMPLEMENTED 502 HTTP BAD GATEWAY 503 HTTP SERVICE UNAVAILABLE 504 HTTP GATEWAY TIMEOUT 505 HTTP VERSION NOT SUPPORTED 506 HTTP VARIANT ALSO NEGOTIATES EXPERIMENTAL 507 HTTP INSUFFICIENT STORAGE ...

200 HTTP OK SOAP is here

USE THE RIGHT STATUS CODE

GET /api/hotels/12456/rooms?checkin=2015-10-01&checkout=2015-10-09&pax=3

{...}

HTTP/1.1 200 OK

{"error": "Hotel Not Found"}

HTTP/1.1 404 Not Found

BE STANDARD

MIDDLEWARE

ex. MIDDLEWARE

ex. MIDDLEWARE

ex. MIDDLEWARE

ex. MIDDLEWARE

ex. MIDDLEWAREvar app = require('express')();

var logger = new (winston.Logger)({

transports: [

new (winston.transports.Console)({ level: 'info' })

]

});

app.use(function(req, res, next) {

logger.info("Received request: %s", JSON.stringify({

headers: req.headers,

method: req.method,

url: req.url

})

);

next();

});

var server = app.listen(3000);

ex. MIDDLEWARE

// File web/app.php

require_once __DIR__.'/../app/bootstrap.php.cache';

require_once __DIR__.'/../app/AppKernel.php';

require_once __DIR__.'/../app/AppCache.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);

$kernel->loadClassCache();

// wrap the default AppKernel with the AppCache one

$kernel = new AppCache($kernel);

$request = Request::createFromGlobals();

$response = $kernel->handle($request);

$response->send();

$kernel->terminate($request, $response);

How REST is

your API ?

Richardson Maturity Model

Level 0 - Plain Old XML

Level 1 - Resources

Level 2 - HTTP Verbs

Level 3 - Hypermedia Controls

HYPERMEDIA

HYPERMEDIA EXAMPLE{

"links": [

{

"rel": "new",

"href": "http://mycompany.hotels/api/hotels/12456/room/new"

},

],

"rooms": [

{

"id": 567,

"beds": ["single", "double"],

"links": [

{

"rel": "self",

"href": "http://mycompany.hotels/api/hotels/12456/room/567"

},

{

"rel": "amenities",

"href": "http://mycompany.hotels/api/hotels/12456/room/567/amenities"

}

]

}, ...

]

}

THE RESPONSE FOR THE CUSTOMER

# The Customer (from Android client)

GET /api/hotels/12456/room/new HTTP/1.1

Host: mycompany.hotels

HTTP/1.1 403 Forbidden

THE RESPONSE FOR THE ADMIN# The Admin (From the SPA in the backoffice)

GET /api/hotels/12456/room/new HTTP/1.1

Host: mycompany.hotels

HTTP/1.1 200 OK

{

"links": {

"ref": "action",

"method": "POST"

"href": "http://mycompany.hotels/api/hotels/12456/room"

}

room: {

"beds": {

"multiple": true,

"options": {

"single": {

"label": "Single"

},

"double": {

"label": "Double"

}

},

}

}

}

HATEOAS

GETHEAD

PUT

POST

PATCH

OPTIONS

DELETE

VERBS

new

edit

remove

Haters gonna HATEOAS

HATEOAS ISN’T A SILVER BULLET

The documentation is important, but instead of explaining what to look for and where, should explain how to look and how to interpret

the resources.

WITHSTAND BREAKING CHANGES

“The foolish and the dead alone never change their opinions”

- James Russell Lowell -

API VERSIONING

Versioning an interface is just a

"polite" way to kill deployed clients.

— Roy Fielding.

WRONG WAY #1Versioning the url

GET /api/v2/your/resource/idHost: yoursite.com

WRONG WAY #2Versioning by header

GET /api/your/resource/idHost: yoursite.comX-api-version: 2

WRONG WAY #3Versioning by content type

GET /api/your/resource/idHost: yoursite.comAccept: application/vnd.mycorp.bookings.v2+jsonVary: Accept

Utopia is not a destination but a direction

Questions ?

Thank You!


Recommended