Comment construire une API Rest ?

Comment construire une API Rest ?

Introduction

Dans un précédent article, nous avons défini ce qu’était une API REST. Mais comment cela se traduit-il dans le code ? Afin d’illustrer cela, Hubvisory te propose de créer ensemble une API Rest en JavaScript. Les pré-requis ? Une compréhension de base de JavaScript, Node JS, un IDE et un Terminal !

Les bases de l’API Rest

Avant de se lancer dans la création d’une API Rest, il est important de définir sa structure, c’est-à-dire :

  • Déterminer la/les ressource(s) dont on aura besoin
  • Déterminer si on a besoin des quatre opérations CRUD (Create, Read, Update, Delete)
  • Définir des points de terminaisons (Endpoint)
  • Documenter son API

Le dernier élément est crucial, surtout si vous créez des API publiques, car il permet aux autres développeurs de comprendre votre API et d’avoir des exemples de requêtes et de réponses précises.

Contexte

Nous souhaitons créer une API Rest permettant à des restaurateurs de :

  • Enregistrer des commandes des clients
  • Visualiser toutes les commandes
  • Modifier des commandes qui n’ont pas encore été réglées
  • Supprimer des commandes

Conception

Le contexte étant fixé, nous identifions la ressource “orders” pour les commandes. Nous pouvons donc définir nos points de terminaison (URI) en sachant que d’après le contexte, nous aurons besoin de réaliser les opérations CRUD suivantes :

  • GET /orders
  • POST /orders
  • PUT /orders/{orderID}
  • DELETE /orders/{orderID}

Réalisation

Dans un nouveau dossier, créez un fichier “index.js” dans lequel nous allons ajouter le code suivant :

// Charge le module HTTP
const http = require("http");
const host = "localhost";
const port = 8000;

// Fonction qui renvoie les réponses du serveur
const requestOrders = function (req, res) {
  res.writeHead(200);
  res.end("Hello world !!");
};

// Crée l'objet serveur qui acceptera les requêtes HTTP
const server = http.createServer(requestOrders);

// Démarre le serveur sur le port renseigné
server.listen(port, host, () => {
  console.log(`Le serveur est accessible à l'adresse http://${host}:${port}`);
});

Dans le Terminal, tapez la commande “node index.js” pour lancer le serveur. Vous devriez voir s’afficher dans le Terminal “Le serveur est accessible à l’adresse http://localhost:8000“. Ouvrez un navigateur et saisissez “http://localhost:8000” : vous devriez voir s’afficher “Hello world !!”. Notre serveur fonctionne correctement.

À lire aussi  Guide du débutant pour Genshin Impact en 2023 : astuces et conseils

Par la suite, nous utiliserons l’outil CLI “curl” dans une nouvelle fenêtre du Terminal pour communiquer avec le serveur.

Avant de créer notre API, nous allons créer une constante contenant nos commandes. Ajoutez le code suivant dans le fichier “index.js” :

let orders = JSON.stringify([
  {
    id: "OGCXnHRzZPjDIoPGyuutcMbx",
    total: 10,
    items: [
      {
        id: "6EqtxEG93VwrRLunr5uyXOJT",
        name: "Salade",
        price: 10,
      },
    ],
  },
  {
    id: "8DhLRD2M7NdzlqUYpDdLX7sb",
    total: 15,
    items: [
      {
        product: [
          {
            id: "jYKdRprTRAhK7GXsEwapaK6L",
            name: "Pâtes",
            price: 15,
          },
        ],
      },
    ],
  },
]);

Maintenant, passons à notre API Rest.

Méthode GET

Dans la fonction “requestOrders()” que nous avons précédemment créée, supprimez la ligne “res.end(“Hello world !!”)” et ajoutez le code suivant :

switch (req.url) {
  case "/orders":
    res.writeHead(200);
    res.end(orders);
    break;
}

Enregistrez et entrez la commande “node index.js” dans le Terminal. Ensuite, dans un autre terminal, entrez la commande suivante :

curl -i -X GET http://localhost:8000/orders

Le résultat devrait ressembler à ceci :

[
  {
    "id": "OGCXnHRzZPjDIoPGyuutcMbx",
    "total": 10,
    "items": [
      {
        "id": "6EqtxEG93VwrRLunr5uyXOJT",
        "name": "Salade",
        "price": 10
      }
    ]
  },
  {
    "id": "8DhLRD2M7NdzlqUYpDdLX7sb",
    "total": 15,
    "items": [
      {
        "product": [
          {
            "id": "jYKdRprTRAhK7GXsEwapaK6L",
            "name": "Pâtes",
            "price": 15
          }
        ]
      }
    ]
  }
]

Méthode POST

Dans la fonction “requestOrders()”, ajoutez le code suivant :

case "/orders":
  req.on("data", (chunk) => {
    data += chunk;
  });
  req.on("end", () => {
    orders = JSON.stringify(JSON.parse(orders).concat(JSON.parse(data)));
    res.end(orders);
  });
  res.writeHead(200);
  break;

Enregistrez et relancez le serveur. Ensuite, dans un autre terminal, entrez la commande suivante :

curl -i -X POST -H 'Content-Type: application/json' -d '{"id": "Dw3ZTpjRK4UVHqC_S6DGqpGe","total": 6,"items": [{"id": "YuHopwCycWGapzKoxh-coL3o","name": "Coca","price": 6}]}' http://localhost:8000/orders

Le résultat devrait ressembler à ceci :

[
  {
    "id": "OGCXnHRzZPjDIoPGyuutcMbx",
    "total": 10,
    "items": [
      {
        "id": "6EqtxEG93VwrRLunr5uyXOJT",
        "name": "Salade",
        "price": 10
      }
    ]
  },
  {
    "id": "8DhLRD2M7NdzlqUYpDdLX7sb",
    "total": 15,
    "items": [
      {
        "product": [
          {
            "id": "jYKdRprTRAhK7GXsEwapaK6L",
            "name": "Pâtes",
            "price": 15
          }
        ]
      }
    ]
  },
  {
    "id": "Dw3ZTpjRK4UVHqC_S6DGqpGe",
    "total": 6,
    "items": [
      {
        "product": [
          {
            "id": "YuHopwCycWGapzKoxh-coL3o",
            "name": "Coca",
            "price": 6
          }
        ]
      }
    ]
  }
]

Méthode PUT

Dans la fonction “requestOrders()”, ajoutez le code suivant :

case `/orders/${orderID}`:
  req.on("data", (chunk) => {
    data += chunk;
  });
  req.on("end", () => {
    orders = JSON.stringify(
      JSON.parse(orders).map((order) => {
        if (order.id === orderID) return JSON.parse(data);
        return order;
      })
    );
    res.end(orders);
  });
  res.writeHead(200);
  break;

Enregistrez et relancez le serveur. Ensuite, dans un autre terminal, entrez la commande suivante :

curl -i -X PUT -H 'Content-Type: application/json' -d '{"id": "8DhLRD2M7NdzlqUYpDdLX7sb","total": 14,"items": {"id": "DUyibRqzUHCd1kKvOD-wz28O","name": "Hamburger","price": 14}}' http://localhost:8000/orders/8DhLRD2M7NdzlqUYpDdLX7sb

Le résultat devrait ressembler à ceci :

[
  {
    "id": "OGCXnHRzZPjDIoPGyuutcMbx",
    "total": 10,
    "items": [
      {
        "id": "6EqtxEG93VwrRLunr5uyXOJT",
        "name": "Salade",
        "price": 10
      }
    ]
  },
  {
    "id": "8DhLRD2M7NdzlqUYpDdLX7sb",
    "total": 14,
    "items": [
      {
        "product": [
          {
            "id": "DUyibRqzUHCd1kKvOD",
            "name": "Hamburger",
            "price": 14
          }
        ]
      }
    ]
  }
]

Méthode DELETE

Dans la fonction “requestOrders()”, ajoutez le code suivant :

case `/orders/${orderID}`:
  orders = JSON.stringify(
    JSON.parse(orders).filter((order) => order.id !== orderID)
  );
  res.writeHead(200);
  res.end(orders);
  break;

Enregistrez et relancez le serveur. Ensuite, dans un autre terminal, entrez la commande suivante :

curl -i -X DELETE http://localhost:8000/orders/8DhLRD2M7NdzlqUYpDdLX7sb

Le résultat devrait ressembler à ceci :

[
  {
    "id": "OGCXnHRzZPjDIoPGyuutcMbx",
    "total": 10,
    "items": [
      {
        "id": "6EqtxEG93VwrRLunr5uyXOJT",
        "name": "Salade",
        "price": 10
      }
    ]
  }
]

Voici à quoi devrait ressembler votre script final :

// Charge le module HTTP
const http = require("http");
const host = "localhost";
const port = 8000;

let orders = JSON.stringify([
  {
    id: "OGCXnHRzZPjDIoPGyuutcMbx",
    total: 10,
    items: [
      {
        id: "6EqtxEG93VwrRLunr5uyXOJT",
        name: "Salade",
        price: 10,
      },
    ],
  },
  {
    id: "8DhLRD2M7NdzlqUYpDdLX7sb",
    total: 15,
    items: [
      {
        product: [
          {
            id: "jYKdRprTRAhK7GXsEwapaK6L",
            name: "Pâtes",
            price: 15,
          },
        ],
      },
    ],
  },
]);

const requestOrders = function (req, res) {
  res.writeHead(200);
  let data = "";
  let orderID = "";

  switch (req.url) {
    case "/orders":
      res.writeHead(200);
      res.end(orders);
      break;
    case "/orders":
      req.on("data", (chunk) => {
        data += chunk;
      });
      req.on("end", () => {
        orders = JSON.stringify(JSON.parse(orders).concat(JSON.parse(data)));
        res.end(orders);
      });
      res.writeHead(200);
      break;
    case `/orders/${orderID}`:
      req.on("data", (chunk) => {
        data += chunk;
      });
      req.on("end", () => {
        orders = JSON.stringify(
          JSON.parse(orders).map((order) => {
            if (order.id === orderID) return JSON.parse(data);
            return order;
          })
        );
        res.end(orders);
      });
      res.writeHead(200);
      break;
    case `/orders/${orderID}`:
      orders = JSON.stringify(
        JSON.parse(orders).filter((order) => order.id !== orderID)
      );
      res.writeHead(200);
      res.end(orders);
      break;
  }
};

const server = http.createServer(requestOrders);
server.listen(port, host, () => {
  console.log(`Le serveur est accessible à l'adresse http://${host}:${port}`);
});

Ceci n’étant qu’un script rudimentaire, voici certaines des évolutions qu’il est possible d’y ajouter :

  • Ajouter une méthode GET /orders/:id pour récupérer un élément précis de la liste
  • Ajouter une méthode PATCH /orders/:id pour modifier une commande sans la recharger complètement
  • Refactoriser le code afin de supprimer les utilisations redondantes de JSON.stringify() et JSON.parse()
  • Sauvegarder les données dans un fichier pour les rendre persistantes
À lire aussi  Guide du débutant pour Genshin Impact en 2023 : astuces et conseils

Conclusion

Vous voilà désormais capable de créer une API Rest !

Vous avez pu constater qu’il existe de nombreux éléments redondants dans la création d’une API REST.

Heureusement, il existe de nombreux outils capables de simplifier ces démarches, tels que Express ou NestJS.