Thématiques principales

samedi 15 juin 2019

ReST : Introduction

ReST pour Representational State Transfert [wiki] est un style d’architecture formalisé par [Thomas Fielding] en 2000 dans sa thèse de doctorat. Le but de ReST est de formaliser et simplifier les échanges d’informations et la communication entre les applications sous la forme d’une API [rest-quick].

En se basant sur HTTP (v1 et maintenant v2 [http2-rest] ) Rest bénéficie d’un mode de communication simple et universel (technologiquement parlant) dont les mécanismes de sécurisations et d’attaques sont connus (ssl, tls, dos, basic authent, SAML, OAuth2, JWT, la liste est longue et nous y reviendrons ....). 

Dans le principe, l’idée est simple: exposer et fournir une ressource au travers d’HTTP. Conformément à ce protocole ceci est réalisé grâce à son URL (Uniform Resource Locator) [url-uri] qui permet au client d’identifier et de manipuler cette ressource.

Lorsque l’on parle de ressource, il va de soit que cela se conçoit dans le cadre de HTTP. Ainsi la ressource est un objet virtuel présent côté serveur dont le cycle de vie sera gérer par celui ci mais avec lequel le client aura la possibilité d’interagir en manipulant les verbe du protocole: (GET, POST, PUT, DELETE, PATCH).



De manière générale ces interactions du client avec la ressource c’est à dire les verbes HTTP pourront suivre une logique de gestion de type CRUD et ainsi voir l’interface serveur Rest comme une interface d'accès à des données comme on le ferait avec une BDD.

Ainsi, pour être plus explicite, lorsque le client réalisera une requête GET, cela pourra être vu comme une requête Read sur la ressource si celle ci était une base de donnée. Si le client réalise une requête de type de POST, cela équivaudra à une requête Create, s'il réalise un PUT, cela équivaut à un update de la ressource [put-vs-post] et s’il fait un DELETE, cela est comme on pourra s’en douter un Delete de la ressource.

Il est évident que cette vision mappant ReST et CRUD est un raccourci abusif [rest-not-crud] car une API ReST doit être spécifié et construire selon un besoin utilisateur clair et non dans une logique où l’on pourra tout faire sur le même endpoint! Ainsi si, dans le cas des modèles simples, adopter une logique CRUD ne sera probablement pas une bêtise, rapidement, il faudra penser l’API ReST comme étant une fenêtre exposant des ressources orientés d’un même modèle de données.

De même, les interactions sont l’occasion de réaliser des échanges d’informations. Ainsi lorsque le client réalise un GET sur une ressource, son but est de disposer des informations la concernant. De même lorsque qu’il réalise un POST, sont but est de pousser les informations dont il dispose afin d’enregistrer ces informations sous la forme d’une nouvelle ressource dans le server. Mais encore une fois, cela ne préjuge pas de la structure des données qui seront réellement mise en base de données, (si celle ci existe).

Comme nous l’avons déjà dit Rest s’appuie sur HTTP et c’est ainsi qu’est formalisé la manière d'échanger de l’informations, quoi? non pas en html! (bien que dans l’absolu ça ne soit pas impossible) mais plutôt en spécifiant le type MIME dans le header de la transaction.

Pour rappel, dans le protocole http, le type MIME permet au client et au server de se mettre d’accord sur le format des données qu’ils vont s'échanger. Ainsi, dans le web classique, on trouve de html, du text des images… Ici avec ReST on trouvera essentiellement de l’XML et plus probablement du JSON (nous reviendrons sur cela).

De l’XML? mais c’est comme SOAP alors! ? et ba loupé! [soap-vs-rest]

En effet Rest et Soap sont souvent comparés et traité à un même niveau sauf que s’ils sont tous deux des protocoles de communication s’appuyant sur HTTP, il est existe une différence importante entre les deux:

  • Rest tend à respecter les standard du web dans l’utilisation de http et utilise ce dernier comme un protocole applicatif où les verbe sont utilisé pour accéder convenablement aux ressources, elle même correctement formalisé selon des URL adaptée.  
  • SOAP n’utilise HTTP que comme un protocole de transport et toute la logique applicative est dans le message SOAP

Pour mieux comprendre ces différences il convient de lire l’article de Martin Flowers sur Richardson Maturity Model [richardson], [richardson-comment].

Ainsi en tant que style d’architecture, en fournissant un interface virtualisant la consommation ou la production de ressources, facilite le découplage des différentes parties applicatives du systèmes conduisant aux architectures microservices (mais cela est une autre histoire).

Ainsi ces architectures à base ReST en s'appuyant sur http impliquent (ou permettent de bénéficier) différentes propriétés qu’il convient de prendre en compte afin de se prémunir d’erreur de conception.
Entre autre:

  • ReST est un style d’architecture basé sur le modèle Client Serveur impliquant que chacun à un rôle différent, le premier consomme les informations, le second, les fournit ou les enregistre.
  • ReST est sans etat. Cela est important dans le sens où les requêtes du client sur le serveur sont indépendantes et doivent se suffirent à elle même pour satisfaire le besoin. De son côté, le serveur ne construit pas de session.
  • ReST autorise la mise en place de cache pour garantir les performances du système. Ce(s) cache(s) peuvent être implémenté(s) en tout lieu de la chaîne de commande (le client, le serveur où tout autre composant intermédiaire)
  • ReST doit fournir une interface uniforme et homogène de façon à faciliter l'accès et le parcours des données
  • ReST peut être conçu en couche autorisant l’utilisation de proxy et reverse proxy ainsi que la délégation d’appel à des sous API ReST. 

Un dernier point spécifie que ReST, optionnellement, peut fournir du code à la demande. J’admet que ce point reste pour ma part assez nébuleux et je ne l’aborderais pas tant j’ai du mal à concevoir l’utilisation de ce point, sa mise en oeuvre et les éventuelles problèmes de sécurité que cela peut poser.

Bien maintenant que l’on en à parler, ca serait bien d’y gouter aussi un peu à du ReST!

Du coup prenons le cas d’une bibliothèque présentant divers resources selon différents supports.

Alors ici on va commencer par un cas particulier, celui de la ressource unique (ou de type singleton) qui va nous permettre d’obtenir des informations sur des ressources accessibles dans l’API.

Ainsi, sur le endpoint on va trouver un premier chemin accessible tel que:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
> GET: /bibliotheque
< 200 : 
{
  nom : Bibliotheque de la mairie
  resources : 
  [
    {
       nom : Les livres
       type: Livre
       url :  /bibliotheque/livres
    },
    {
       nom : Les videos
       type: Video
       url :  /bibliotheque/videos
    }

  ] 
} 


Ici on à donc grace à cette premiere requette la connaissance des resources disposibles. Celle ci de type Livre et Video sont identifiable et accessible via une url. On notera que la nomenclature de nomage est au pluriel car comme on va le voir la ressource associée (contrairement à la bibliotheque qui est un singleton pour sa part) est multiple.

Intéressons nous aux livres:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> GET : /bibliotheque/books
< 200 :
[
  {
    id:1
    name: “Clean Code”,
    ISBN-13: 978-0132350884,
    nbrChapitre: 17
  },
  ...
]


On obtient donc une liste dans laquelle on trouvera le livre Clean Code. A noter qu’avec cette requête, on obtient donc tous les livres! Si on veut limiter cette requete, il est alors possible de faire une requete avec un param:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> GET : /bibliotheque/books?nbrChapitre=17
< 200 :
[
  {
    id:1
    name: “Clean Code”,
    ISBN-13: 978-0132350884,
    nbrChapitre: 17
  },
  ...
]


Dans ce cas, on obtient toujours une liste de libre mais seul ceux contenant que 17 chapitres… (bon ok comme recherche c’est pas ce qu’il y à de plus courant mais c’est pour l’exemple) De même si l’on fait la même recherche mais sur le nom, on obtient:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> GET : /bibliotheque/books?name=Clean Code
< 200 :
[
  {
    id:1
    name: “Clean Code”,
    ISBN-13: 978-0132350884,
    nbrChapitre: 17
  },
  ...
]


Ce qui revient au même… mais on notera que l’on obtient quand même une liste… pourquoi? car il s’agit de l'équivalent de faire une recherche avec un filtre, du coup ce n’est pas faire une récupération spécifique et si l’on cherchait à récupérer que le livre Clean Code, alors on a mal penser sa requête. Ce qu’il aurait fallu faire c’est :


1
2
3
4
5
6
7
8
> GET : /bibliotheque/books/1
< 200 :
 {
    id:1
    name: “Clean Code”,
    ISBN-13: 978-0132350884,
    nbrChapitre: 17
  }


La on ne récupère qu’un élément et c’est celui identifié par son identifiant unique, l’id. (équivalent à un clef primaire)

Nous n’avons jusque là fait que des GET, et on remarque qu’il manque Clean Architecture… bon ok, ajoutons le:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
> POST : /bibliotheque/books
{
    name: “Clean Architecture”,
    ISBN-13: 978-0134494166,
    nbrChapitre: 1
}
< 201 :  /bibliotheque/books/2
 {
    id:2
    name: “Clean Code”,
    ISBN-13: 978-0132350884,
    nbrChapitre: 17
  }


Bien on note plusieurs choses: d’une part on ne post pas le livre avec un identifiant, on laisse le serveur se charger de le faire. Ainsi c’est pour cela que la réponse au POST est un code 201, nous spécifiant que la ressource à bien été créée et à cela est ajouté sa localisation (afin de savoir comment la récupérer) mais aussi la ressource elle-même.

Par contre on constate une erreur, ce livre ne contient pas qu’un chapitre mais 34… Il nous faut donc corriger cela. Le hic c’est que si l’on tente de refaire un POST, il y à des chances que l’on nous réponde que la ressource existe déjà… (je vous laisse chercher le code http associé) voir peut être qu’il nous en créer une seconde en faisant par ce biais un doublon. non ce que l’on veut c’est modifier la valeur associée à la ressource.

Bon pour cela, on pourrait faire un DELETE sur l’id et refaire le POST…. bon vous avez compris, ça fonctionnerait mais c’est lourd… non il existe des façon de faire plus efficace.

Entre il est possible d’utiliser (je vous le donne en mille) soit le verbe PUT en fournissant l'intégralité de la ressource ou alors PATCH permettant de cibler la modification à réaliser. Voyons les deux:


1
2
3
4
5
6
7
8
> PUT : /bibliotheque/books/2
{
    id:2,
    name: “Clean Architecture”,
    ISBN-13: 978-0134494166,
    nbrChapitre: 34
}
< 204 


Ici dans ce cas, le PUT va donc surcharger complètement la ressource. Seul un code 204 sera retourné pour spécifier que l'opération à été réalisée (mais qu’il n’y à pas d’information supplémentaire à attendre, en effet avec un PUT on connait déjà le localisation de la ressource sinon on aurait pas pu exécuter ce verbe)

Avec le PATCH, c’est un peu plus délicat car il faut spécifier que ce qui est modifier. On prendra garde à ce que l’id ne soit pas surcharger bêtement (à noter d’ailleur que l’id est inutile dans la ressource elle-même si le location du retour du POST est correctement fourni, le seul hic ici est que l’objet ne porte alors pas son identifiant unique, on verra que ceci est alors surtout un problème de représentation des données au sein du modèle ReST. On réfléchira à ce point lorsque ne traiterons d’exemples)

Enfin donc le PATCH: (on considérant que nous n’avons pas fait le PUT précédent)


1
2
3
4
5
> PATCH : /bibliotheque/books/2
{
    nbrChapitre: 34
}
< 204 


Voilà les grandes lignes de l’utilisation de ReST et de son design afin d’en tirer le meilleur. Maintenant il reste à le formaliser et pour cela rien de tel que quelques exemples. Du coup on tachera de faire du ReST avec quelques langages histoire de bien en montrer l'intérêt et surtout que finalement, le langage en question ne change rien aux fondamentaux et aux propriétés portées par ReST!

Références

[http2-rest] https://dzone.com/articles/benefits-of-rest-apis-with-http2?edition=352091&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=Daily%20Digest%202018-01-10
[Thomas Fielding] https://www.ics.uci.edu/~fielding/
[wiki] https://en.wikipedia.org/wiki/Representational_state_transfer
[rest-tuto] https://www.restapitutorial.com/
[soap-vs-rest] https://dzone.com/articles/differences-in-performance-apis-amp-more?edition=286955&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=dd%202017-03-31
[richardson] https://martinfowler.com/articles/richardsonMaturityModel.html
[richardson-comment] https://blog.xebia.fr/2010/06/25/rest-richardson-maturity-model/
[swagger] https://dzone.com/articles/api-first-with-swagger?edition=330491&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=Daily%20Digest%202017-10-12
[put-vs-post] https://restfulapi.net/rest-put-vs-post/
[rest-not-crud] https://medium.com/@marinithiago/guys-rest-apis-are-not-databases-60db4e1120e4
[rest-quick] https://blog.nicolashachet.com/niveaux/confirme/larchitecture-rest-expliquee-en-5-regles/
[url-uri] https://www.java67.com/2013/01/difference-between-url-uri-and-urn.html

vendredi 14 juin 2019

Changement de taff!!

Et bien cela va faire presque deux mois que je n’ai rien écrit! non je n’ai pas mis de coté le blog. Mais j’avoue que ces deux derniers mois ont été très chargé. D'une part, j’ai déménagé! Encore! Ce qui en terme d’organisation pour écrire, perturbe un peu les habitudes! Et aussi j’ai changé de boulot! aussi et oui ça faisait un an que j'étais chez Capemini mais je m’ennuyais.

Du coup je suis rentré chez Norsys, je me suis laisser séduire par le dynamisme, le côté écolo, et une volonté de bien faire…  et j’ai débuté le premier avril dernier… (sans blague)

Alors je disais dans un précédent article que d’ailleurs, souvent on choisi une boite surtout pour les gens qui y travaillent et le fait que l’on veuille bosser avec eux… et bien là clairement, j'étais en plein dedans! et je regrette pas! Alors initialement, c’est surtout parce que Christophe venait lui aussi d’y rentrer (bon j’ai du coup délaissé David … ^^) mais au final je l’ai assez peu croisé et j’ai dû me confronter aux effectifs en présence….

Honnêtement, ça a quand même été un choc. J’ai vu sur ces dernières années pas mal de choses, j’ai bien sûr eut des haut et des bas, j’imagine comme tout le monde… mais je ne mesurais pas à ce point comment j’avais surtout capitalisé sur des technologies qui avaient fait leur temps. D’un coup il m’a donc fallu intégrer dans mes outils du quotidien plein de nouveaux concepts et de manière de travailler….

Alors non bien sur je ne parle pas des processus de développement, de l’agilité… mais plutôt le fait que typiquement passer de Java 8 (et encore) à Java 11 implique quelques mise à jours qui même si elles ont été réalisé à titre personnelle, cela reste qu’un débroussaillage par rapport aux besoins que l’on peut en avoir dans une utilisation quotidienne!

Alors quand même! heureusement que j’ai bien débroussaillé ces dernières années! Je ne regrette pas ces heures de rafraîchissement sur Postgres et la normalisation des SGBD-R, ni cette monté en compétence sur docker qui m'a permis d'être OP des le GO sur les projets. Cependant, changer de projet, et partir sur de nouvelles techno c’est quand même la loterie et forcément on tombe toujours sur des numéros que l’on avait pas choisi!

Du coup même en ayant fait du String sur ces 10 dernières années, j’avoue que j’ai mesuré à quel point je n'étais qu’un utilisateur de cette technologie. Celle ci est vraiment trop magique et devenir vraiment compétent sur cette technologie nécessite de passer la montagne de la stupidité (cf Dunning-Kruger)

Alors oui bien sur j’ai d’autres compétences (du moins je l'espère ^^) mais quand celles ci ne sont pas à utiliser dans le cadre d’un projet, le sentiment qui en ressort est un gros syndrome de l’imposteur!

Enfin donc tout ça pour dire que ces deux derniers mois ont été très riches, que je n’ai pas eut le temps de consolider quoique ce soit mais, que je reviens doucement mais surement avec plein de sujet en tête… (sans oublier ceux qui étaient en cours….)

Du coup en aperçu, on parlera dans les prochains mois, de

  • ReST
  • Spring Boot
  • JavaScript
  • Reactor

Peut être aussi quelques sujet sur la sécurité (Spring Security, OAuth2, JWT, etc…)
Sans oublié je le disais les sujets sur l’IA:
  • Mnist
  • Les arbres de décision
  • Les forêts aléatoire


Et bien d’autres choses comme l'héritage de table dans Postgres, SpringData, peut être un peu de bayésianisme si enfin j’arrive à me poser sur ce sujet et meme un peu de réseau!

Donc à très vite pour le prochain article!