Fermer

septembre 8, 2020

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.

 Construisez une API RESTful avec Deno

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.

 MongoDB Connectez-vous "title =" MongoDB Connectez-vous "/></p data-recalc-dims=

Après authentification réussie, vous devrez créer un projet. Nommez le projet et cliquez sur le bouton Suivant .

 MongoDB Name Project "title =" MongoDB Name Project "/></p data-recalc-dims=

Ensuite, cliquez sur le bouton Créer un projet .

 MongoDB Créer un projet "title =" MongoDB Créer un projet "/></p data-recalc-dims=

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 .

 MongoDB Build Cluster "title =" MongoDB Build Cluster "/></p data-recalc-dims=

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.

 MongoDB Cluster Tier "title = "MongoDB Cluster Tier" /></p data-recalc-dims=

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.

 Créer un cluster de démarrage "title =" Créer un cluster de démarrage "/></p data-recalc-dims=

MongoDB Atlas prendra maintenant environ trois à cinq minutes pour configurer votre cluster.

 MongoDB Cluster Sandbox" title = "MongoDB Cluster Sandbox" /></p data-recalc-dims=

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 .

 MongoDB Add Database User "title =" MongoDB Add Database User "/> [19659004] Dans la boîte de dialogue qui apparaît, saisissez le nom d'utilisateur <strong data-recalc-dims= 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 .

 MongoDB Ajouter un utilisateur "title =" MongoDB Ajouter un utilisateur "/></p data-recalc-dims=

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.

 MongoDB Add IP Address "title =" MongoDB Add IP Address "/></p data-recalc-dims=

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.

 MongoDB Confirm Added IP Address "title =" MongoDB Confirm Added IP Address "/ ></p data-recalc-dims=

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 .

 MongoDB Connect "title =" MongoDB Connect "/></p data-recalc-dims=

Maintenant, cliquez sur sur Connectez votre application .

 MongoDB Connectez votre application "title =" MongoDB Connectez votre application "/></p data-recalc-dims=

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 .

 MongoDB Connection String "title =" MongoDB Connection String "/></p data-recalc-dims=

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

 Test du facteur: Créer un contact "title =" Test du facteur: Créer un contact "/></p data-recalc-dims=

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 .

 Postman Test; Get All Contact "title =" Test du facteur; Get All Contact "/></p data-recalc-dims=

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 .

 Test du facteur: obtenir un contact "title =" Test du facteur: obtenir One Contact "/></p data-recalc-dims=

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 .

 Test du facteur: Mettre à jour le contact "title =" Test du facteur: Mettre à jour le contact "/></p data-recalc-dims=

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 .

 Test du facteur: Supprimer le contact "title =" Test du facteur: Supprimer le contact "/></p data-recalc-dims=

Vous pouvez trouver le code source complet sur Github .





Source link