Pour connecter mon interface front-end à la base de données, je dois concevoir une API pour permettre à l'application front-end de récupérer et d'envoyer des données. Cela activera ma logique utilisateur, comme la création de comptes, la connexion et la déconnexion, etc. Cela activera toute la logique autour des rôtis.
J'ai déjà créé une API Express, mais cette fois, je voulais voir si je pouvais en apprendre un peu plus sur Swagger dans le processus de construction.
Swagger est une entreprise qui a conçu et gère trois produits, Swagger Editor, Swagger CodeGen et Swagger UI. Ces trois produits fonctionnent main dans la main pour faciliter la création d'une application compatible OpenAPI (et la documentation) !
Le processus d'utilisation de Swagger pour créer une API commence avec l'éditeur Swagger. Cet outil permet de créer ce qu'on appelle un contrat. Le contrat est un document YAML qui définit différentes choses sur l'application comme le nom, les itinéraires qu'elle gérera, etc.
Si vous n'avez jamais travaillé avec YAML auparavant, il s'agit d'un langage de balisage basé sur des objets plus souple qui présente certaines similitudes avec JSON, mais il est beaucoup plus facile à saisir rapidement. Voici un exemple du même contenu en JSON puis en YAML :
// JSON Example { "name": "ThisApp", "description": "An example of data.", "list": [ "option1", "option2", "option3" ], "object": { "key": "value" } }
# YAML Example name: ThisApp description: An example of data. list: - option1 - option2 - option3 object: key: value
Remarquez que YAML, bien que toujours lisible par machine, est également un peu plus facile à lire pour les humains, ce qui en fait un excellent langage de balisage pour cette spécification.
En utilisant Swagger Editor et en suivant OAS, vous pouvez écrire tout ce que vous programmeriez habituellement dans une API.
Au niveau supérieur, vous définirez les spécificités de l'application :
openapi: 3.0.3 info: title: Roast - Know Your Home Roasts description: # This will appear in the API UI version: 1.0.0 servers: - url: # A url to one or more servers here tags: These are groups of paths - name: user description: Operations for your user - name: roast description: Access to roasts paths: # Define all of your paths in this object components: # Define reusable pieces of code here
La magie de CodeEditor prend vie lorsque vous commencez à définir des chemins. Suivez le chemin suivant que j'ai défini pour obtenir un seul rôti par identifiant.
# ... contract information paths: # ... users paths, etc. /roasts/{roastId}: get: tags: - roast summary: Get roast by id description: Must include a valid roast id parameters: - $ref: '#/components/parameters/roastIdParam' responses: '200': description: Successful operation content: application/json: schema: $ref: "#/components/schemas/Roast" '400': $ref: '#/components/responses/Invalid' '404': $ref: '#/components/responses/NotFound'
Décomposons cet objet. Tout d’abord, il s’appelle /roasts/{roastId}. Cela signifie que nous définissons le comportement attendu du serveur lorsqu'une requête est envoyée sur cette route. Que se passe-t-il en dessous ?
En développant un contrat comme celui-ci, vous vous retrouverez probablement à taper les mêmes choses encore et encore. Et vous savez peut-être qu'en tant que programmeur, nous voulons suivre le principe DRY : "Ne vous répétez pas". Par exemple, lors de la définition d'un corps de requête requis, plusieurs points de terminaison peuvent nécessiter le même objet.
Eh bien, c'est ici que les composants entrent en jeu. Pour cet exemple, vous pouvez définir un schéma, puis référencer ce schéma n'importe où dans le contrat en utilisant $ref : .
Donc, en bas de mon contrat, j'ai un composant : objet.
components: schemas: Roast: # An arbitrary name to identify the schema type: object properties: id: type: integer format: int64 example: 10 ## Include all other properties
Cet objet composant contient un schéma appelé Roast , alors maintenant, si je devais spécifier que cet objet devait être envoyé dans une requête, par exemple, dans une requête POST à /roast pour ajouter un nouveau rôti. Je peux référencer l'objet de cette façon :
/roast: post: # additional specifications requestBody: content: application/json: schema: $ref: '#/components/schemas/Roast'
Vous pouvez également le faire en définissant vos paramètres et de nombreuses autres sections répétées de votre spécification !
Pendant que vous tapez dans votre éditeur Swagger, l'interface utilisateur de Swagger est constamment mise à jour dans la fenêtre à votre droite. Swagger UI met à jour ce qui deviendra la documentation de votre API ! Cela signifie que vous n'avez pas besoin de revenir plus tard et de rédiger vous-même la documentation.
La meilleure partie à ce sujet, c'est qu'il sera servi avec votre application (tant que vous utilisez CodeGen pour la créer).
Once you feel like your API is up to spec, you can have a working server in 17 different languages/frameworks in seconds! Just click Generate Server, and select your flavor and CodeGen reads your OAS spec and downloads a server.
In Node, your code comes out in a few different directories.
generated-server/ |-- api/ |-- controllers/ |-- service/ |-- utils/ |-- README.md |-- index.js |-- package.json
The api directory contains your OpenAPI spec. The controllers directory contains a file for each of your path groups, with exported functions specifically for handling the unique paths and operations of your application. The service directory, is where you will hook these operations up to your database and perform the business logic of the application, and utils contains functions that help read and write data.
Your server will actually live in index.js.
Yes! Well, sort of.
CodeGen does in fact make a working server for you, but it's still up to you to hook up the database and design the logic of the application! But, it gives you a complete and organized skeleton that you can work in!
Here's an example of the code that it output for my POST request to /roasts .
// controllers/Roast.js // ... module.exports.addRoast = function addRoast (req, res, next, body) { Roast.addRoast(body) .then(function (response) { utils.writeJson(res, response); }) .catch(function (response) { utils.writeJson(res, response); }); }; // service/RoastService.js // ... exports.addRoast = function(body) { return new Promise(function(resolve, reject) { var examples = {}; examples['application/json'] = { "notes" : "Doesn't taste as good as last time... I wonder if the weather is making the beans roast faster now that it's warmer", "heatLevel" : "Med", "origin" : "Ethiopian", // ... "id" : 10, }; if (Object.keys(examples).length > 0) { resolve(examples[Object.keys(examples)[0]]); } else { resolve(); } }); }
The above code was entirely generated by Swagger CodeGen. However, it won't actually add a roast object anywhere. This is creating a mock object and sending it back. But, after hooking up a Postgres database, and creating queries with this logic inside the service, the API will be fully operational!
I loved working with Swagger on this API, it was the first time that I committed to learning some of the intricacies of OAS to generate the server. The only rub that I have with it is that the docs are not formatted the best, and they can be hard to navigate searching for what you want to add to the server.
But, once you're familiar with OAS, this tool can save a ton of time. Not only do you have extremely thorough documentation when you're done, but you can treat the generated code as a to-do list of the functions and logic that you need to implement as you build!
Would you give it a try?
If you want to keep up with the changes, fork and run locally, or even suggest code changes, here’s a link to the GitHub repo!
https://github.com/nmiller15/roast
The frontend application is currently deployed on Netlify! If you want to mess around with some features and see it in action, view it on a mobile device below.
https://knowyourhomeroast.netlify.app
Note: This deployment has no backend api, so accounts and roasts are not actually saved anywhere between sessions.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!