Comment créer une API RESTful avec Deno

Dans cet article, nous allons créer une API de contact à part entière avec Deno – un runtime simple, moderne et sécurisé pour JavaScript et TypeScript qui utilise V8 et est construit avec Rust.
Dans la première partie de cette série nous avons abordé les principes fondamentaux de Deno, et également couvert des choses comme les fonctionnalités, la bibliothèque standard, l'installation et bien plus encore. Dans cet article, nous allons créer une API RESTful. Si vous êtes un novice total de la programmation côté serveur, cet article vous mettra à l'aise avec le runtime.
Voici une liste de quelques microframeworks REST pour Deno:
Nous allons utiliser le framework abc pour construire le contact API.
L'API que nous allons construire pourra:
- Créer un contact et le stocker dans une base de données MongoDB
- Récupérer un ou plusieurs contacts de la base de données en fonction de la demande
- Mettre à jour un contact existant dans la base de données
- Supprimez tout contact de la base de données sur demande
Nous le ferons dans TypeScript, mais rien ne vous empêche de créer l'API en JavaScript – vous pouvez supprimer les types, et vous êtes prêt à
PS: Dans le post précédent j'ai déjà expliqué comment installer Deno, alors n'hésitez pas à vérifier cela, ou suivez l'installation officielle de denoland sur githhub .
Configurer MongoDB Atlas
Pour pouvoir utiliser MongoDB services cloud, vous aurez besoin d'un compte MongoDB Atlas. Pour en créer un, accédez à sa page d'accueil et inscrivez-vous ou connectez-vous si vous avez un compte.
Après authentification réussie, vous devrez créer un projet. Nommez le projet et cliquez sur le bouton Suivant .
Ensuite, cliquez sur le bouton Créer un projet .
REMARQUE: Un cluster MongoDB est le mot généralement utilisé pour cluster partitionné dans MongoDB. Les principaux objectifs d'une MongoDB partitionnée sont:
- L'échelle lit et écrit le long de plusieurs nœuds du cluster
- Chaque nœud ne gère pas toutes les données, vous pouvez donc séparer données le long de tous les nœuds de la partition – chaque nœud est membre d'une partition et les données sont séparées sur toutes les partitions
Pour plus d'informations, lisez le document officiel docs . Maintenant, nous devons créer un cluster pour notre projet, donc cliquez sur Build a Cluster .
Cliquez sur le Créer un cluster dans la section Cluster Tier et sélectionnez l'option Shared Cluster pour créer votre cluster de niveau gratuit.
Pour minimiser la latence du réseau, vous choisiriez idéalement une région proche. Cliquez sur le bouton Créer un cluster .
REMARQUE: Si vous développez sur le cloud, choisissez le fournisseur de cloud correspondant.
MongoDB Atlas prendra maintenant environ trois à cinq minutes pour configurer votre cluster.
Avant de commencer à utiliser le cluster , vous devrez fournir quelques détails relatifs à la sécurité. Passez à l'onglet Database Access puis cliquez sur Add New Database User .
et le mot de passe sélectionnez le privilège Lire et écrire dans n'importe quelle base de données puis cliquez sur le ] Bouton Ajouter un utilisateur .
Ensuite, dans la section Accès réseau vous devez fournir une liste de Adresses IP à partir desquelles vous accéderez au cluster. Cliquez sur l'onglet Accès réseau et sélectionnez Ajouter une adresse IP.
Pour le Pour cette démo, cliquez sur Autoriser l'accès de n'importe où pour remplir automatiquement le champ Entrée de la liste blanche puis cliquez sur le bouton Confirmer .
REMARQUE: Ceci est juste pour le développement; dans un environnement de production, vous devrez entrer l'adresse IP statique du serveur qui accédera à la base de données.
Enfin, vous aurez besoin d'une chaîne de connexion valide pour vous connecter à votre cluster depuis votre application. Pour l'obtenir, retournez dans l'onglet Cluster et cliquez sur Connect .
Maintenant, cliquez sur sur Connectez votre application .
Pour l'instant, il n'y a pas encore de chaîne de connexion officielle Deno, mais nous le ferons utilisez la chaîne de connexion Node.js. Sélectionnez Node.js dans la liste déroulante DRIVER VERSION 2.2.12 ou version ultérieure. Cliquez sur Copier .
REMARQUE: La chaîne de connexion n'aura pas votre mot de passe, vous devrez donc remplissez-le manuellement dans l'espace réservé.
Configurer le serveur
Créez un répertoire de projet:
mkdir contactAPI
Créez un fichier .env
:
touch .env
Dans le fichier .env
créez un nom de base de données et collez la chaîne de connexion que nous avons copiée précédemment à partir de MongoDB:
DB_NAME =
DB_HOST_URL =
Ensuite, créez un dossier appelé utils
et à l'intérieur, créez un fichier middleware.ts
:
mkdir utils
toucher middlewares.ts
Ci-dessous, nous avons deux middlewares mis en place, pour la journalisation de chaque requête et pour gérer les erreurs détectées dans les contrôleurs:
import { MiddlewareFunc Context } [19659060] de "https://deno.land/x/abc@v1.0.0-rc2/mod.ts" ;
export class ErrorHandler s'étend ] Erreur {
status : numéro ;
constructeur ( message : string status : numéro [19659062]) {
super ( message ) ;
this . status = status ;
}
}
export const LogMiddleware : MiddlewareFunc = ( next ) =>
async ( c ) => {
const start = Date . now [19659062] ()
const { method url proto } = c . demande
attendre suivant ( c ) ;
console . log ( JSON . stringify ( {
heure : Date ()
méthode
url
proto
response_time : Date . now () - start + "millisecond"
response_status : c . response . status
} null " t" ) )
}
export const ErrorMiddleware : MiddlewareFunc = ( next ) =>
async ( c ) => [19659062]) {
const error = err as ErrorHandler ;
c . response . status = error . status || 500 ;
c . response . body = error . message ;
}
} ;
Il est maintenant temps d'écrire le code de notre serveur. Commençons par créer un fichier main.ts
dans le répertoire du projet:
touch main.ts
import { Application } de "https://deno.land/x/abc@v1.0.0-rc2/mod.ts" ;
import "https://deno.land/x/dotenv/load.ts" ;
import {
getAllContact
createContact
getOneContact
updateContact
deleteContact
} from "./ controllers / contacts.ts" ;
import {
ErrorMiddleware
LogMiddleware
} de "./ utils / middlewares.ts" ;
const app = new Application ( ]) ;
app . use ( LogMiddleware )
. use ( ErrorMiddleware )
app . get ( "/ contacts" getAllContact )
. post ( "/ contact " createContact )
. get (" / contact /: id " getOneContact )
. put ( "/ contact /: id" updateContact )
. delete ( "/ contact / : id " deleteContact )
. start ( { port : 5000 } ) ;
console . log ( `serveur écoutant sur http: // localhost: 5000` ) ;
Dans la première ligne, remarquez comment nous importons des modules d'Internet directement en utilisant l'URL.
La deuxième ligne importe le module dotenv pour charger les variables d'environnement à partir du fichier .env. Le reste du code est similaire à express, rien de spécial.
Maintenant, nous devons configurer notre base de données pour interagir avec le serveur. Nous allons utiliser deno_mongo un pilote de base de données MongoDB développé pour Deno. Il est en cours de développement actif et ne contient pas pour l'instant les différentes méthodes d'un pilote MongoDB complet.
mkdir models
touchez db.ts
import { init MongoClient } de "https://deno.land/x/mongo@v0.8.0/mod. ts ";
class DB {
public client : MongoClient ;
constructor ( public dbName : string public url : string ) {
this . ] dbName = dbName ;
this . url = url ;
this . client = {} as MongoClient ;
}
connect () {
const client = nouveau MongoClient () ;
client . connectWithUri ( this . url ) ;
this . client = client ;
}
get getDatabase () {
return this . client . base de données ( this . dbName ) ;
}
}
const dbName = Deno . env . get ( "DB_NAME" ) || "contactdb" ; [19659063] const dbHostUrl = Deno . env . get ( "DB_HOST_URL" ) || [19659061] "mongodb: // localhost: 27017" ;
console . log ( dbName dbHostUrl )
const db = new DB [19659062] ( dbName dbHostUrl ) ;
db . connect () ;
export default db ;
Ici, j'ai créé une classe DB
; puis, j'ai instancié la classe avec le paramètre DB_NAME
et DB_HOST_URL
récupéré à partir de la variable d'environnement.
REMARQUE: Deno.env.get () est utilisé pour récupérer la variable d'environnement we défini plus tôt.
Maintenant, il est temps de configurer nos contrôleurs.
contrôleurs mkdir
touch contracts.ts
import { HandlerFunc Context } from "https://deno.land/x/abc@v1.0.0-rc2/ mod.ts ";
import db from '../ models / db.ts' ;
import { ErrorHandler } de "../ utils / middlewares.ts"
const database = db . getDatabase ; [19659063] const contacts = base de données . collection ( 'contacts' ) ;
interface Contact [19659059] {
_id : {
$ oid : chaîne ;
} ;
nom : chaîne ;
âge : numéro ;
email : chaîne ;
adresse : chaîne ;
}
...
Tout d'abord, nous avons importé le type HandlerFunc
du module abc. Ce sera le type attribué à toutes nos fonctions de gestionnaire. Ensuite, nous avons utilisé la méthode getDatabase
que nous avons créée précédemment pour récupérer notre classe Database . Ensuite, nous avons utilisé la méthode de collecte pour configurer notre collection. L'interface Contact
est utilisée lorsque nous voulons récupérer tous les contacts de notre collection.
createContact : Ajoute le contact à la base de données.
export const createContact : HandlerFunc = async ( c : Context ) => {
] essayez {
if ( c . request . headers . get ( " content-type ") ! == " application / json ") {
throw new ErrorHandler (" Corps non valide " 422 ) ;
}
const body = wait ( c . corps () ) ;
if (! Object . keys [1 9659062] ( body ) . length ) {
throw new ErrorHandler ( "Request body can ne soyez pas vide! " 400 ) ;
}
const { name age courriel adresse } = corps ;
const inséréContact = attendre contacts . insertOne ( {
nom
âge
courriel
adresse
} ) ;
return c . json ( inséréContact 201 ) [19659062];
} catch ( error ) {
throw new ErrorHandler ( error . message error . status || 500 ) ;
}
} ; [19659358] ...
Test sur le facteur : Faire une demande POST sur / contact
. Démarrez le serveur et assurez-vous d'utiliser les indicateurs appropriés bien sûr:
deno run --allow-write --allow-read --allow-plugin --allow-net --allow-env --unstable ./ main.ts
La première fois que vous exécutez le serveur, Deno télécharge et met en cache les dépendances. La prochaine fois devrait ressembler à quelque chose de similaire dans votre terminal.
INFO charger le plugin deno "deno_mongo" à partir du local "~ / .deno_plugins / deno_mongo_40ee79e739a57022e3984775fe5fd0ff.dll"
serveur écoutant sur http: // localhost: 5000
getAllContact: Ceci récupère tous les contacts de la base de données.
export const getOneContact : HandlerFunc = async ( c : Context ) => {
essayez {
const { id } = c . params as { id : string } ;
const getContact = wait contacts . findOne ( { _id : { "$ oid" : id } } ) ;
if ( getContact ) {
const { _id : { $ oid } [19659062] nom âge email adresse } = getContact ;
return c . json ( { id : $ oid name age email address } 200 ) ;
}
throw new [19659065] ErrorHandler ( "Contact not found" 404 ) ;
} catch ( error ) {
throw new ErrorHandler ( error . message error . status ] || 500 ) ;
}
} ;
...
Test sur Postman : Faire une requête GET sur / contacts
.
getOneContact: Récupère un contact de la base de données par identifiant.
export const getOneContact : HandlerFunc = async ( c : Context ) => {
try {
const { id } = c . params as { id : string } ;
const getContact = wait contacts . findOne ( { _id : {[19659061] "$ oid" : id } } ) ;
if ( getContact ) {
const { _id : { $ oid } name age em ail adresse } = getContact ;
return c . json ( { id : $ oid nom age email address } [19659062] 200 ) ;
}
throw new ErrorHandler ( "Contact not found" 404 ) ;
} catch ( error ) {
throw new ErrorHandler ( ] error . message error . status || 500 ) ;
}
} ;
...
Test sur le facteur : Faire une requête GET sur / contact /: id
.
updateContact: Il mettra à jour le contact avec l'ID spécifié dans la base de données.
export const updateContact : HandlerFunc = asynchrone ( c : Contexte ) => {
try {
const ] { id } = c . params as { id : string } ;
if ( c . request . headers . get ( "content- type ") ! == " application / json ") {
throw new ErrorHandler [196590] 62] ( "Invalid body" 422 ) ;
}
const body = wait ( c . corps () ) comme {
name ? : string ;
âge ? : numéro ;
email ? : string ;
adresse ? : string ;
} ;
if (! Object . keys [19659062] ( body ) . length ) {
throw new ErrorHandler ( "Request body can ne soyez pas vide! " 400 ) ;
}
const getContact = wait contacts . [19659096] findOne ( { _id : { "$ oid" : id } } ) ;
if ( getContact ) {
const { matchedCount } = wait contacts . updateOne (
{ _id : { "$ oid" : id } [19659059]}
{ $ set : body }
) ;
if ( matchedCount ) {
return c . string ( "Contact mis à jour avec succès!" 204 ) ;
}
return c . string ( "Unable to update contact" ) ;
}
throw new [19659065] ErrorHandler ( "Contact not found" 404 ) ;
} catch ( error ) {
throw new ErrorHandler ( error . message error . status || 500 ) ;
}
} ;
...
Test sur le facteur : Faire une requête PUT sur / contact /: id
.
deleteContact: Ceci supprime le contact avec l'ID spécifié
dans la base de données.
export const deleteContact: HandlerFunc = async (c: Context) => {
essayez {
const {id} = c.params as {id: string};
const getContact = attendre contacts.findOne ({_id: {"$ oid": id}});
if (getContact) {
const deleteCount = attendre contacts.deleteOne ({_id: {"$ oid": id}});
if (deleteCount) {
return c.string ("Contact supprimé avec succès!", 204);
}
throw new ErrorHandler ("Impossible de supprimer l'employé", 400);
}
throw new ErrorHandler ("Contact not found", 404);
} catch (erreur) {
lancer un nouveau ErrorHandler (error.message, error.status || 500);
}
};
Test sur le facteur : Faire une demande DELETE sur / contact /: id
.
Vous pouvez trouver le code source complet sur Github .
Source link