One place for hosting & domains

      Module

      How To Use the collections Module in Python 3


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Python 3 has a number of built-in data structures, including tuples, dictionaries, and lists. Data structures provide us with a way to organize and store data. The collections module helps us populate and manipulate data structures efficiently.

      In this tutorial, we’ll go through three classes in the collections module to help you work with tuples, dictionaries, and lists. We’ll use namedtuples to create tuples with named fields, defaultdict to concisely group information in dictionaries, and deque to efficiently add elements to either side of a list-like object.

      For this tutorial, we’ll be working primarily with an inventory of fish that we need to modify as fish are added to or removed from a fictional aquarium.

      Prerequisites

      To get the most out of this tutorial, it is recommended to have some familiarity with the tuple, dictionary, and list data types, both with their syntax, and how to retrieve data from them. You can review these tutorials for the necessary background information:

      Adding Named Fields to Tuples

      Python tuples are an immutable, or unchangeable, ordered sequence of elements. Tuples are frequently used to represent columnar data; for example, lines from a CSV file or rows from a SQL database. An aquarium might keep track of its inventory of fish as a series of tuples.

      An individual fish tuple:

      ("Sammy", "shark", "tank-a")
      

      This tuple is composed of three string elements.

      While useful in some ways, this tuple does not clearly indicate what each of its fields represents. In actuality, element 0 is a name, element 1 is a species, and element 2 is the holding tank.

      Explanation of fish tuple fields:

      name species tank
      Sammy shark tank-a

      This table makes it clear that each of the tuple’s three elements has a clear meaning.

      namedtuple from the collections module lets you add explicit names to each element of a tuple to make these meanings clear in your Python program.

      Let’s use namedtuple to generate a class that clearly names each element of the fish tuple:

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple gives your Python program access to the namedtuple factory function. The namedtuple() function call returns a class that is bound to the name Fish. The namedtuple() function has two arguments: the desired name of our new class "Fish" and a list of named elements ["name", "species", "tank"].

      We can use the Fish class to represent the fish tuple from earlier:

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      If we run this code, we’ll see the following output:

      Output

      Fish(name='Sammy', species='shark', tank='tank-a')

      sammy is instantiated using the Fish class. sammy is a tuple with three clearly named elements.

      sammy’s fields can be accessed by their name or with a traditional tuple index:

      print(sammy.species)
      print(sammy[1])
      

      If we run these two print calls, we’ll see the following output:

      Output

      shark shark

      Accessing .species returns the same value as accessing the second element of sammy using [1].

      Using namedtuple from the collections module makes your program more readable while maintaining the important properties of a tuple (that they’re immutable and ordered).

      In addition, the namedtuple factory function adds several extra methods to instances of Fish.

      Use ._asdict() to convert an instance to a dictionary:

      print(sammy._asdict())
      

      If we run print, you’ll see output like the following:

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      Calling .asdict() on sammy returns a dictionary mapping each of the three field names to their corresponding values.

      Python versions older than 3.8 might output this line slightly differently. You might, for example, see an OrderedDict instead of the plain dictionary shown here.

      Note: In Python, methods with leading underscores are usually considered “private.” Additional methods provided by namedtuple (like _asdict(), ._make(), ._replace(), etc.), however, are public.

      Collecting Data in a Dictionary

      It is often useful to collect data in Python dictionaries. defaultdict from the collections module can help us assemble information in dictionaries quickly and concisely.

      defaultdict never raises a KeyError. If a key isn’t present, defaultdict just inserts and returns a placeholder value instead:

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      If we run this code, we’ll see output like the following:

      Output

      []

      defaultdict inserts and returns a placeholder value instead of throwing a KeyError. In this case we specified the placeholder value as a list.

      Regular dictionaries, in contrast, will throw a KeyError on missing keys:

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      If we run this code, we’ll see output like the following:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      The regular dictionary my_regular_dict raises a KeyError when we try to access a key that is not present.

      defaultdict behaves differently than a regular dictionary. Instead of raising a KeyError on a missing key, defaultdict calls the placeholder value with no arguments to create a new object. In this case list() to create an empty list.

      Continuing with our fictional aquarium example, let’s say we have a list of fish tuples representing an aquarium’s inventory:

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      Three fish exist in the aquarium—their name, species, and holding tank are noted in these three tuples.

      Our goal is to organize our inventory by tank—we want to know the list of fish present in each tank. In other words, we want a dictionary that maps "tank-a" to ["Jamie", "Mary"] and "tank-b" to ["Jamie"].

      We can use defaultdict to group fish by tank:

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      Running this code, we’ll see the following output:

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank is declared as a defaultdict that defaults to inserting list() instead of throwing a KeyError. Since this guarantees that every key in fish_names_by_tank will point to a list, we can freely call .append() to add names to each tank’s list.

      defaultdict helps you here because it reduces the chance of unexpected KeyErrors. Reducing the unexpected KeyErrors means your program can be written more clearly and with fewer lines. More concretely, the defaultdict idiom lets you avoid manually instantiating an empty list for every tank.

      Without defaultdict, the for loop body might have looked more like this:

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      Using just a regular dictionary (instead of a defaultdict) means that the for loop body always has to check for the existence of the given tank in fish_names_by_tank. Only after we’ve verified that tank is already present in fish_names_by_tank, or has just been initialized with a [], can we append the fish name.

      defaultdict can help cut down on boilerplate code when filling up dictionaries because it never raises a KeyError.

      Using deque to Efficiently Add Elements to Either Side of a Collection

      Python lists are a mutable, or changeable, ordered sequence of elements. Python can append to lists in constant time (the length of the list has no effect on the time it takes to append), but inserting at the beginning of a list can be slower—the time it takes increases as the list gets bigger.

      In terms of Big O notation, appending to a list is a constant time O(1) operation. Inserting at the beginning of a list, in contrast, is slower with O(n) performance.

      Note: Software engineers often measure the performance of procedures using something called “Big O” notation. When the size of an input has no effect on the time it takes to perform a procedure, it is said to run in constant time or O(1) (“Big O of 1”). As you learned above, Python can append to lists with constant time performance, otherwise known as O(1).

      Sometimes, the size of an input directly affects the amount of time it takes to run a procedure. Inserting at the beginning of a Python list, for example, runs slower the more elements there are in the list. Big O notation uses the letter n to represent the size of the input. This means that adding items to the beginning of a Python list runs in “linear time” or O(n) (“Big O of n”).

      In general, O(1) procedures are faster than O(n) procedures.

      We can insert at the beginning of a Python list:

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      If we run the following, we will see output like the following:

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      The .insert(index, object) method on list allows us to insert "Alice" at the beginning of favorite_fish_list. Notably, though, inserting at the beginning of a list has O(n) performance. As the length of favorite_fish_list grows, the time to insert a fish at the beginning of the list will grow proportionally and take longer and longer.

      deque (pronounced “deck”) from the collections module is a list-like object that allows us to insert items at the beginning or end of a sequence with constant time (O(1)) performance.

      Insert an item at the beginning of a deque:

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      Running this code, we will see the following output:

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      We can instantiate a deque using a preexisting collection of elements, in this case a list of three favorite fish names. Calling favorite_fish_deque’s appendleft method allows us to insert an item at the beginning of our collection with O(1) performance. O(1) performance means that the time it takes to add an item to the beginning of favorite_fish_deque will not grow even if favorite_fish_deque has thousands or millions of elements.

      Note: Although deque adds entries to the beginning of a sequence more efficiently than a list, deque does not perform all of its operations more efficiently than a list. For example, accessing a random item in a deque has O(n) performance, but accessing a random item in a list has O(1) performance. Use deque when it is important to insert or remove elements from either side of your collection quickly. A full comparison of time performance is available on Python’s wiki.

      Conclusion

      The collections module is a powerful part of the Python standard library that lets you work with data concisely and efficiently. This tutorial covered three of the classes provided by the collections module including namedtuple, defaultdict, and deque.

      From here, you can use the collection module’s documentation to learn more about other available classes and utilities. To learn more about Python in general, you can read our How To Code in Python 3 tutorial series.



      Source link

      Comment créer un serveur Web en Node.js avec le module HTTP


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Lorsque vous visualisez une page web dans votre navigateur, vous faites une demande à un autre ordinateur sur internet, qui vous fournit alors la page web en réponse. L’ordinateur avec lequel vous parlez via l’internet est un serveur web. Un serveur web reçoit des requêtes HTTP d’un client, comme votre navigateur, et fournit une réponse HTTP, comme une page HTML ou JSON d’une API.

      De nombreux logiciels sont nécessaires pour qu’un serveur renvoie une page web. Ces logiciels se classent généralement en deux catégories : le frontend et le backend. Le code front-end concerne la manière dont le contenu est présenté, comme la couleur d’une barre de navigation et le style du texte.  Le code back-end concerne la manière dont les données sont échangées, traitées et stockées.  Le code qui traite les requêtes réseau de votre navigateur ou qui communique avec la base de données est principalement géré par le code back-end.

      Node.js permet aux développeurs d’utiliser JavaScript pour écrire du code back-end, même si, traditionnellement, il était utilisé dans le navigateur pour écrire du code front-end. Le fait d’avoir le front-end et le back-end ensemble de cette manière réduit l’effort nécessaire pour créer un serveur web, ce qui est une des raisons majeures pour lesquelles Node.js est un choix populaire pour écrire du code back-end.

      Dans ce tutoriel, vous apprendrez comment construire des serveurs web en utilisant le module http qui est inclus dans Node.js. Vous allez construire des serveurs web capables de renvoyer des données JSON, des fichiers CSV et des pages web HTML.

      Conditions préalables

      Étape 1 – Création d’un serveur HTTP de base

      Commençons par créer un serveur qui renvoie du texte en clair à l’utilisateur. Cela couvrira les concepts clés nécessaires à la mise en place d’un serveur, qui fournira la base nécessaire pour retourner des formats de données plus complexes comme JSON.

      Tout d’abord, nous devons mettre en place un environnement de codage accessible pour effectuer nos exercices, ainsi que les autres dans l’article. Dans le terminal, créez un dossier appelé first-servers :

      Entrez ensuite dans ce dossier :

      Maintenant, créez le fichier qui abritera le code :

      Ouvrez le fichier dans un éditeur de texte. Nous utiliserons nano puisqu’il est disponible dans le terminal :

      Nous commençons par charger le module http qui est standard avec toutes les installations de Node.js Ajoutez la ligne suivante à hello.js :

      first-servers/hello.js

      const http = require("http");
      

      Le module http contient la fonction de création du serveur, que nous verrons plus tard. Si vous souhaitez en savoir plus sur les modules dans Node.js, consultez notre article Comment créer un module Node.js.

      Notre prochaine étape consistera à définir deux constantes, l’hôte et le port auxquels notre serveur sera lié :

      first-servers/hello.js

      ...
      const host = 'localhost';
      const port = 8000;
      

      Comme mentionné précédemment, les serveurs web acceptent des requêtes des navigateurs et autres clients. Nous pouvons interagir avec un serveur web en entrant un nom de domaine, qui est traduit en une adresse IP par un serveur DNS. Une adresse IP est une séquence unique de chiffres qui identifie une machine sur un réseau, comme l’internet. Pour plus d’informations sur les concepts de noms de domaine, consultez notre article Introduction à la terminologie, aux composants et aux concepts du DNS.

      La valeur localhost est une adresse privée spéciale que les ordinateurs utilisent pour se désigner eux-mêmes.  Elle est généralement l’équivalent de l’adresse IP interne 127.0.0.1 et n’est disponible que pour l’ordinateur local, et non pour les réseaux locaux que nous avons rejoints ou pour l’internet.

      Le port est un numéro que les serveurs utilisent comme point d’accès ou “porte” à notre adresse IP. Dans notre exemple, nous utiliserons le port 8000 pour notre serveur web. Les ports 8080 et 8000 sont généralement utilisés comme ports par défaut dans le développement, et dans la plupart des cas, les développeurs les utiliseront plutôt que d’autres ports pour les serveurs HTTP.

      Lorsque nous lierons notre serveur à cet hôte et à cet port, nous pourrons atteindre notre serveur en visitant http://localhost:8000 dans un navigateur local.

      Ajoutons une fonction spéciale, que nous appelons dans Node.js un request listener. Cette fonction est destinée à traiter une requête HTTP entrante et à renvoyer une réponse HTTP. Cette fonction doit avoir deux arguments, un objet de requête et un objet de réponse. L’objet de requête capture toutes les données de la requête HTTP entrante. L’objet de réponse est utilisé pour renvoyer des réponses HTTP au serveur.

      Nous voulons que notre premier serveur renvoie ce message chaque fois que quelqu’un y accède : "My first server!"​.

      Ajoutons ensuite cette fonction :

      first-servers/hello.js

      ...
      
      const requestListener = function (req, res) {
          res.writeHead(200);
          res.end("My first server!");
      };
      

      La fonction est généralement nommée en fonction de ce qu’elle fait. Par exemple, si nous créons une fonction request listener pour renvoyer une liste de livres, nous la nommerons probablement listBooks(). Comme celui-ci est un exemple, nous utiliserons le nom générique requestListener.

      Toutes les fonctions request listener dans Node.js acceptent deux arguments : req et res (nous pouvons les nommer différemment si nous le voulons). La requête HTTP que l’utilisateur envoie est capturée dans un objet Request, qui correspond au premier argument, req. La réponse HTTP que nous renvoyons à l’utilisateur est formée par l’interaction avec l’objet Response en second argument, res.

      La première ligne res.writeHead(200); définit le code d’état HTTP de la réponse. Les codes d’état HTTP indiquent comment une requête HTTP a été traitée par le serveur. Dans ce cas, le code d’état 200 correspond à "OK". Si vous souhaitez en savoir plus sur les différents codes HTTP que vos serveurs web peuvent renvoyer avec la signification qu’ils revêtent, notre guide Comment dépanner les codes d’erreur HTTP courants est un bon point de départ.

      La ligne suivante de la fonction, res.end("My first server!") ;, renvoie la réponse HTTP au client qui l’a demandée. Cette fonction renvoie toutes les données que le serveur doit renvoyer.  Dans ce cas, elle renvoie des données textuelles.

      Enfin, nous pouvons maintenant créer notre serveur et utiliser notre request listener :

      first-servers/hello.js

      ...
      
      const server = http.createServer(requestListener);
      server.listen(port, host, () => {
          console.log(`Server is running on http://${host}:${port}`);
      });
      

      Enregistrez et quittez nano en appuyant sur CTRL+X.

      À la première ligne, nous créons un nouvel objet server via la fonction createServer() du module http. Ce serveur accepte les requêtes HTTP et les renvoie à notre fonction requestListener().

      Après avoir créé notre serveur, nous devons le lier à une adresse réseau. Nous le faisons avec la méthode server.listen(). Elle accepte trois arguments : le port, host et une fonction de rappel qui se déclenche lorsque le serveur commence à écouter.

      Tous ces arguments sont facultatifs, mais il est bon d’indiquer explicitement quel port et quel hôte nous voulons qu’un serveur web utilise. Lorsque l’on déploie des serveurs web dans différents environnements, il est nécessaire de connaître le port et l’hôte sur lesquels ils fonctionnent pour mettre en place une répartition de charge ou un alias DNS.

      La fonction de rappel enregistre un message sur notre console afin que nous puissions savoir quand le serveur a commencé à écouter les connexions.

      Remarque : même si requestListener() n’utilise pas l’objet req, il doit toujours être le premier argument de la fonction.

      Avec moins de quinze lignes de code, nous avons maintenant un serveur web. Voyons-le en action et testons-le de bout en bout en exécutant le programme :

      Dans la console, nous verrons cette sortie :

      Output

      Server is running on http://localhost:8000

      Notez que l’invite disparaît. C’est dû au fait qu’un serveur Node.js est un processus de longue durée. Il ne se termine que s’il rencontre une erreur qui le fait planter et quitter, ou si nous arrêtons le processus Node.js qui fait tourner le serveur.

      Dans une fenêtre de terminal séparée, nous communiquerons avec le serveur en utilisant cURL, un outil CLI pour transférer des données vers et depuis un réseau. Entrez la commande pour faire une requête HTTP GET à notre serveur en cours d’exécution :

      • curl http://localhost:8000

      Lorsque nous appuyons sur ENTER, notre terminal affichera la sortie suivante :

      Output

      My first server!

      Nous avons maintenant mis en place un serveur et nous avons obtenu notre première réponse du serveur.

      Décomposons ce qui s’est passé lorsque nous avons testé notre serveur. En utilisant cURL, nous avons envoyé une requête GET au serveur sur http://localhost:8000. Notre serveur Node.js a écouté les connexions à partir de cette adresse.  Le serveur a transmis cette requête à la fonction requestListener(). Cette fonction a renvoyé des données textuelles avec le code d’état 200. Le serveur a alors renvoyé cette réponse à cURL, qui a affiché le message dans notre terminal.

      Avant de continuer, quittons notre serveur en cours d’exécution en appuyant sur CTRL+C. Cela interrompt l’exécution de notre serveur, nous renvoyant à l’invite de la ligne de commande.

      Dans la plupart des sites web que nous visit ou API nous utilisons, les réponses du serveur sont rarement en texte en clair. Nous obtenons des pages HTML et des données JSON comme formats de réponse courants. Dans la prochaine étape, nous apprendrons comment renvoyer des réponses HTTP dans les formats de données courants que nous rencontrons sur le web.

      Étape 2 – Renvoi de différents types de contenu

      La réponse que nous recevons d’un serveur web peut prendre plusieurs formats. JSON et HTML ont déjà été mentionnés, et nous pouvons également renvoyer d’autres formats de texte comme XML et CSV. Enfin, les serveurs web peuvent renvoyer des données non textuelles telles que des PDF, des fichiers zippés, des fichiers audio et vidéo.

      Dans cet article, en plus du texte clair que nous venons de renvoyer, vous apprendrez comment renvoyer les types de données suivants :

      Les trois types de données sont tous basés sur le texte et sont des formats populaires pour la diffusion de contenu sur le web. De nombreux outils et langages de développement côté serveur prennent en charge le retour de ces différents types de données. Dans le contexte de Node.js, nous devons faire deux choses :

      1. Définir l’en-tête Content-Type dans nos réponses HTTP avec la valeur appropriée.
      2. Nous assurert que res.end() reçoit les données au bon format.

      Voyons cela en action avec quelques exemples. Le code que nous allons écrire dans cette section et les suivantes présentent de nombreuses similitudes avec le code que nous avons écrit précédemment. La plupart des modifications existent dans la fonction requestListener(). Créons des fichiers avec ce “code modèle” afin de rendre les futures sections plus faciles à suivre.

      Créez un nouveau fichier appelé html.js : Ce fichier sera utilisé plus tard pour renvoyer du texte HTML dans une réponse HTTP. Nous allons mettre le code modèle ici et le copier aux autres serveurs qui renvoient différents types.

      Dans le terminal, entrez ce qui suit :

      Ouvrez maintenant ce fichier dans un éditeur de texte :

      Copions le “code modèle”. Saisissez ceci dans nano :

      first-servers/html.js

      const http = require("http");
      
      const host = 'localhost';
      const port = 8000;
      
      const requestListener = function (req, res) {};
      
      const server = http.createServer(requestListener);
      server.listen(port, host, () => {
          console.log(`Server is running on http://${host}:${port}`);
      });
      

      Enregistrez et quittez html.js avec CTRL+X, puis retournez au terminal.

      Maintenant, copions ce fichier dans deux nouveaux fichiers. Le premier fichier servira à renvoyer les données CSV dans la réponse HTTP :

      Le second fichier retournera une réponse JSON dans le serveur :

      Les autres fichiers seront destinés à des exercices ultérieurs :

      • cp html.js htmlFile.js
      • cp html.js routes.js

      Nous sommes maintenant prêts pour continuer nos exercices. Commençons par retourner JSON.

      Servir JSON

      JavaScript Object Notation, communément appelée JSON, est un format d’échange de données basé sur le texte. Comme son nom l’indique, il est dérivé d’objets JavaScript, mais il est indépendant du langage, ce qui signifie qu’il peut être utilisé par tout langage de programmation capable d’analyser sa syntaxe.

      JSON est couramment utilisé par les API pour accepter et renvoyer des données. Sa popularité est due à une taille de transfert de données inférieure aux normes d’échange de données précédentes comme XML, ainsi qu’à l’outillage existant qui permet aux programmes de les analyser sans effort excessif. Si vous souhaitez en savoir plus sur JSON, vous pouvez lire notre guide Comment travailler avec JSON en JavaScript.

      Ouvrez le fichier json.js avec nano :

      Nous voulons renvoyer une réponse JSON. Modifions la fonction requestListener() pour renvoyer l’en-tête approprié de toutes les réponses JSON en changeant les lignes surlignées comme ceci :

      first-servers/json.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
      };
      ...
      

      La méthode res.setHeader() ajoute un en-tête HTTP à la réponse. Les en-têtes HTTP sont des informations supplémentaires qui peuvent être jointes à une requête ou à une réponse. La méthode res.setHeader() prend deux arguments : le nom de l’en-tête et sa valeur.

      L’en-tête Content-Type est utilisé pour indiquer le format des données, également appelé media type, qui sont envoyées avec la requête ou la réponse.  Dans ce cas, notre Content-Type est application/json.

      Maintenant, retournons le contenu JSON à l’utilisateur. Modifiez json.js pour qu’il ressemble à ceci :

      first-servers/json.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          res.writeHead(200);
          res.end(`{"message": "This is a JSON response"}`);
      };
      ...
      

      Comme précédemment, nous indiquons à l’utilisateur que sa demande a abouti en lui renvoyant un code de statut 200. Cette fois-ci, dans l’appel response.end(), notre argument chaîne de caractères contient un JSON valide.

      Enregistrez et quittez json.js en appuyant sur CTRL+X. Maintenant, lançons le serveur avec la commande node :

      Dans un autre terminal, atteignons le serveur en utilisant cURL :

      • curl http://localhost:8000

      En appuyant sur ENTER, nous obtiendrons le résultat suivant :

      Output

      {"message": "This is a JSON response"}

      Nous avons maintenant renvoyé avec succès une réponse JSON, tout comme beaucoup d’API populaires avec lesquelles nous créons des applications. Veillez à quitter le serveur en cours d’exécution avec CTRL+C afin que nous puissions retourner à l’invite du terminal standard. Ensuite, examinons un autre format populaire de retour de données : CSV.

      Servir CSV

      Le format de fichier CSV (Comma Separated Values) est une norme de texte couramment utilisée pour fournir des données tabulaires. Dans la plupart des cas, chaque ligne est séparée par une nouvelle ligne, et chaque élément de la ligne est séparé par une virgule.

      Dans notre espace de travail, ouvrons le fichier csv.js avec un éditeur de texte :

      Ajoutons les lignes suivantes à notre fonction requestListener() :

      first-servers/csv.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/csv");
          res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
      };
      ...
      

      Cette fois, notre Content-Type indique qu’un fichier CSV est renvoyé car la valeur est text/csv. Le deuxième en-tête que nous ajoutons est Content-Disposition. Cet en-tête indique au navigateur comment afficher les données, en particulier dans le navigateur ou en tant que fichier séparé.

      Lorsque nous renvoyons des réponses CSV, la plupart des navigateurs modernes téléchargent automatiquement le fichier même si l’en-tête Content-Disposition n’est pas défini. Cependant, lorsque nous renvoyons un fichier CSV, nous devons quand même ajouter cet en-tête car il nous permet de définir le nom du fichier CSV. Dans ce cas, nous signalons au navigateur que ce fichier CSV est une pièce jointe et qu’il doit être téléchargé. Nous indiquons ensuite au navigateur que le nom du fichier est oceanpals.csv.

      Écrivons les données CSV dans la réponse HTTP :

      first-servers/csv.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/csv");
          res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
          res.writeHead(200);
          res.end(`id,name,emailn1,Sammy Shark,shark@ocean.com`);
      };
      ...
      

      Comme avant, nous retournons un statut 200/OK avec notre réponse. Cette fois, notre appel à res.end() contient une chaîne de caractères qui est un CSV valide. La virgule sépare la valeur dans chaque colonne et le nouveau caractère de ligne (n) sépare les lignes. Nous avons deux lignes, l’une pour l’en-tête de la table et l’autre pour les données.

      Nous allons tester ce serveur dans le navigateur. Enregistrez csv.js et quittez l’éditeur avec CTRL+X.

      Lancez le serveur avec la commande Node.js :

      Dans un autre Terminal, rejoignons le serveur en utilisant cURL :

      • curl http://localhost:8000

      La console affichera ceci :

      Output

      id,name,email 1,Sammy Shark,shark@ocean.com

      Si nous allons sur http://localhost:8000 dans notre navigateur, un fichier CSV sera téléchargé.  Son nom de fichier sera oceanpals.csv.

      Quittez le serveur en cours d’exécution avec CTRL+C pour revenir à l’invite standard du terminal.

      Après avoir renvoyé JSON et CSV, nous avons couvert deux cas populaires pour les API. Passons maintenant à la manière dont nous renvoyons les données pour les sites web que les gens consultent dans un navigateur.

      Servir HTML

      HTML, HyperText Markup Language, est le format le plus courant à utiliser lorsque nous voulons que des utilisateurs interagissent avec notre serveur via un navigateur web. Il a été créé pour structurer le contenu web. Les navigateurs web sont conçus pour afficher du contenu HTML, ainsi que tous les styles que nous ajoutons avec le CSS, une autre technologie web front-end qui nous permet de modifier l’esthétique de nos sites web.

      Réouvrons html.js avec notre éditeur de texte :

      Modifiez la fonction requestListener() pour renvoyer l’en-tête Content-Type approprié pour une réponse HTML :

      first-servers/html.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
      };
      ...
      

      Maintenant, retournons le contenu HTML à l’utilisateur. Ajoutez les lignes surlignées au fichier html.js pour qu’il ressemble à ceci :

      first-servers/html.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
          res.writeHead(200);
          res.end(`<html><body><h1>This is HTML</h1></body></html>`);
      };
      ...
      

      Nous ajoutons d’abord le code de statut HTTP. Nous appelons ensuite response.end() avec un argument de chaîne contenant du HTML valide. Lorsque nous accédons à notre serveur dans le navigateur, nous verrons une page HTML avec une balise d’en-tête contenant This is HTML.

      Enregistrez et quittez en appuyant sur CTRL+X. Maintenant, lançons le serveur avec la commande node :

      Nous verrons Server is running on http://localhost:8000 lorsque notre programme a démarré.

      Maintenant, allez dans le navigateur et visitez http://localhost:8000. Notre page ressemblera à ceci :

      Image de la réponse HTML renvoyée par le serveur Node.js

      Quittons le serveur en cours d’exécution avec CTRL+C et revenons à l’invite standard du terminal.

      Il est courant que le HTML soit écrit dans un fichier, séparé du code côté serveur comme nos programmes Node.js. Voyons ensuite comment nous pouvons renvoyer des réponses HTML à partir de fichiers.

      Étape 3 – Servir une page HTML à partir d’un fichier

      Nous pouvons servir le HTML comme des chaînes dans Node.js à l’utilisateur, mais il est préférable que nous chargeions les fichiers HTML et que nous servions leur contenu. De cette façon, lorsque le fichier HTML se développe, nous n’avons pas à maintenir de longues chaînes dans notre code Node.js, ce qui le rend plus concis et nous permet de travailler sur chaque aspect de notre site web de manière indépendante. Cette “séparation des préoccupations” est courante dans de nombreuses configurations de développement web, il est donc bon de savoir comment charger les fichiers HTML pour les prendre en charge dans Node.js

      Pour servir les fichiers HTML, nous chargeons le fichier HTML avec le module fs et utilisons ses données lors de l’écriture de notre réponse HTTP.

      Tout d’abord, nous créons un fichier HTML que le serveur web renvoie. Créez un nouveau fichier HTML :

      Maintenant, ouvrez index.html dans un éditeur de texte :

      Notre page web sera minimale. Elle aura un fond orange et affichera un texte de salutation au centre. Ajoutez ce code au fichier :

      first-servers/index.html

      <!DOCTYPE html>
      
      <head>
          <title>My Website</title>
          <style>
              *,
              html {
                  margin: 0;
                  padding: 0;
                  border: 0;
              }
      
              html {
                  width: 100%;
                  height: 100%;
              }
      
              body {
                  width: 100%;
                  height: 100%;
                  position: relative;
                  background-color: rgb(236, 152, 42);
              }
      
              .center {
                  width: 100%;
                  height: 50%;
                  margin: 0;
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  color: white;
                  font-family: "Trebuchet MS", Helvetica, sans-serif;
                  text-align: center;
              }
      
              h1 {
                  font-size: 144px;
              }
      
              p {
                  font-size: 64px;
              }
          </style>
      </head>
      
      <body>
          <div class="center">
              <h1>Hello Again!</h1>
              <p>This is served from a file</p>
          </div>
      </body>
      
      </html>
      

      Cette page web unique affiche deux lignes de texte :Hello again! et This is served from a file. Les lignes apparaissent au centre de la page, l’une au-dessus de l’autre. La première ligne de texte est affichée dans un titre, ce qui signifie qu’elle serait grande. La deuxième ligne de texte apparaîtra un peu plus petite. Tout le texte apparaîtra en blanc et la page web aura un fond orange.

      Bien que ce ne soit pas l’objet de cet article ou de cette série, si vous souhaitez en savoir plus sur le HTML, le CSS et d’autres technologies web frontales, vous pouvez consulter le guide de Mozilla intitulé Premiers pas avec le web.

      C’est tout ce dont nous avons besoin pour le HTML, alors enregistrez et quittez le fichier avec CTRL+X. Nous pouvons maintenant passer au code du serveur.

      Pour cet exercice, nous travaillerons sur htmlFile.js. Ouvrez-le avec l’éditeur de texte :

      Comme nous devons lire un fichier, commençons par importer le module fs :

      first-servers/htmlFile.js

      const http = require("http");
      const fs = require('fs').promises;
      ...
      

      Ce module contient une fonction readFile() que nous utiliserons pour charger le fichier HTML en place. Nous importons la variante promise en respectant les meilleures pratiques modernes de JavaScript. Nous utilisons les promesses en tant que syntaxe plus succincte que les rappels, que nous devrions utiliser si nous assignions fs à juste require('fs'). Pour en savoir plus sur les meilleures pratiques de programmation asynchrone, vous pouvez lire notre guide Comment écrire du code asynchrone dans Node.js.

      Nous voulons que notre fichier HTML soit lu lorsqu’un utilisateur sollicite notre système. Commençons par modifier requestListener() pour lire le fichier :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
      };
      ...
      

      Nous utilisons la méthode fs.readFile() pour charger le fichier. Son argument a __dirname + "/index.html". La variable spéciale __dirname a le chemin absolu de l’emplacement où le code Node.js est en cours d’exécution. Nous ajoutons ensuite /index.html afin de pouvoir charger le fichier HTML que nous avons créé précédemment.

      Maintenant, retournons la page HTML une fois qu’elle est chargée :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
      };
      ...
      

      Si la promesse fs.readFile() se résout avec succès, elle renverra ses données. Nous utilisons la méthode then() pour traiter ce cas. Le paramètre contents contient les données du fichier HTML.

      Nous définissons d’abord l’en-tête Content-Type sur text/html pour indiquer au client que nous renvoyons les données HTML. Nous écrivons ensuite le code d’état pour indiquer que la demande a abouti. Nous envoyons enfin au client la page HTML que nous avons chargée avec les données dans la variable contents.

      La méthode fs.readFile() peut parfois échouer, c’est pourquoi nous devons gérer ce cas lorsque nous obtenons une erreur. Ajoutez ceci à la fonction requestListener() :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
              .catch(err => {
                  res.writeHead(500);
                  res.end(err);
                  return;
              });
      };
      ...
      

      Sauvegardez le fichier et quittez nano avec CTRL+X.

      Lorsqu’une promesse rencontre une erreur, elle est rejetée. Nous traiterons ce cas avec la méthode catch(). Elle accepte l’erreur que fs.readFile() renvoie, met le code de statut à 500 signifiant qu’une erreur interne a été rencontrée, et renvoie l’erreur à l’utilisateur.

      Exécutez notre serveur avec la commande node :

      Dans le navigateur web, visitez http://localhost:8000. Vous verrez cette page :

      Image de la page HTML chargée à partir d'un fichier dans Node.js

      Vous avez maintenant renvoyé une page HTML du serveur à l’utilisateur. Vous pouvez quitter le serveur en cours d’exécution avec CTRL+C. Vous verrez le retour de l’invite du terminal lorsque vous le ferez.

      Lorsque vous écrivez un code de ce type en production, vous ne voudrez peut-être pas charger une page HTML chaque fois que vous recevez une requête HTTP. Alors que cette page HTML a une taille d’environ 800 octets, les sites web plus complexes peuvent avoir une taille de plusieurs mégaoctets. Le chargement de fichiers volumineux peut prendre un certain temps. Si votre site s’attend à un trafic important, il peut être préférable de charger les fichiers HTML au démarrage et de sauvegarder leur contenu. Une fois qu’ils sont chargés, vous pouvez configurer le serveur et lui faire écouter les requêtes sur une adresse.

      Pour démontrer cette méthode, voyons comment nous pouvons retravailler notre serveur pour qu’il soit plus efficace et plus évolutif.

      Servir efficacement le HTML

      Au lieu de charger le HTML pour chaque requête, dans cette étape, nous le chargerons une fois, au début. La requête renverra les données que nous avons chargées au démarrage.

      Dans le terminal, réouvrez le script Node.js avec un éditeur de texte :

      Commençons par ajouter une nouvelle variable avant de créer la fonction requestListener() :

      first-servers/htmlFile.js

      ...
      let indexFile;
      
      const requestListener = function (req, res) {
      ...
      

      Lorsque nous exécutons ce programme, cette variable contiendra le contenu du fichier HTML.

      Maintenant, réajustons la fonction requestListener(). Au lieu de charger le fichier, il va maintenant renvoyer le contenu de indexFile :

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
          res.writeHead(200);
          res.end(indexFile);
      };
      ...
      

      Ensuite, nous déplaçons la logique de lecture du fichier de la fonction requestListener() au démarrage de notre serveur. Effectuez les changements suivants au moment de la création du serveur :

      first-servers/htmlFile.js

      ...
      
      const server = http.createServer(requestListener);
      
      fs.readFile(__dirname + "/index.html")
          .then(contents => {
              indexFile = contents;
              server.listen(port, host, () => {
                  console.log(`Server is running on http://${host}:${port}`);
              });
          })
          .catch(err => {
              console.error(`Could not read index.html file: ${err}`);
              process.exit(1);
          });
      

      Sauvegardez le fichier et quittez nano avec CTRL+X.

      Le code qui lit le fichier est semblable à celui que nous avons écrit lors de notre première tentative. Cependant, lorsque nous réussissons à lire le fichier, nous enregistrons maintenant le contenu dans notre variable globale indexFile. Nous démarrons ensuite le serveur avec la méthode listen() L’essentiel est que le fichier soit chargé avant que le serveur ne soit lancé. De cette façon, la fonction requestListener() sera sûre de renvoyer une page HTML, car indexFile n’est plus une variable vide.

      Notre gestionnaire d’erreurs a également changé. Si le fichier ne peut pas être chargé, nous récupérons l’erreur et l’imprimons sur notre console. Nous quittons ensuite le programme Node.js avec la fonction exit() sans démarrer le serveur. De cette façon, nous pouvons voir pourquoi la lecture du fichier a échoué, résoudre le problème, puis redémarrer le serveur.

      Nous avons maintenant créé différents serveurs web qui renvoient différents types de données à un utilisateur. Jusqu’à présent, nous n’avons utilisé aucune donnée de requête pour déterminer ce qui doit être renvoyé. Nous devrons utiliser des données de requête lors de la configuration de routes ou de chemins différents dans un serveur Node.js, alors voyons maintenant comment ils fonctionnent ensemble.

      Étape 4 – Gestion des routes à l’aide d’un Objet de requête HTTP

      La plupart des sites web que nous visitons ou des API que nous utilisons ont généralement plus d’un point d’accès, ce qui nous permet d’accéder à diverses ressources. Un bon exemple serait un système de gestion des livres, qui pourrait être utilisé dans une bibliothèque. Il ne devrait pas seulement gérer les données relatives aux livres, mais aussi les données relatives aux auteurs pour faciliter le catalogage et la recherche.

      Même si les données concernant les livres et les auteurs sont liées, il s’agit de deux objets différents. Dans ce cas, les développeurs de logiciels codent généralement chaque objet sur des terminaux différents afin d’indiquer à l’utilisateur de l’API le type de données avec lesquelles ils interagissent.

      Créons un nouveau serveur pour une petite bibliothèque, qui renverra deux types de données différents. Si l’utilisateur se rend à l’adresse de notre serveur à /books, il recevra une liste de livres en JSON. S’il se rend à l’adresse /authors, il recevra une liste d’informations sur les auteurs en JSON.

      Jusqu’à présent, nous avons répondu de la même manière à toutes les demandes que nous avons reçues. Illustrons cela rapidement.

      Relancez notre exemple de réponse JSON :

      Dans un autre terminal, faisons une demande CURL comme précédemment :

      • curl http://localhost:8000

      Vous verrez :

      Output

      {"message": "This is a JSON response"}

      Maintenant, essayons une autre commande curl :

      • curl http://localhost:8000/todos

      Après avoir appuyé sur Enter, vous verrez le même résultat :

      Output

      {"message": "This is a JSON response"}

      Nous n’avons pas intégré de logique spéciale dans notre fonction requestListener() pour traiter une requête dont l’URL contient /todos, donc Node.js retourne le même message JSON par défaut.

      Comme nous voulons construire un serveur de gestion de bibliothèque miniature, nous allons maintenant séparer le type de données qui sont retournées en fonction du point final auquel l’utilisateur accède.

      Tout d’abord, quittez le serveur en cours d’exécution avec CTRL+C.

      Maintenant, ouvrez routes.js dans votre éditeur de texte :

      Commençons par stocker nos données JSON dans des variables avant la fonction requestListener() :

      first-servers/routes.js

      ...
      const books = JSON.stringify([
          { title: "The Alchemist", author: "Paulo Coelho", year: 1988 },
          { title: "The Prophet", author: "Kahlil Gibran", year: 1923 }
      ]);
      
      const authors = JSON.stringify([
          { name: "Paulo Coelho", countryOfBirth: "Brazil", yearOfBirth: 1947 },
          { name: "Kahlil Gibran", countryOfBirth: "Lebanon", yearOfBirth: 1883 }
      ]);
      ...
      

      La variable livres est une chaîne qui contient JSON pour un tableau d’objets livres. Chaque livre a un titre ou un nom, un auteur, et l’année de sa publication.

      La variable authors est une chaîne de caractères qui contient le JSON pour un tableau d’objets auteur. Chaque auteur a un nom, un pays de naissance et une année de naissance.

      Maintenant que nous avons les données que nos réponses vont renvoyer, commençons à modifier la fonction requestListener() pour les renvoyer vers les chemins corrects.

      Tout d’abord, nous allons nous assurer que chaque réponse de notre serveur a l’en-tête Content-Type correct :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
      }
      ...
      

      Maintenant, nous voulons renvoyer le bon JSON en fonction du chemin URL utilisé par l’utilisateur. Créons une déclaration switch sur l’URL de la requête :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {}
      }
      ...
      

      Pour obtenir le chemin de l’URL d’un objet de requête, nous devons accéder à la propriété de son url. Nous pouvons maintenant ajouter des cas à la déclaration switch pour renvoyer le JSON approprié.

      L’instruction switch de JavaScript permet de contrôler le code qui est exécuté en fonction de la valeur d’un objet ou d’une expression JavaScript (par exemple, le résultat d’opérations mathématiques). Si vous avez besoin d’une leçon ou d’un rappel sur la manière de les utiliser, consultez notre guide Comment utiliser la déclaration switch en JavaScript.

      Continuons en ajoutant un cas pour lequel l’utilisateur veut obtenir notre liste de livres :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
          }
      }
      ...
      

      Nous fixons notre code de statut à 200 pour indiquer que la demande est correcte et nous renvoyons le JSON contenant la liste de nos livres. Maintenant, ajoutons un autre cas pour nos auteurs :

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
          }
      }
      ...
      

      Comme précédemment, le code de statut sera 200 car la requête est bonne. Cette fois, nous retournons le JSON contenant la liste de nos auteurs.

      Nous voulons renvoyer une erreur si l’utilisateur essaie d’aller par un autre chemin. Ajoutons le cas par défaut pour ce faire :

      routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
              default:
                  res.writeHead(404);
                  res.end(JSON.stringify({error:"Resource not found"}));
          }
      }
      ...
      

      Nous utilisons le mot-clé default dans une déclaration switch pour capturer tous les autres scénarios non capturés par nos cas précédents. Nous fixons le code de statut à 404 pour indiquer que l’URL qu’il recherchait n’a pas été trouvée. Nous définissons ensuite un objet JSON qui contient un message d’erreur.

      Testons notre serveur pour voir s’il se comporte comme nous l’attendons. Dans un autre terminal, lançons d’abord une commande pour voir si nous récupérons notre liste de livres :

      • curl http://localhost:8000/books

      Appuyez sur Enter pour voir la sortie suivante :

      Output

      [{"title":"The Alchemist","author":"Paulo Coelho","year":1988},{"title":"The Prophet","author":"Kahlil Gibran","year":1923}]

      Jusqu’à présent, tout va bien. Essayons la même chose pour /authors. Tapez la commande suivante dans le terminal :

      • curl http://localhost:8000/authors

      Vous verrez la sortie suivante lorsque la commande sera terminée :

      Output

      [{"name":"Paulo Coelho","countryOfBirth":"Brazil","yearOfBirth":1947},{"name":"Kahlil Gibran","countryOfBirth":"Lebanon","yearOfBirth":1883}]

      Enfin, essayons une URL erronée pour nous assurer que requestListener() renvoie la réponse d’erreur :

      • curl http://localhost:8000/notreal

      La saisie de cette commande affichera ce message :

      Output

      {"error":"Resource not found"}

      Vous pouvez quitter le serveur en cours d’exécution avec CTRL+C.

      Nous avons maintenant créé différentes possibilités pour que les utilisateurs puissent obtenir des données différentes. Nous avons également ajouté une réponse par défaut qui renvoie une erreur HTTP si l’utilisateur entre une URL que nous ne prenons pas en charge.

      Conclusion

      Dans ce tutoriel, vous avez réalisé une série de serveurs HTTP Node.js. Vous avez d’abord renvoyé une réponse textuelle de base. Vous avez ensuite demandé de renvoyer différents types de données de notre serveur : JSON, CSV et HTML. À partir de là, vous avez pu combiner le chargement de fichiers avec les réponses HTTP pour renvoyer une page HTML du serveur à l’utilisateur, et créer une API qui utilisait les informations relatives à la requête de l’utilisateur pour déterminer quelles données devaient être envoyées dans sa réponse.

      Vous êtes maintenant équipé pour créer des serveurs web qui peuvent traiter une variété de requêtes et de réponses. Grâce à ces connaissances, vous pouvez créer un serveur qui renvoie de nombreuses pages HTML à l’utilisateur à différents endroits. Vous pouvez également créer votre propre API.

      Pour en savoir plus sur les serveurs web HTTP dans Node.js, vous pouvez lire la documentation de Node.js sur le module http. Si vous souhaitez poursuivre l’apprentissage de Node.js, vous pouvez retourner à la page de la série Comment coder en Node.js.



      Source link

      How To Create a Web Server in Node.js with the HTTP Module


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      When you view a webpage in your browser, you are making a request to another computer on the internet, which then provides you the webpage as a response. That computer you are talking to via the internet is a web server. A web server receives HTTP requests from a client, like your browser, and provides an HTTP response, like an HTML page or JSON from an API.

      A lot of software is involved for a server to return a webpage. This software generally falls into two categories: frontend and backend. Front-end code is concerned with how the content is presented, such as the color of a navigation bar and the text styling. Back-end code is concerned with how data is exchanged, processed, and stored. Code that handles network requests from your browser or communicates with the database is primarily managed by back-end code.

      Node.js allows developers to use JavaScript to write back-end code, even though traditionally it was used in the browser to write front-end code. Having both the frontend and backend together like this reduces the effort it takes to make a web server, which is a major reason why Node.js is a popular choice for writing back-end code.

      In this tutorial, you will learn how to build web servers using the http module that’s included in Node.js. You will build web servers that can return JSON data, CSV files, and HTML web pages.

      Prerequisites

      Step 1 — Creating a Basic HTTP Server

      Let’s start by creating a server that returns plain text to the user. This will cover the key concepts required to set up a server, which will provide the foundation necessary to return more complex data formats like JSON.

      First, we need to set up an accessible coding environment to do our exercises, as well as the others in the article. In the terminal, create a folder called first-servers:

      Then enter that folder:

      Now, create the file that will house the code:

      Open the file in a text editor. We will use nano as it’s available in the terminal:

      We start by loading the http module that’s standard with all Node.js installations. Add the following line to hello.js:

      first-servers/hello.js

      const http = require("http");
      

      The http module contains the function to create the server, which we will see later on. If you would like to learn more about modules in Node.js, check out our How To Create a Node.js Module article.

      Our next step will be to define two constants, the host and port that our server will be bound to:

      first-servers/hello.js

      ...
      const host = 'localhost';
      const port = 8000;
      

      As mentioned before, web servers accept requests from browsers and other clients. We may interact with a web server by entering a domain name, which is translated to an IP address by a DNS server. An IP address is a unique sequence of numbers that identify a machine on a network, like the internet. For more information on domain name concepts, take a look at our An Introduction to DNS Terminology, Components, and Concepts article.

      The value localhost is a special private address that computers use to refer to themselves. It’s typically the equivalent of the internal IP address 127.0.0.1 and it’s only available to the local computer, not to any local networks we’ve joined or to the internet.

      The port is a number that servers use as an endpoint or “door” to our IP address. In our example, we will use port 8000 for our web server. Ports 8080 and 8000 are typically used as default ports in development, and in most cases developers will use them rather than other ports for HTTP servers.

      When we bind our server to this host and port, we will be able to reach our server by visiting http://localhost:8000 in a local browser.

      Let’s add a special function, which in Node.js we call a request listener. This function is meant to handle an incoming HTTP request and return an HTTP response. This function must have two arguments, a request object and a response object. The request object captures all the data of the HTTP request that’s coming in. The response object is used to return HTTP responses for the server.

      We want our first server to return this message whenever someone accesses it: "My first server!".

      Let’s add that function next:

      first-servers/hello.js

      ...
      
      const requestListener = function (req, res) {
          res.writeHead(200);
          res.end("My first server!");
      };
      

      The function would usually be named based on what it does. For example, if we created a request listener function to return a list of books, we would likely name it listBooks(). Since this one is a sample case, we will use the generic name requestListener.

      All request listener functions in Node.js accept two arguments: req and res (we can name them differently if we want). The HTTP request the user sends is captured in a Request object, which corresponds to the first argument, req. The HTTP response that we return to the user is formed by interacting with the Response object in second argument, res.

      The first line res.writeHead(200); sets the HTTP status code of the response. HTTP status codes indicate how well an HTTP request was handled by the server. In this case, the status code 200 corresponds to "OK". If you are interested in learning about the various HTTP codes that your web servers can return with the meaning they signify, our guide on How To Troubleshoot Common HTTP Error Codes is a good place to start.

      The next line of the function, res.end("My first server!");, writes the HTTP response back to the client who requested it. This function returns any data the server has to return. In this case, it’s returning text data.

      Finally, we can now create our server and make use of our request listener:

      first-servers/hello.js

      ...
      
      const server = http.createServer(requestListener);
      server.listen(port, host, () => {
          console.log(`Server is running on http://${host}:${port}`);
      });
      

      Save and exit nano by pressing CTRL+X.

      In the first line, we create a new server object via the http module’s createServer() function. This server accepts HTTP requests and passes them on to our requestListener() function.

      After we create our server, we must bind it to a network address. We do that with the server.listen() method. It accepts three arguments: port, host, and a callback function that fires when the server begins to listen.

      All of these arguments are optional, but it is a good idea to explicitly state which port and host we want a web server to use. When deploying web servers to different environments, knowing the port and host it is running on is required to set up load balancing or a DNS alias.

      The callback function logs a message to our console so we can know when the server began listening to connections.

      Note: Even though requestListener() does not use the req object, it must still be the first argument of the function.

      With less than fifteen lines of code, we now have a web server. Let’s see it in action and test it end-to-end by running the program:

      In the console, we will see this output:

      Output

      Server is running on http://localhost:8000

      Notice that the prompt disappears. This is because a Node.js server is a long running process. It only exits if it encounters an error that causes it to crash and quit, or if we stop the Node.js process running the server.

      In a separate terminal window, we’ll communicate with the server using cURL, a CLI tool to transfer data to and from a network. Enter the command to make an HTTP GET request to our running server:

      • curl http://localhost:8000

      When we press ENTER, our terminal will show the following output:

      Output

      My first server!

      We’ve now set up a server and got our first server response.

      Let’s break down what happened when we tested our server. Using cURL, we sent a GET request to the server at http://localhost:8000. Our Node.js server listened to connections from that address. The server passed that request to the requestListener() function. The function returned text data with the status code 200. The server then sent that response back to cURL, which displayed the message in our terminal.

      Before we continue, let’s exit our running server by pressing CTRL+C. This interrupts our server’s execution, bringing us back to the command line prompt.

      In most web sites we visit or APIs we use, the server responses are seldom in plain text. We get HTML pages and JSON data as common response formats. In the next step, we will learn how to return HTTP responses in common data formats we encounter in the web.

      Step 2 — Returning Different Types of Content

      The response we return from a web server can take a variety of formats. JSON and HTML were mentioned before, and we can also return other text formats like XML and CSV. Finally, web servers can return non-text data like PDFs, zipped files, audio, and video.

      In this article, in addition to the plain text we just returned, you’ll learn how to return the following types of data:

      The three data types are all text-based, and are popular formats for delivering content on the web. Many server-side development languages and tools have support for returning these different data types. In the context of Node.js, we need to do two things:

      1. Set the Content-Type header in our HTTP responses with the appropriate value.
      2. Ensure that res.end() gets the data in the right format.

      Let’s see this in action with some examples. The code we will be writing in this section and later ones have many similarities to the code we wrote previously. Most changes exist within the requestListener() function. Let’s create files with this “template code” to make future sections easier to follow.

      Create a new file called html.js. This file will be used later to return HTML text in an HTTP response. We’ll put the template code here and copy it to the other servers that return various types.

      In the terminal, enter the following:

      Now open this file in a text editor:

      Let’s copy the “template code.” Enter this in nano:

      first-servers/html.js

      const http = require("http");
      
      const host = 'localhost';
      const port = 8000;
      
      const requestListener = function (req, res) {};
      
      const server = http.createServer(requestListener);
      server.listen(port, host, () => {
          console.log(`Server is running on http://${host}:${port}`);
      });
      

      Save and exit html.js with CTRL+X, then return to the terminal.

      Now let’s copy this file into two new files. The first file will be to return CSV data in the HTTP response:

      The second file will return a JSON response in the server:

      The remaining files will be for later exercises:

      • cp html.js htmlFile.js
      • cp html.js routes.js

      We’re now set up to continue our exercises. Let’s begin with returning JSON.

      Serving JSON

      JavaScript Object Notation, commonly referred to as JSON, is a text-based data exchange format. As its name suggests, it is derived from JavaScript objects, but it is language independent, meaning it can be used by any programming language that can parse its syntax.

      JSON is commonly used by APIs to accept and return data. Its popularity is due to lower data transfer size than previous data exchange standards like XML, as well as the tooling that exists that allow programs to parse them without excessive effort. If you’d like to learn more about JSON, you can read our guide on How To Work with JSON in JavaScript.

      Open the json.js file with nano:

      We want to return a JSON response. Let’s modify the requestListener() function to return the appropriate header all JSON responses have by changing the highlighted lines like so:

      first-servers/json.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
      };
      ...
      

      The res.setHeader() method adds an HTTP header to the response. HTTP headers are additional information that can be attached to a request or a response. The res.setHeader() method takes two arguments: the header’s name and its value.

      The Content-Type header is used to indicate the format of the data, also known as media type, that’s being sent with the request or response. In this case our Content-Type is application/json.

      Now, let’s return JSON content to the user. Modify json.js so it looks like this:

      first-servers/json.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          res.writeHead(200);
          res.end(`{"message": "This is a JSON response"}`);
      };
      ...
      

      Like before, we tell the user that their request was successful by returning a status code of 200. This time in the response.end() call, our string argument contains valid JSON.

      Save and exit json.js by pressing CTRL+X. Now, let’s run the server with the node command:

      In another terminal, let’s reach the server by using cURL:

      • curl http://localhost:8000

      As we press ENTER, we will see the following result:

      Output

      {"message": "This is a JSON response"}

      We now have successfully returned a JSON response, just like many of the popular APIs we create apps with. Be sure to exit the running server with CTRL+C so we can return to the standard terminal prompt. Next, let’s look at another popular format of returning data: CSV.

      Serving CSV

      The Comma Separated Values (CSV) file format is a text standard that’s commonly used for providing tabular data. In most cases, each row is separated by a newline, and each item in the row is separated by a comma.

      In our workspace, open the csv.js file with a text editor:

      Let’s add the following lines to our requestListener() function:

      first-servers/csv.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/csv");
          res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
      };
      ...
      

      This time, our Content-Type indicates that a CSV file is being returned as the value is text/csv. The second header we add is Content-Disposition. This header tells the browser how to display the data, particularly in the browser or as a separate file.

      When we return CSV responses, most modern browsers automatically download the file even if the Content-Disposition header is not set. However, when returning a CSV file we should still add this header as it allows us to set the name of the CSV file. In this case, we signal to the browser that this CSV file is an attachment and should be downloaded. We then tell the browser that the file’s name is oceanpals.csv.

      Let’s write the CSV data in the HTTP response:

      first-servers/csv.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/csv");
          res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
          res.writeHead(200);
          res.end(`id,name,emailn1,Sammy Shark,shark@ocean.com`);
      };
      ...
      

      Like before we return a 200/OK status with our response. This time, our call to res.end() has a string that’s a valid CSV. The comma separates the value in each column and the new line character (n) separates the rows. We have two rows, one for the table header and one for the data.

      We’ll test this server in the browser. Save csv.js and exit the editor with CTRL+X.

      Run the server with the Node.js command:

      In another Terminal, let’s reach the server by using cURL:

      • curl http://localhost:8000

      The console will show this:

      Output

      id,name,email 1,Sammy Shark,shark@ocean.com

      If we go to http://localhost:8000 in our browser, a CSV file will be downloaded. Its file name will be oceanpals.csv.

      Exit the running server with CTRL+C to return to the standard terminal prompt.

      Having returned JSON and CSV, we’ve covered two cases that are popular for APIs. Let’s move on to how we return data for websites people view in a browser.

      Serving HTML

      HTML, HyperText Markup Language, is the most common format to use when we want users to interact with our server via a web browser. It was created to structure web content. Web browsers are built to display HTML content, as well as any styles we add with CSS, another front-end web technology that allows us to change the aesthetics of our websites.

      Let’s reopen html.js with our text editor:

      Modify the requestListener() function to return the appropriate Content-Type header for an HTML response:

      first-servers/html.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
      };
      ...
      

      Now, let’s return HTML content to the user. Add the highlighted lines to html.js so it looks like this:

      first-servers/html.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
          res.writeHead(200);
          res.end(`<html><body><h1>This is HTML</h1></body></html>`);
      };
      ...
      

      We first add the HTTP status code. We then call response.end() with a string argument that contains valid HTML. When we access our server in the browser, we will see an HTML page with one header tag containing This is HTML.

      Let’s save and exit by pressing CTRL+X. Now, let’s run the server with the node command:

      We will see Server is running on http://localhost:8000 when our program has started.

      Now go into the browser and visit http://localhost:8000. Our page will look like this:

      Image of HTML response returned from Node.js server

      Let’s quit the running server with CTRL+C and return to the standard terminal prompt.

      It’s common for HTML to be written in a file, separate from the server-side code like our Node.js programs. Next, let’s see how we can return HTML responses from files.

      Step 3 — Serving an HTML Page From a File

      We can serve HTML as strings in Node.js to the user, but it’s preferable that we load HTML files and serve their content. This way, as the HTML file grows we don’t have to maintain long strings in our Node.js code, keeping it more concise and allowing us to work on each aspect of our website independently. This “separation of concerns” is common in many web development setups, so it’s good to know how to load HTML files to support it in Node.js

      To serve HTML files, we load the HTML file with the fs module and use its data when writing our HTTP response.

      First, we’ll create an HTML file that the web server will return. Create a new HTML file:

      Now open index.html in a text editor:

      Our web page will be minimal. It will have an orange background and will display some greeting text in the center. Add this code to the file:

      first-servers/index.html

      <!DOCTYPE html>
      
      <head>
          <title>My Website</title>
          <style>
              *,
              html {
                  margin: 0;
                  padding: 0;
                  border: 0;
              }
      
              html {
                  width: 100%;
                  height: 100%;
              }
      
              body {
                  width: 100%;
                  height: 100%;
                  position: relative;
                  background-color: rgb(236, 152, 42);
              }
      
              .center {
                  width: 100%;
                  height: 50%;
                  margin: 0;
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  color: white;
                  font-family: "Trebuchet MS", Helvetica, sans-serif;
                  text-align: center;
              }
      
              h1 {
                  font-size: 144px;
              }
      
              p {
                  font-size: 64px;
              }
          </style>
      </head>
      
      <body>
          <div class="center">
              <h1>Hello Again!</h1>
              <p>This is served from a file</p>
          </div>
      </body>
      
      </html>
      

      This single webpage shows two lines of text: Hello Again! and This is served from a file. The lines appear in the center of the page, one above each other. The first line of text is displayed in a heading, meaning it would be large. The second line of text will appear slightly smaller. All the text will appear white and the webpage has an orange background.

      While it’s not the scope of this article or series, if you are interested in learning more about HTML, CSS, and other front-end web technologies, you can take a look at Mozilla’s Getting Started with the Web guide.

      That’s all we need for the HTML, so save and exit the file with CTRL+X. We can now move on to the server code.

      For this exercise, we’ll work on htmlFile.js. Open it with the text editor:

      As we have to read a file, let’s begin by importing the fs module:

      first-servers/htmlFile.js

      const http = require("http");
      const fs = require('fs').promises;
      ...
      

      This module contains a readFile() function that we’ll use to load the HTML file in place. We import the promise variant in keeping with modern JavaScript best practices. We use promises as its syntactically more succinct than callbacks, which we would have to use if we assigned fs to just require('fs'). To learn more about asynchronous programming best practices, you can read our How To Write Asynchronous Code in Node.js guide.

      We want our HTML file to be read when a user requests our system. Let’s begin by modifying requestListener() to read the file:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
      };
      ...
      

      We use the fs.readFile() method to load the file. Its argument has __dirname + "/index.html". The special variable __dirname has the absolute path of where the Node.js code is being run. We then append /index.html so we can load the HTML file we created earlier.

      Now let’s return the HTML page once it’s loaded:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
      };
      ...
      

      If the fs.readFile() promise successfully resolves, it will return its data. We use the then() method to handle this case. The contents parameter contains the HTML file’s data.

      We first set the Content-Type header to text/html to tell the client that we are returning HTML data. We then write the status code to indicate the request was successful. We finally send the client the HTML page we loaded, with the data in the contents variable.

      The fs.readFile() method can fail at times, so we should handle this case when we get an error. Add this to the requestListener() function:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          fs.readFile(__dirname + "/index.html")
              .then(contents => {
                  res.setHeader("Content-Type", "text/html");
                  res.writeHead(200);
                  res.end(contents);
              })
              .catch(err => {
                  res.writeHead(500);
                  res.end(err);
                  return;
              });
      };
      ...
      

      Save the file and exit nano with CTRL+X.

      When a promise encounters an error, it is rejected. We handle that case with the catch() method. It accepts the error that fs.readFile() returns, sets the status code to 500 signifying that an internal error was encountered, and returns the error to the user.

      Run our server with the node command:

      In the web browser, visit http://localhost:8000. You will see this page:

      Image of HTML page loaded from a file in Node.js

      You have now returned an HTML page from the server to the user. You can quit the running server with CTRL+C. You will see the terminal prompt return when you do.

      When writing code like this in production, you may not want to load an HTML page every time you get an HTTP request. While this HTML page is roughly 800 bytes in size, more complex websites can be megabytes in size. Large files can take a while to load. If your site is expecting a lot of traffic, it may be best to load HTML files at startup and save their contents. After they are loaded, you can set up the server and make it listen to requests on an address.

      To demonstrate this method, let’s see how we can rework our server to be more efficient and scalable.

      Serving HTML Efficiently

      Instead of loading the HTML for every request, in this step we will load it once at the beginning. The request will return the data we loaded at startup.

      In the terminal, re-open the Node.js script with a text editor:

      Let’s begin by adding a new variable before we create the requestListener() function:

      first-servers/htmlFile.js

      ...
      let indexFile;
      
      const requestListener = function (req, res) {
      ...
      

      When we run this program, this variable will hold the HTML file’s contents.

      Now, let’s readjust the requestListener() function. Instead of loading the file, it will now return the contents of indexFile:

      first-servers/htmlFile.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "text/html");
          res.writeHead(200);
          res.end(indexFile);
      };
      ...
      

      Next, we shift the file reading logic from the requestListener() function to our server startup. Make the following changes as we create the server:

      first-servers/htmlFile.js

      ...
      
      const server = http.createServer(requestListener);
      
      fs.readFile(__dirname + "/index.html")
          .then(contents => {
              indexFile = contents;
              server.listen(port, host, () => {
                  console.log(`Server is running on http://${host}:${port}`);
              });
          })
          .catch(err => {
              console.error(`Could not read index.html file: ${err}`);
              process.exit(1);
          });
      

      Save the file and exit nano with CTRL+X.

      The code that reads the file is similar to what we wrote in our first attempt. However, when we successfully read the file we now save the contents to our global indexFile variable. We then start the server with the listen() method. The key thing is that the file is loaded before the server is run. This way, the requestListener() function will be sure to return an HTML page, as indexFile is no longer an empty variable.

      Our error handler has changed as well. If the file can’t be loaded, we capture the error and print it to our console. We then exit the Node.js program with the exit() function without starting the server. This way we can see why the file reading failed, address the problem, and then start the server again.

      We’ve now created different web servers that return various types of data to a user. So far, we have not used any request data to determine what should be returned. We’ll need to use request data when setting up different routes or paths in a Node.js server, so next let’s see how they work together.

      Step 4 — Managing Routes Using an HTTP Request Object

      Most websites we visit or APIs we use usually have more than one endpoint so we can access various resources. A good example would be a book management system, one that might be used in a library. It would not only need to manage book data, but it would also manage author data for cataloguing and searching convenience.

      Even though the data for books and authors are related, they are two different objects. In these cases, software developers usually code each object on different endpoints as a way to indicate to the API user what kind of data they are interacting with.

      Let’s create a new server for a small library, which will return two different types of data. If the user goes to our server’s address at /books, they will receive a list of books in JSON. If they go to /authors, they will receive a list of author information in JSON.

      So far, we have been returning the same response to every request we get. Let’s illustrate this quickly.

      Re-run our JSON response example:

      In another terminal, let’s do a cURL request like before:

      • curl http://localhost:8000

      You will see:

      Output

      {"message": "This is a JSON response"}

      Now let’s try another curl command:

      • curl http://localhost:8000/todos

      After pressing Enter, you will see the same result:

      Output

      {"message": "This is a JSON response"}

      We have not built any special logic in our requestListener() function to handle a request whose URL contains /todos, so Node.js returns the same JSON message by default.

      As we want to build a miniature library management server, we’ll now separate the kind of data that’s returned based on the endpoint the user accesses.

      First, exit the running server with CTRL+C.

      Now open routes.js in your text editor:

      Let’s begin by storing our JSON data in variables before the requestListener() function:

      first-servers/routes.js

      ...
      const books = JSON.stringify([
          { title: "The Alchemist", author: "Paulo Coelho", year: 1988 },
          { title: "The Prophet", author: "Kahlil Gibran", year: 1923 }
      ]);
      
      const authors = JSON.stringify([
          { name: "Paulo Coelho", countryOfBirth: "Brazil", yearOfBirth: 1947 },
          { name: "Kahlil Gibran", countryOfBirth: "Lebanon", yearOfBirth: 1883 }
      ]);
      ...
      

      The books variable is a string that contains JSON for an array of book objects. Each book has a title or name, an author, and the year it was published.

      The authors variable is a string that contains the JSON for an array of author objects. Each author has a name, a country of birth, and their year of birth.

      Now that we have the data our responses will return, let’s start modifying the requestListener() function to return them to the correct routes.

      First, we’ll ensure that every response from our server has the correct Content-Type header:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
      }
      ...
      

      Now, we want to return the right JSON depending on the URL path the user visits. Let’s create a switch statement on the request’s URL:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {}
      }
      ...
      

      To get the URL path from a request object, we need to access its url property. We can now add cases to the switch statement to return the appropriate JSON.

      JavaScript’s switch statement provides a way to control what code is run depending on the value of an object or JavaScript expression (for example, the result of mathematical operations). If you need a lesson or reminder on how to use them, take a look at our guide on How To Use the Switch Statement in JavaScript.

      Let’s continue by adding a case for when the user wants to get our list of books:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
          }
      }
      ...
      

      We set our status code to 200 to indicate the request is fine and return the JSON containing the list of our books. Now let’s add another case for our authors:

      first-servers/routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
          }
      }
      ...
      

      Like before, the status code will be 200 as the request is fine. This time we return the JSON containing the list of our authors.

      We want to return an error if the user tries to go to any other path. Let’s add the default case to do this:

      routes.js

      ...
      const requestListener = function (req, res) {
          res.setHeader("Content-Type", "application/json");
          switch (req.url) {
              case "/books":
                  res.writeHead(200);
                  res.end(books);
                  break
              case "/authors":
                  res.writeHead(200);
                  res.end(authors);
                  break
              default:
                  res.writeHead(404);
                  res.end(JSON.stringify({error:"Resource not found"}));
          }
      }
      ...
      

      We use the default keyword in a switch statement to capture all other scenarios not captured by our previous cases. We set the status code to 404 to indicate that the URL they were looking for was not found. We then set a JSON object that contains an error message.

      Let’s test our server to see if it behaves as we expect. In another terminal, let’s first run a command to see if we get back our list of books:

      • curl http://localhost:8000/books

      Press Enter to see the following output:

      Output

      [{"title":"The Alchemist","author":"Paulo Coelho","year":1988},{"title":"The Prophet","author":"Kahlil Gibran","year":1923}]

      So far so good. Let’s try the same for /authors. Type the following command in the terminal:

      • curl http://localhost:8000/authors

      You will see the following output when the command is complete:

      Output

      [{"name":"Paulo Coelho","countryOfBirth":"Brazil","yearOfBirth":1947},{"name":"Kahlil Gibran","countryOfBirth":"Lebanon","yearOfBirth":1883}]

      Last, let’s try an erroneous URL to ensure that requestListener() returns the error response:

      • curl http://localhost:8000/notreal

      Entering that command will display this message:

      Output

      {"error":"Resource not found"}

      You can exit the running server with CTRL+C.

      We’ve now created different avenues for users to get different data. We also added a default response that returns an HTTP error if the user enters a URL that we don’t support.

      Conclusion

      In this tutorial, you’ve made a series of Node.js HTTP servers. You first returned a basic textual response. You then went on to return various types of data from our server: JSON, CSV, and HTML. From there you were able to combine file loading with HTTP responses to return an HTML page from the server to the user, and to create an API that used information about the user’s request to determine what data should be sent in its response.

      You’re now equipped to create web servers that can handle a variety of requests and responses. With this knowledge, you can make a server that returns many HTML pages to the user at different endpoints. You could also create your own API.

      To learn about more HTTP web servers in Node.js, you can read the Node.js documentation on the http module. If you’d like to continue learning Node.js, you can return to the How To Code in Node.js series page.



      Source link