Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RESTons Zen

RESTons Zen

Sandrine Banas

June 08, 2022
Tweet

More Decks by Sandrine Banas

Other Decks in Technology

Transcript

  1. public class SandrineBanas { private String job = "Expert Technique";

    private String employeur = "CGI"; private int nbAnneesExperience = "20"; private final String language = "JAVA"; private final String twitter = "@cosJava"; private List<String> fun = Arrays.asList("Zen", "Books", "Science-fiction", "Playmobil"); }
  2. Contrat entre deux parties: - Méthodes et payload - Technologie

    d’échange Application Programming Interface API ? A P I
  3. REST REpresentational State Transfer Un style d’architecture logicielle défini dans

    la thèse de doctorat de Roy Fielding en 2000 définissant des contraintes à respecter pour créer des services web (services web RESTful). https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  4. Architecture REST 01 02 03 04 Architecture Client - Serveur

    Aucun stockage de session côté serveur Stateless Pour l’optimisation Cache Load balancer, gateway, proxy etc. Un système à couches 05 Code à la demande (optionnel) 06 Interface uniforme
  5. Interface uniforme Identification des ressources: http://api.com/conferences/5 Manipulation des ressources à

    travers des représentations: Opérations CRUD disponibles via un format ex JSON Messages auto-descriptif Content-type: application/json Hypermédia comme moteur d’application (HATEOAS) Hyperliens présents dans les réponses pour naviguer dans l’api.
  6. SOAP vs REST XML JSON, XML, yaml, excel… WSDL Open

    API (swagger) HTTP, SMTP HTTP SOA WOA Opérations Ressources
  7. Open API/Swagger Swagger API project crée en 2011 par Tony

    Tam pour automatiser la création de documentations sur les API. En 2015 s’incorpore dans une nouvelle organisation Open API initiative. En 2016 devient l’OpenAPI specification. https://www.openapis.org/ Actuellement version 3.1.0 de Février 2021 En yaml ou json https://editor.swagger.io/
  8. Ressource vs Représentation URL: http://api.com/book/5 {"titre":"Clean Architecture", "Auteur": "Robert C.

    Martin"} <titre>Clean Architecture</titre> <auteur>Robert C. Martin</auteur> titre: Clean Architecture auteur: Robert C. Martin Content-Type: application/xml; charset=utf-8 => 415 (Non pris en charge) Accept: application/json
  9. Request Response Vient du client Une URL Un verbe: POST,

    PUT, DELETE… Vient du serveur, c’est: Un status: 200, 400, 500 … Des méta-données dans les HTTP headers Une payload (ou pas)
  10. GET Lecture d'une ressource ou d'une collection /books /books/5 200

    (OK) 206 (Partiel) Avec cache Renvoie une ou plusieurs représentations POST Création d'une ressource /books 201 (Created) 202 (Asynchrone) Sans cache Représentation + location header DELETE Suppression d'une ressource /books/5 204 (No content) 200 (OK) 202 (Asynchrone) 404 (Not found) Sans cache Vide PUT Crée ou remplace une ressource /books/5 200 (OK) 201 (Created) 202 (Asynchrone) 404 (Not found) Sans cache Représentation + location header PATCH Modification partielle d'une ressource /books/5 200 (OK) 202 (Asynchrone) 404 (Not found) Sans cache Représentation + location header
  11. Options ? - Demande des informations sur ce qui est

    disponible : les verbes et content-type - Une requête de pré-vérification / Cross-origin resource sharing Et Head ? Idem que get mais sans le body… Pour les grosses collections avec Etag header. Et Trace ? Pour du debug, le server renvoie ce qu’il a reçu.
  12. Safe et Idempotence Safe => Ne change pas l’état du

    serveur Idempotent => Peut importe le nombre d’appels à une route, même payload, même résultat (mais peut retourner un code différent). Idempotent et safe: GET Pas idempotent et pas safe : POST, PATCH Idempotent et pas safe: PUT, DELETE Pour tous les cas non idempotents utiliser plutôt POST.
  13. Les champs header Pour les méta-données associées à l’appel Paires

    de type clé-valeur Request header Authorization => token d’authentification Accept-Charset => le charset voulu par le client (ex UTF-8) Content-type => Format de la payload envoyée Accept -> la représentation voulue Response header Pour la pagination => content-range, link, accept-range Cache-Control / Pragma / Expires => la gestion du cache Content-Type => la représentation envoyée Content-Length => la taille du contenue
  14. Accept / Content-type Type/subtype; charset=xxx text text/plain, text/html, text/css, text/javascript

    Image image/gif, image/png, image/bmp audio audio/mpeg, audio/wav video video/ogg, video/webm application application/octet-stream, application/pdf, application/json, application/xml multipart multipart/form-data, multipart/byteranges 415 – Media not supported https://www.rfc-editor.org/rfc/rfc7231#section-3.1.1.1
  15. Les headers conditionnels Demande au serveur de tester une pré-condition

    avant d’effectuer la requête Etag (entity tag) => string token représentant l’état de la ressource change si l’état change, wildcard * pour dire si n’existe pas If-match => Appliquer si pas de changement (ex PUT) If-none-match => Appliquer si il y a eu des changement (ex GET) Last-modified => date de dernière modification If-unmodified-since => Appliquer seulement si pas de modification depuis la date donnée If-modified-since => Appliquer si modifié depuis la date donnée En cas d’échec pour un GET ou HEAD => 304 (Not modified) En cas d’échec pour les autres => 412 (Precondition failed)
  16. Caching Cache-control => Un ensemble de directives, ex no-cache, must-revalidate,

    public, private, max-age… Expires => à la date indiquée la ressource doit être revalidée par le serveur Last-modified => dernière modification de la ressource Avec Etag ou Last-Modified pour faire un conditional get pour revalider la re quête.
  17. Http Status 1xx - Information 2xx – Success 200 (Ok)

    – 206 (Partial) -201 (Created) – 204 (No content) – 207 (multistatus) 3xx – Redirection 301 (Moved permanently) – 303 (See other) - 304 (Not modified) 4xx – Erreur (faute du client…) 400 (Bad Request) 401 (Unauthorized) 403 (Forbidden) 405 (Method not Allowed) 404 (Not found) 418 (I’m a teapot) 5xx – Erreur (faute du serveur) 500 (Internal Server Error) 503 (Service unavailable) https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
  18. Nommage des ressources Noms ou des verbes ? /getAllBooks ou

    /books Singulier ou pluriel ? /books /books/5 ou /book/5 Snake_case, camelCale, spinal-case ? /book_techno /bookTechno ou /book-techno
  19. Choix des champs {"titre":"Clean Architecture", "Auteur": { "Nom": "Martin "

    , "Prenom": "Robert C."} /books/1?fields=(titre,auteur(nom)) {"titre":"Clean Architecture", "Auteur": {"Nom": "Martin" } Pas supporté par l’open API
  20. Query Verbe ? /books/search?title=XXX ou /books?title=XXX Global ou par param?

    /books?q=XXX ou /books?title=XXX ou /books?filter=XXX Get ou post ? POST /books {"title" : "XXX" } ou GET /books?title=XXX
  21. Pagination Range ? /books?limit=20&offset=5 ou /books?range=5-25 ou /books?page=2&per_page=10 ou dans

    le HTTP header range Tri ? /books?sort=TITLE ou /books?asc=TITLE et /books?desc=TITLE Headers response ? Content-Range: 10-20/999 Link: <https://api.github.com/search/code?q=addClass+user%3A mozilla&page=2>; rel="next", <https://api.github.com/search/code?q=addClass+user%3Amozi lla&page=34>; rel="last"
  22. Versioning ? A droite ou à gauche ? http://api.com/v1/books/1 ou

    http://api.com/books/v1/1 Mineur ou seulement majeur ? http://api.com/v1.0.1/books/1 Dans le header ? Api-version=2 Accept: application/vnd.example+json;version=1.0 Dans un paramètre ? http://api.com/books/1?version=2 Dans le body? {« version »:2.0}
  23. Versioning ? Deux versions au maximum, coût du versioning élevé

    - Soit déployer deux microservices, gestion de deux branches - Soit maintenir les deux versions dans le même microservice https://www.infoq.com/news/2013/12/api-versioning/ Versions Coûts Knot Point-to- point Compatible
  24. Versioning ou pas ? S’en passer car c’est un détail

    d’implémentation qui « fuit » dans l’url. Si changement « cassant », c’est peut être plutôt une nouvelle ressource ? Ne peut-on déterminer la version voulue via la payload envoyée par le client ? Ou peut-on supporter les nouveaux champs dans la même route ? {"fullName":"Robert Martin"} {"nom": "Martin","prenom":"Robert"} {"fullName":"Robert Martin","nom": "Martin","prenom":"Robert"}
  25. Payload classique DRY: do not repeat yourself (dans la payload

    et l’url) Combien de niveau ? A plat ? 2 niveaux max ? Camel Case, snake_case, spinal-case ? Utiliser des enum en UPPER_SNAKE_CASE Date au format UTC – Zulu time Représenter les listes vides par [] et pas null Indiquer la devise (iso-4217), ou l’unité de mesure ou de poids (ex enum)
  26. Json patch ? https://datatracker.ietf.org/doc/html/rfc6902 application/json-patch+json [ { "op": "test", "path":

    "/a/b/c", "value": "foo" }, { "op": "remove", "path": "/a/b/c" }, { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }, { "op": "replace", "path": "/a/b/c", "value": 42 }, { "op": "move", "from": "/a/b/c", "path": "/a/b/d" }, { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" } ] application/json { "a":"z", "c": { "f": null } }
  27. Gestion des erreurs type => type du problème (optionnel, défaut

    about:blank) title => description du problème status => status code detail => détail du problème instance => URI Ex twitter {"title": "Invalid Request", "detail": "One or more parameters to your request was invalid.", "type": https://api.twitter.com/2/problems/invalid-request , "errors": [ { "parameters": { "end_time": [ "2026-10-31T23:59Z" ] }, "message": "Invalid 'end_time':'2026-10-31T23:59Z'." } ], } Attention aux risques de sécurité, ne pas remonter l’exception et sa stack trace. https://datatracker.ietf.org/doc/html/rfc7807
  28. Scénario non ressource Utilisation de POST + utiliser un verbe

    dans la route /site/5/block /site/5/unblock Sauf que, que faire si pas de body ? Trouver un body quoiqu’il en coûte ? /site/5/block {« block » : true} /site/act { « id »: 5, « action »: « block », « block »: true, « otherAction »: « paramOther » }
  29. Traitement en masse Sur la même route ? POST /books

    [{"titre":"Clean Architecture","Auteur": "Robert C. Martin"}, {"titre":"Clean Code","Auteur": "Robert C. Martin"}] Avec une « ressource » bulk ? POST /books/bulk Avec un verbe ? POST https://gmail.googleapis.com/gmail/v1/users/{userId}/messages/batchModify { "ids": [string], "addLabelIds": [string], "removeLabelIds": [string] }
  30. Traitement en masse Avec une requête par lots ? (facebook)

    POST /endpoint?batch= (google) POST /batch/endpoint/ Payload [{"method":"POST", "relative_url": "books", "body": "… "}, {"method":"GET", "relative_url": "books/5"}] Response [{"code":201, "headers": « xxx", "body": "… "}, {"code":200, "headers": "xxx", "body": "… "} 207 Multi-Status,
  31. Vers la gloire du REST (Richardson Maturity Model) https://martinfowler.com/articles/richardsonMaturityModel.html Niveau

    0: Le marais du POX (Plain Old XML) Un seul point d’accès, un seul verbe (GET ou POST) Niveau 1: Ressources Utilisation d’url représentant des ressources Niveau 2: Verbes Utilisation des verbes http: DELETE, PUT, PATCH… Niveau 3: Contrôles hypermédia L’api devient navigable.
  32. HATEOAS (Hypermedia As The Engine Of Application State) Formats: •

    Collection+JSON, créé par Mike Amundsen en 2011 • UBER, créé par Mike Amundsen en 2014 • HAL, créé par Mike Kelly en 2011 • Siren, créé par Kevin Swiber en 2012 • Mason, créé par Jorn Widlt en 2014 • JSON-LD, créé par Manu Sporny & al. en 2010 • Hydra, créé par Markus Lanthaler en 2012 • JSON-API, créé par Steve Klabnik en 2013