[{"data":1,"prerenderedAt":3453},["ShallowReactive",2],{"article-fr-\u002Fdevops\u002Fdeploy-expressjs-api-using-docker":3,"article-sibling-fr-\u002Fdevops\u002Fdeploy-expressjs-api-using-docker":1907,"surround-fr-\u002Fdevops\u002Fdeploy-expressjs-api-using-docker":3419,"related-fr-\u002Fdevops\u002Fdeploy-expressjs-api-using-docker":3426},{"id":4,"title":5,"body":6,"date":1888,"description":1889,"extension":1890,"img":1891,"meta":1892,"navigation":157,"path":1893,"seo":1894,"slug":1895,"stem":1896,"tags":1897,"topics":1903,"__hash__":1906},"content\u002Fdevops\u002F1.deploy-expressjs-api-using-docker.fr.md","Déployer une API Express.js avec Docker",{"type":7,"value":8,"toc":1866},"minimark",[9,14,18,28,32,40,44,50,54,62,67,90,94,601,604,624,628,634,638,649,653,656,676,682,686,790,793,897,901,904,924,932,935,1310,1314,1320,1323,1326,1329,1333,1342,1470,1487,1490,1494,1500,1504,1840,1852,1856,1859,1862],[10,11,13],"h2",{"id":12},"introduction","Introduction",[15,16,17],"p",{},"Dans le paysage technologique d'aujourd'hui, livrer des applications rapidement et de manière\nfiable est critique. Docker, avec sa technologie de conteneurisation, propose un moyen simple de\ndéployer des applications Node.js. Cet article discute du déploiement d'une API Express.js avec\nMongoDB, en se concentrant sur les bonnes pratiques des conteneurs Docker et les méthodologies\nde test. On passe sur les bases de la construction d'une application Express.js et de la\nconnexion à MongoDB. On se concentre plutôt sur l'utilisation des capacités de Docker, le suivi\ndes bonnes pratiques MongoDB, la création de tests robustes avec Jest, et l'utilisation de Nginx\nen tant que reverse proxy.",[15,19,20,21,27],{},"L'ensemble du code, ",[22,23,26],"a",{"href":24,"target":25},"https:\u002F\u002Fgithub.com\u002Fdenisakp\u002Fexpressjs-mongo-docker","_blank","dépôt sur GitHub",",\nsert d'illustration pratique des concepts et pratiques couverts dans ce guide.",[10,29,31],{"id":30},"expressjs","Express.js",[15,33,34,35,39],{},"Express.js est un framework Node.js populaire qui accélère et facilite le développement\nd'applications web et d'APIs. Il fournit un ensemble puissant de fonctionnalités qui\nsimplifient le process de création de serveur, permettant aux développeurs de mettre en place\ndes routes complexes, des middlewares et des fonctionnalités côté serveur avec moins de code.\nGrâce à sa large popularité, Express.js est soutenu par une grosse communauté qui propose un\nensemble de middlewares étendant ses capacités, ce qui en fait un choix populaire pour\nconstruire des applications web performantes. Si Express.js ne t'es pas familier, consulte\nla ",[22,36,38],{"href":37,"target":25},"https:\u002F\u002Fexpressjs.com\u002F","documentation",".",[10,41,43],{"id":42},"mongodb","MongoDB",[15,45,46,47,39],{},"MongoDB est une base NoSQL conçue pour un développement et une mise à l'échelle simples. Elle\nest connue comme une base de données orientée document et stocke les données dans des documents\nflexibles type JSON, ce qui signifie que les champs peuvent différer d'un document à l'autre et\nque les structures de données peuvent évoluer dans le temps. Cette architecture permet de\ndéfinir facilement des relations hiérarchiques, de stocker des tableaux et de créer d'autres\nstructures plus complexes. MongoDB est connue pour son agilité, sa haute disponibilité et son\norientation sécurité, ce qui en fait un choix populaire pour les applications web modernes qui\nexigent un accès rapide à de grandes quantités de données. Si tu débutes avec MongoDB, consulte\nla ",[22,48,38],{"href":49,"target":25},"https:\u002F\u002Fwww.mongodb.com\u002Fdocs\u002F",[10,51,53],{"id":52},"pattern-singleton","Pattern Singleton",[15,55,56,57,61],{},"Le pattern Singleton est un design pattern logiciel qui garantit qu'une classe n'a qu'une seule\ninstance tout en fournissant un point d'accès global à celle-ci. Selon\n",[22,58,60],{"href":59,"target":25},"https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fsingleton","Refactoring Guru",",\nle pattern Singleton est fréquemment utilisé pour gérer les connexions à la base de données\npuisqu'il permet d'instancier une classe une seule fois. C'est particulièrement bénéfique\nquand une ressource partagée unique, comme une connexion DB, est nécessaire pour réaliser des\nopérations à travers plusieurs composants d'une application. En utilisant le pattern Singleton,\non évite de créer par erreur plusieurs instances d'une classe, ce qui économise des ressources\net garantit un comportement cohérent dans tout le programme.",[63,64,66],"h3",{"id":65},"bénéfices-du-singleton-pour-le-client-mongodb","Bénéfices du Singleton pour le client MongoDB",[68,69,70,78,84],"ul",{},[71,72,73,77],"li",{},[74,75,76],"strong",{},"Connexion cohérente"," : maintenir une seule connexion MongoDB évite le surcoût d'ouvrir et\nfermer plusieurs connexions, ce qui améliore les performances.",[71,79,80,83],{},[74,81,82],{},"Optimisation des ressources"," : le Singleton garantit un usage optimal des ressources, en\nprévenant les pièges des connexions redondantes.",[71,85,86,89],{},[74,87,88],{},"Éviter les fuites de connexion"," : tu peux éviter les fuites de connexion potentielles\ncausées par des composants distincts d'une application qui géreraient mal des instances de\nconnexion individuelles. Une fuite de connexion peut épuiser les ressources du serveur de\nbase de données, et entraîner une dégradation des performances.",[63,91,93],{"id":92},"implémenter-le-pattern-singleton-pour-le-client-mongodb","Implémenter le pattern Singleton pour le client MongoDB",[95,96,102],"pre",{"className":97,"code":98,"filename":99,"language":100,"meta":101,"style":101},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F this snippet is based on official mongodb npm module, not mongoosejs module. \nclass MyDatabase {\n  static client;\n  static db;\n\n  \u002F**\n   * @static\n   * @return {Promise\u003CMongoClient>}\n   *\u002F\n  static async connect() {\n    if (!this.client) {\n      try {\n        this.client = new MongoClient(\"mongodb:\u002F\u002Flocalhost:27017\u002F\", { serverApi: ServerApiVersion.v1 });\n        await this.client.connect();\n        console.info('connected to database'); \u002F\u002F we may use proper logging system instead of console.log\n      } catch (error) {\n        console.error(\"failed to connect to MongoDB: \", error.message);\n        throw error\n      }\n    }\n    return this.client;\n  }\n\n  \u002F**\n   * Retrieves the MongoDB database instance.\n   * @static\n   * @returns {Promise\u003CDb>}\n   *\u002F\n  static async getDB() {\n    if (!this.db) {\n      const client = await this.connect();\n      this.db = client.db(\"express\"); \u002F\u002F express is our database name\n    }\n    return this.db\n  }\n}\n","database.config.mjs","js","",[103,104,105,114,129,142,152,159,165,179,199,205,221,243,251,308,328,357,375,407,416,422,428,440,446,451,456,462,471,488,493,507,523,544,576,581,591,596],"code",{"__ignoreMap":101},[106,107,110],"span",{"class":108,"line":109},"line",1,[106,111,113],{"class":112},"sHwdD","\u002F\u002F this snippet is based on official mongodb npm module, not mongoosejs module. \n",[106,115,117,121,125],{"class":108,"line":116},2,[106,118,120],{"class":119},"spNyl","class",[106,122,124],{"class":123},"sBMFI"," MyDatabase",[106,126,128],{"class":127},"sMK4o"," {\n",[106,130,132,135,139],{"class":108,"line":131},3,[106,133,134],{"class":119},"  static",[106,136,138],{"class":137},"swJcz"," client",[106,140,141],{"class":127},";\n",[106,143,145,147,150],{"class":108,"line":144},4,[106,146,134],{"class":119},[106,148,149],{"class":137}," db",[106,151,141],{"class":127},[106,153,155],{"class":108,"line":154},5,[106,156,158],{"emptyLinePlaceholder":157},true,"\n",[106,160,162],{"class":108,"line":161},6,[106,163,164],{"class":112},"  \u002F**\n",[106,166,168,171,175],{"class":108,"line":167},7,[106,169,170],{"class":112},"   * ",[106,172,174],{"class":173},"s7zQu","@",[106,176,178],{"class":177},"s6hCs","static\n",[106,180,182,184,186,189,192,196],{"class":108,"line":181},8,[106,183,170],{"class":112},[106,185,174],{"class":173},[106,187,188],{"class":177},"return",[106,190,191],{"class":173}," {",[106,193,195],{"class":194},"sFweD","Promise\u003CMongoClient>",[106,197,198],{"class":173},"}\n",[106,200,202],{"class":108,"line":201},9,[106,203,204],{"class":112},"   *\u002F\n",[106,206,208,210,213,216,219],{"class":108,"line":207},10,[106,209,134],{"class":119},[106,211,212],{"class":119}," async",[106,214,215],{"class":137}," connect",[106,217,218],{"class":127},"()",[106,220,128],{"class":127},[106,222,224,227,230,233,237,240],{"class":108,"line":223},11,[106,225,226],{"class":173},"    if",[106,228,229],{"class":137}," (",[106,231,232],{"class":127},"!this.",[106,234,236],{"class":235},"sTEyZ","client",[106,238,239],{"class":137},") ",[106,241,242],{"class":127},"{\n",[106,244,246,249],{"class":108,"line":245},12,[106,247,248],{"class":173},"      try",[106,250,128],{"class":127},[106,252,254,257,259,262,265,269,272,275,279,281,284,286,289,292,295,297,300,303,306],{"class":108,"line":253},13,[106,255,256],{"class":127},"        this.",[106,258,236],{"class":235},[106,260,261],{"class":127}," =",[106,263,264],{"class":127}," new",[106,266,268],{"class":267},"s2Zo4"," MongoClient",[106,270,271],{"class":137},"(",[106,273,274],{"class":127},"\"",[106,276,278],{"class":277},"sfazB","mongodb:\u002F\u002Flocalhost:27017\u002F",[106,280,274],{"class":127},[106,282,283],{"class":127},",",[106,285,191],{"class":127},[106,287,288],{"class":137}," serverApi",[106,290,291],{"class":127},":",[106,293,294],{"class":235}," ServerApiVersion",[106,296,39],{"class":127},[106,298,299],{"class":235},"v1",[106,301,302],{"class":127}," }",[106,304,305],{"class":137},")",[106,307,141],{"class":127},[106,309,311,314,317,319,321,324,326],{"class":108,"line":310},14,[106,312,313],{"class":173},"        await",[106,315,316],{"class":127}," this.",[106,318,236],{"class":235},[106,320,39],{"class":127},[106,322,323],{"class":267},"connect",[106,325,218],{"class":137},[106,327,141],{"class":127},[106,329,331,334,336,339,341,344,347,349,351,354],{"class":108,"line":330},15,[106,332,333],{"class":235},"        console",[106,335,39],{"class":127},[106,337,338],{"class":267},"info",[106,340,271],{"class":137},[106,342,343],{"class":127},"'",[106,345,346],{"class":277},"connected to database",[106,348,343],{"class":127},[106,350,305],{"class":137},[106,352,353],{"class":127},";",[106,355,356],{"class":112}," \u002F\u002F we may use proper logging system instead of console.log\n",[106,358,360,363,366,368,371,373],{"class":108,"line":359},16,[106,361,362],{"class":127},"      }",[106,364,365],{"class":173}," catch",[106,367,229],{"class":137},[106,369,370],{"class":235},"error",[106,372,239],{"class":137},[106,374,242],{"class":127},[106,376,378,380,382,384,386,388,391,393,395,398,400,403,405],{"class":108,"line":377},17,[106,379,333],{"class":235},[106,381,39],{"class":127},[106,383,370],{"class":267},[106,385,271],{"class":137},[106,387,274],{"class":127},[106,389,390],{"class":277},"failed to connect to MongoDB: ",[106,392,274],{"class":127},[106,394,283],{"class":127},[106,396,397],{"class":235}," error",[106,399,39],{"class":127},[106,401,402],{"class":235},"message",[106,404,305],{"class":137},[106,406,141],{"class":127},[106,408,410,413],{"class":108,"line":409},18,[106,411,412],{"class":173},"        throw",[106,414,415],{"class":235}," error\n",[106,417,419],{"class":108,"line":418},19,[106,420,421],{"class":127},"      }\n",[106,423,425],{"class":108,"line":424},20,[106,426,427],{"class":127},"    }\n",[106,429,431,434,436,438],{"class":108,"line":430},21,[106,432,433],{"class":173},"    return",[106,435,316],{"class":127},[106,437,236],{"class":235},[106,439,141],{"class":127},[106,441,443],{"class":108,"line":442},22,[106,444,445],{"class":127},"  }\n",[106,447,449],{"class":108,"line":448},23,[106,450,158],{"emptyLinePlaceholder":157},[106,452,454],{"class":108,"line":453},24,[106,455,164],{"class":112},[106,457,459],{"class":108,"line":458},25,[106,460,461],{"class":112},"   * Retrieves the MongoDB database instance.\n",[106,463,465,467,469],{"class":108,"line":464},26,[106,466,170],{"class":112},[106,468,174],{"class":173},[106,470,178],{"class":177},[106,472,474,476,478,481,483,486],{"class":108,"line":473},27,[106,475,170],{"class":112},[106,477,174],{"class":173},[106,479,480],{"class":177},"returns",[106,482,191],{"class":173},[106,484,485],{"class":194},"Promise\u003CDb>",[106,487,198],{"class":173},[106,489,491],{"class":108,"line":490},28,[106,492,204],{"class":112},[106,494,496,498,500,503,505],{"class":108,"line":495},29,[106,497,134],{"class":119},[106,499,212],{"class":119},[106,501,502],{"class":137}," getDB",[106,504,218],{"class":127},[106,506,128],{"class":127},[106,508,510,512,514,516,519,521],{"class":108,"line":509},30,[106,511,226],{"class":173},[106,513,229],{"class":137},[106,515,232],{"class":127},[106,517,518],{"class":235},"db",[106,520,239],{"class":137},[106,522,242],{"class":127},[106,524,526,529,531,533,536,538,540,542],{"class":108,"line":525},31,[106,527,528],{"class":119},"      const",[106,530,138],{"class":235},[106,532,261],{"class":127},[106,534,535],{"class":173}," await",[106,537,316],{"class":127},[106,539,323],{"class":267},[106,541,218],{"class":137},[106,543,141],{"class":127},[106,545,547,550,552,554,556,558,560,562,564,567,569,571,573],{"class":108,"line":546},32,[106,548,549],{"class":127},"      this.",[106,551,518],{"class":235},[106,553,261],{"class":127},[106,555,138],{"class":235},[106,557,39],{"class":127},[106,559,518],{"class":267},[106,561,271],{"class":137},[106,563,274],{"class":127},[106,565,566],{"class":277},"express",[106,568,274],{"class":127},[106,570,305],{"class":137},[106,572,353],{"class":127},[106,574,575],{"class":112}," \u002F\u002F express is our database name\n",[106,577,579],{"class":108,"line":578},33,[106,580,427],{"class":127},[106,582,584,586,588],{"class":108,"line":583},34,[106,585,433],{"class":173},[106,587,316],{"class":127},[106,589,590],{"class":235},"db\n",[106,592,594],{"class":108,"line":593},35,[106,595,445],{"class":127},[106,597,599],{"class":108,"line":598},36,[106,600,198],{"class":127},[15,602,603],{},"Ce code garantit que partout dans ton application, tu travailles avec la même instance du\nclient MongoDB quand tu en as besoin.",[68,605,606,612,618],{},[71,607,608,611],{},[74,609,610],{},"Propriétés statiques"," : pour stocker les instances uniques de MongoClient et de la base\n(Db).",[71,613,614,617],{},[74,615,616],{},"Méthode Connect"," : établit une connexion à MongoDB, en s'assurant qu'une seule instance\nMongoClient est active.",[71,619,620,623],{},[74,621,622],{},"Méthode GetDB"," : pour récupérer la base tout en maintenant le pattern Singleton.",[10,625,627],{"id":626},"docker","Docker",[15,629,630,633],{},[22,631,627],{"href":632,"target":25},"https:\u002F\u002Fdocs.docker.com\u002Fget-started\u002Foverview\u002F"," est une\nplateforme puissante qui facilite la création, le déploiement et l'exploitation d'applications\nvia des conteneurs. Les conteneurs permettent aux développeurs d'empaqueter un programme avec\ntous ses éléments — bibliothèques et autres dépendances — et de tout livrer comme un seul\npaquet.",[63,635,637],{"id":636},"dockerfile","Dockerfile",[15,639,640,641,644,645,39],{},"Un Dockerfile est un document texte qui contient toutes les commandes nécessaires qu'un\nutilisateur peut utiliser sur la ligne de commande pour construire une image. Il sert de\nmodèle pour créer des images Docker. Le Dockerfile inclut des directives comme ",[103,642,643],{},"FROM"," pour\ncréer une nouvelle étape de build à partir d'une image de base. On trouve de nombreux exemples\nsur la ",[22,646,648],{"href":647,"target":25},"https:\u002F\u002Fdocs.docker.com\u002Freference\u002Fdockerfile\u002F","page de\ndocumentation Docker",[63,650,652],{"id":651},"couches-multistage","Couches multistage",[15,654,655],{},"Le build multistage Docker est une fonctionnalité qui permet de construire une image en\nplusieurs étapes en utilisant un seul Dockerfile. Chaque étape peut utiliser une image de base\ndifférente et s'appuyer sur le travail des étapes précédentes, en ne sélectionnant que les\nartefacts nécessaires pour l'étape suivante. C'est très bénéfique pour optimiser les\nDockerfiles, les rendant plus efficaces et plus faciles à gérer. Voici quelques bénéfices de\nl'usage du multistage :",[68,657,658,664,670],{},[71,659,660,663],{},[74,661,662],{},"Tailles d'image réduites"," : utiliser les builds multistage permet de réduire\nconsidérablement la taille de l'image finale. Les fichiers et dépendances inutiles des étapes\nprécédentes ne sont pas requis dans l'image finale, ce qui donne un artefact de déploiement\nplus petit.",[71,665,666,669],{},[74,667,668],{},"Améliorations de sécurité"," : comme l'image finale ne contient que le nécessaire, elle\nréduit la surface d'attaque, ce qui améliore la sécurité. Moins de dépendances à l'exécution\nsignifie moins d'opportunités de vulnérabilités.",[71,671,672,675],{},[74,673,674],{},"Temps de build plus rapides"," : en divisant les Dockerfiles en plusieurs étapes, tu peux\nmettre en cache et réutiliser les étapes précédentes sans reconstruire l'image complète. Ça\naccélère le process de build, particulièrement pendant le développement et les tests.",[15,677,678,679,39],{},"Tu peux en apprendre plus sur le multistage Docker via la\n",[22,680,38],{"href":681,"target":25},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-stage\u002F",[63,683,685],{"id":684},"notre-dockerfile-dapi-expressjs","Notre Dockerfile d'API Express.js",[95,687,691],{"className":688,"code":689,"filename":690,"language":626,"meta":101,"style":101},"language-docker shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","FROM node:lts-alpine AS base\nRUN apk add --no-cache libc6-compat dumb-init\nWORKDIR \u002Fapp\n\nFROM base AS dependencies\nCOPY package*.json .\nRUN npm install\n\nFROM dependenices AS prune\nRUN npm prune --omit=dev\n\nFROM base AS production\nCOPY --from=prune \u002Fapp\u002Fnode_modules .\nCOPY . .\nRUN addgroup -S vegeta && adduser -S vegeta -G vegeta\nUSER vegeta\nENV NODE_ENV production\nEXPOSE 3000\nENTRYPOINT [\"dumb-init\", \"--\"]\nCMD [\"node\", \"src\u002Fserver.mjs\"]\n","Dokerfile",[103,692,693,698,703,708,712,717,722,727,731,736,741,745,750,755,760,765,770,775,780,785],{"__ignoreMap":101},[106,694,695],{"class":108,"line":109},[106,696,697],{},"FROM node:lts-alpine AS base\n",[106,699,700],{"class":108,"line":116},[106,701,702],{},"RUN apk add --no-cache libc6-compat dumb-init\n",[106,704,705],{"class":108,"line":131},[106,706,707],{},"WORKDIR \u002Fapp\n",[106,709,710],{"class":108,"line":144},[106,711,158],{"emptyLinePlaceholder":157},[106,713,714],{"class":108,"line":154},[106,715,716],{},"FROM base AS dependencies\n",[106,718,719],{"class":108,"line":161},[106,720,721],{},"COPY package*.json .\n",[106,723,724],{"class":108,"line":167},[106,725,726],{},"RUN npm install\n",[106,728,729],{"class":108,"line":181},[106,730,158],{"emptyLinePlaceholder":157},[106,732,733],{"class":108,"line":201},[106,734,735],{},"FROM dependenices AS prune\n",[106,737,738],{"class":108,"line":207},[106,739,740],{},"RUN npm prune --omit=dev\n",[106,742,743],{"class":108,"line":223},[106,744,158],{"emptyLinePlaceholder":157},[106,746,747],{"class":108,"line":245},[106,748,749],{},"FROM base AS production\n",[106,751,752],{"class":108,"line":253},[106,753,754],{},"COPY --from=prune \u002Fapp\u002Fnode_modules .\n",[106,756,757],{"class":108,"line":310},[106,758,759],{},"COPY . .\n",[106,761,762],{"class":108,"line":330},[106,763,764],{},"RUN addgroup -S vegeta && adduser -S vegeta -G vegeta\n",[106,766,767],{"class":108,"line":359},[106,768,769],{},"USER vegeta\n",[106,771,772],{"class":108,"line":377},[106,773,774],{},"ENV NODE_ENV production\n",[106,776,777],{"class":108,"line":409},[106,778,779],{},"EXPOSE 3000\n",[106,781,782],{"class":108,"line":418},[106,783,784],{},"ENTRYPOINT [\"dumb-init\", \"--\"]\n",[106,786,787],{"class":108,"line":424},[106,788,789],{},"CMD [\"node\", \"src\u002Fserver.mjs\"]\n",[15,791,792],{},"Voici un découpage du Dockerfile fourni :",[794,795,796,828,848,861],"ol",{},[71,797,798,801],{},[74,799,800],{},"Étape base",[68,802,803,810,821],{},[71,804,805,806,809],{},"Image de base : ",[103,807,808],{},"node:lts-alpine"," pour un environnement Node.js léger.",[71,811,812,813,816,817,820],{},"Packages essentiels : installe ",[103,814,815],{},"libc6-compat"," pour la compatibilité et ",[103,818,819],{},"dumb-init"," pour\nla gestion de process.",[71,822,823,824,827],{},"Répertoire de travail : définit ",[103,825,826],{},"\u002Fapp"," comme répertoire de travail pour les instructions\nsuivantes.",[71,829,830,833],{},[74,831,832],{},"Étape dependencies",[68,834,835,845],{},[71,836,837,838,841,842,39],{},"Copie ",[103,839,840],{},"package.json"," et ",[103,843,844],{},"package-lock.json",[71,846,847],{},"Installe uniquement les dépendances de production.",[71,849,850,853],{},[74,851,852],{},"Étape prune",[68,854,855],{},[71,856,857,858,39],{},"Supprime les fichiers superflus et les dépendances de développement pour réduire\ndavantage la taille de ",[103,859,860],{},"node_modules",[71,862,863,866],{},[74,864,865],{},"Étape production",[68,867,868,871,877,880,891],{},[71,869,870],{},"Réutilisation de l'image de base : repart de l'étape base pour garantir un environnement\npropre.",[71,872,873,874,876],{},"Modules et code : ajoute les ",[103,875,860],{}," élagués et copie le code source de\nl'application dans le conteneur.",[71,878,879],{},"Sécurité : configure un utilisateur non-root pour renforcer la sécurité, en évitant de\nlancer le conteneur avec les privilèges root.",[71,881,882,883,886,887,890],{},"Configuration : définit ",[103,884,885],{},"NODE_ENV"," à ",[103,888,889],{},"production"," pour optimiser l'environnement Node.js\npour la production.",[71,892,893,894,896],{},"Setup runtime : configure ",[103,895,819],{}," comme point d'entrée pour gérer le process\nprincipal, garantissant un démarrage et un arrêt propres.",[10,898,900],{"id":899},"tests-e2e-avec-jest","Tests E2E avec Jest",[15,902,903],{},"Les tests E2E (end-to-end) évaluent le workflow de l'application du début à la fin. Ce type de\ntest valide l'intégration du système avec d'autres interfaces, évalue ses dépendances à\nd'autres environnements, et garantit que toutes les pièces du système fonctionnent ensemble\ncomme prévu dans des situations changeantes.",[15,905,906,907,911,912,911,916,911,920,39],{},"Les tests E2E peuvent être réalisés sur une API Express.js avec divers outils. Ces outils\npermettent de répliquer un usage réel en envoyant des requêtes HTTP à l'API et en vérifiant\nles réponses, garantissant que l'ensemble du système fonctionne correctement. Les outils\ncouramment utilisés pour les tests E2E d'applications Express.js incluent\n",[22,908,910],{"href":909,"target":25},"https:\u002F\u002Flearning.postman.com\u002Fdocs\u002Fintroduction\u002Foverview\u002F","Postman",",\n",[22,913,915],{"href":914,"target":25},"https:\u002F\u002Fjestjs.io\u002F","JestJS",[22,917,919],{"href":918,"target":25},"https:\u002F\u002Fmochajs.org\u002F","MochaJS",[22,921,923],{"href":922,"target":25},"https:\u002F\u002Fdocs.cypress.io\u002Fguides\u002Foverview\u002Fwhy-cypress","Cypress",[15,925,926,927,931],{},"Pour ce guide, on utilise JestJS, connu comme un framework de tests unitaires pour JavaScript.\nOn le combine avec ",[22,928,930],{"href":929,"target":25},"https:\u002F\u002Fgithub.com\u002Fladjs\u002Fsupertest","SuperTest","\npour gérer nos tests E2E, puisqu'il inclut une syntaxe claire pour écrire des tests et un\nsupport correct de la gestion asynchrone.",[15,933,934],{},"Voici un cas de test qui s'assure que notre serveur est en marche et fonctionnel.",[95,936,939],{"className":97,"code":937,"filename":938,"language":100,"meta":101,"style":101},"import supertest from 'supertest';\nimport server from 'src\u002Fserver.mjs';\n\ndescribe('Healthcheck E2E tests', () => {\n  afterAll(async () => {\n    await server.close(); \u002F\u002F Ensure the server is closed after tests\n  });\n\n  it('\u002FGET \u002Fapi\u002Fhealthcheck', async () => {\n    const response = await supertest(server).get('\u002Fapi\u002Fhealthcheck');\n    expect(response.statusCode).toBe(200);\n    expect(response.body).toHaveProperty(\"uptime\");\n    expect(typeof response.body.uptime).toBe('number');\n    expect(response.body.uptime).toBeGreaterThan(0);\n    expect(response.body).toHaveProperty(\"mongo\", true);\n  });\n});\n","healthcheck.test.mjs",[103,940,941,962,980,984,1008,1024,1044,1053,1057,1081,1121,1153,1186,1224,1256,1293,1301],{"__ignoreMap":101},[106,942,943,946,949,952,955,958,960],{"class":108,"line":109},[106,944,945],{"class":173},"import",[106,947,948],{"class":235}," supertest ",[106,950,951],{"class":173},"from",[106,953,954],{"class":127}," '",[106,956,957],{"class":277},"supertest",[106,959,343],{"class":127},[106,961,141],{"class":127},[106,963,964,966,969,971,973,976,978],{"class":108,"line":116},[106,965,945],{"class":173},[106,967,968],{"class":235}," server ",[106,970,951],{"class":173},[106,972,954],{"class":127},[106,974,975],{"class":277},"src\u002Fserver.mjs",[106,977,343],{"class":127},[106,979,141],{"class":127},[106,981,982],{"class":108,"line":131},[106,983,158],{"emptyLinePlaceholder":157},[106,985,986,989,991,993,996,998,1000,1003,1006],{"class":108,"line":144},[106,987,988],{"class":267},"describe",[106,990,271],{"class":235},[106,992,343],{"class":127},[106,994,995],{"class":277},"Healthcheck E2E tests",[106,997,343],{"class":127},[106,999,283],{"class":127},[106,1001,1002],{"class":127}," ()",[106,1004,1005],{"class":119}," =>",[106,1007,128],{"class":127},[106,1009,1010,1013,1015,1018,1020,1022],{"class":108,"line":154},[106,1011,1012],{"class":267},"  afterAll",[106,1014,271],{"class":137},[106,1016,1017],{"class":119},"async",[106,1019,1002],{"class":127},[106,1021,1005],{"class":119},[106,1023,128],{"class":127},[106,1025,1026,1029,1032,1034,1037,1039,1041],{"class":108,"line":161},[106,1027,1028],{"class":173},"    await",[106,1030,1031],{"class":235}," server",[106,1033,39],{"class":127},[106,1035,1036],{"class":267},"close",[106,1038,218],{"class":137},[106,1040,353],{"class":127},[106,1042,1043],{"class":112}," \u002F\u002F Ensure the server is closed after tests\n",[106,1045,1046,1049,1051],{"class":108,"line":167},[106,1047,1048],{"class":127},"  }",[106,1050,305],{"class":137},[106,1052,141],{"class":127},[106,1054,1055],{"class":108,"line":181},[106,1056,158],{"emptyLinePlaceholder":157},[106,1058,1059,1062,1064,1066,1069,1071,1073,1075,1077,1079],{"class":108,"line":201},[106,1060,1061],{"class":267},"  it",[106,1063,271],{"class":137},[106,1065,343],{"class":127},[106,1067,1068],{"class":277},"\u002FGET \u002Fapi\u002Fhealthcheck",[106,1070,343],{"class":127},[106,1072,283],{"class":127},[106,1074,212],{"class":119},[106,1076,1002],{"class":127},[106,1078,1005],{"class":119},[106,1080,128],{"class":127},[106,1082,1083,1086,1089,1091,1093,1096,1098,1101,1103,1105,1108,1110,1112,1115,1117,1119],{"class":108,"line":207},[106,1084,1085],{"class":119},"    const",[106,1087,1088],{"class":235}," response",[106,1090,261],{"class":127},[106,1092,535],{"class":173},[106,1094,1095],{"class":267}," supertest",[106,1097,271],{"class":137},[106,1099,1100],{"class":235},"server",[106,1102,305],{"class":137},[106,1104,39],{"class":127},[106,1106,1107],{"class":267},"get",[106,1109,271],{"class":137},[106,1111,343],{"class":127},[106,1113,1114],{"class":277},"\u002Fapi\u002Fhealthcheck",[106,1116,343],{"class":127},[106,1118,305],{"class":137},[106,1120,141],{"class":127},[106,1122,1123,1126,1128,1131,1133,1136,1138,1140,1143,1145,1149,1151],{"class":108,"line":223},[106,1124,1125],{"class":267},"    expect",[106,1127,271],{"class":137},[106,1129,1130],{"class":235},"response",[106,1132,39],{"class":127},[106,1134,1135],{"class":235},"statusCode",[106,1137,305],{"class":137},[106,1139,39],{"class":127},[106,1141,1142],{"class":267},"toBe",[106,1144,271],{"class":137},[106,1146,1148],{"class":1147},"sbssI","200",[106,1150,305],{"class":137},[106,1152,141],{"class":127},[106,1154,1155,1157,1159,1161,1163,1166,1168,1170,1173,1175,1177,1180,1182,1184],{"class":108,"line":245},[106,1156,1125],{"class":267},[106,1158,271],{"class":137},[106,1160,1130],{"class":235},[106,1162,39],{"class":127},[106,1164,1165],{"class":235},"body",[106,1167,305],{"class":137},[106,1169,39],{"class":127},[106,1171,1172],{"class":267},"toHaveProperty",[106,1174,271],{"class":137},[106,1176,274],{"class":127},[106,1178,1179],{"class":277},"uptime",[106,1181,274],{"class":127},[106,1183,305],{"class":137},[106,1185,141],{"class":127},[106,1187,1188,1190,1192,1195,1197,1199,1201,1203,1205,1207,1209,1211,1213,1215,1218,1220,1222],{"class":108,"line":253},[106,1189,1125],{"class":267},[106,1191,271],{"class":137},[106,1193,1194],{"class":127},"typeof",[106,1196,1088],{"class":235},[106,1198,39],{"class":127},[106,1200,1165],{"class":235},[106,1202,39],{"class":127},[106,1204,1179],{"class":235},[106,1206,305],{"class":137},[106,1208,39],{"class":127},[106,1210,1142],{"class":267},[106,1212,271],{"class":137},[106,1214,343],{"class":127},[106,1216,1217],{"class":277},"number",[106,1219,343],{"class":127},[106,1221,305],{"class":137},[106,1223,141],{"class":127},[106,1225,1226,1228,1230,1232,1234,1236,1238,1240,1242,1244,1247,1249,1252,1254],{"class":108,"line":310},[106,1227,1125],{"class":267},[106,1229,271],{"class":137},[106,1231,1130],{"class":235},[106,1233,39],{"class":127},[106,1235,1165],{"class":235},[106,1237,39],{"class":127},[106,1239,1179],{"class":235},[106,1241,305],{"class":137},[106,1243,39],{"class":127},[106,1245,1246],{"class":267},"toBeGreaterThan",[106,1248,271],{"class":137},[106,1250,1251],{"class":1147},"0",[106,1253,305],{"class":137},[106,1255,141],{"class":127},[106,1257,1258,1260,1262,1264,1266,1268,1270,1272,1274,1276,1278,1281,1283,1285,1289,1291],{"class":108,"line":330},[106,1259,1125],{"class":267},[106,1261,271],{"class":137},[106,1263,1130],{"class":235},[106,1265,39],{"class":127},[106,1267,1165],{"class":235},[106,1269,305],{"class":137},[106,1271,39],{"class":127},[106,1273,1172],{"class":267},[106,1275,271],{"class":137},[106,1277,274],{"class":127},[106,1279,1280],{"class":277},"mongo",[106,1282,274],{"class":127},[106,1284,283],{"class":127},[106,1286,1288],{"class":1287},"sfNiH"," true",[106,1290,305],{"class":137},[106,1292,141],{"class":127},[106,1294,1295,1297,1299],{"class":108,"line":359},[106,1296,1048],{"class":127},[106,1298,305],{"class":137},[106,1300,141],{"class":127},[106,1302,1303,1306,1308],{"class":108,"line":377},[106,1304,1305],{"class":127},"}",[106,1307,305],{"class":235},[106,1309,141],{"class":127},[10,1311,1313],{"id":1312},"nginx","Nginx",[15,1315,1316,1319],{},[22,1317,1313],{"href":1318,"target":25},"https:\u002F\u002Fnginx.org\u002Fen\u002Fdocs\u002F"," est un logiciel puissant et\nhautement performant qui agit comme serveur web et reverse proxy.",[15,1321,1322],{},"En tant que serveur web, Nginx peut gérer les requêtes HTTP\u002FHTTPS et fournir du contenu\nstatique rapidement en envoyant les fichiers depuis le disque vers le réseau. Il est très\nefficace pour servir du contenu statique comme des images, des fichiers JavaScript et CSS.",[15,1324,1325],{},"Nginx sert de reverse proxy, en dirigeant le trafic vers différents services backend selon\nles URLs ou en-têtes. Il gère également le load balancing entre plusieurs serveurs. C'est\nparticulièrement utile dans les architectures microservices, où plusieurs services gèrent\ndifférentes portions d'une application web.",[15,1327,1328],{},"Ainsi, utiliser Nginx comme reverse proxy pour une API Express.js fournit un moyen robuste,\nsécurisé et efficace de gérer les connexions clients, la sécurité et la livraison de contenu\nstatique — autant d'éléments qui contribuent à une architecture applicative plus scalable et\nmaintenable.",[63,1330,1332],{"id":1331},"mise-en-place-du-fichier-de-configuration-nginx","Mise en place du fichier de configuration Nginx",[15,1334,1335,1336,1339,1340,39],{},"Le fichier ",[103,1337,1338],{},"nginx.conf"," est le fichier de configuration principal de Nginx. Il spécifie\ncomment le serveur répond aux requêtes HTTP entrantes, gère de nombreux serveurs virtuels,\ntraite les paramètres SSL\u002FTLS, dirige les requêtes vers les apps backend, et plus encore.\nVoici la définition du bloc serveur de notre fichier ",[103,1341,1338],{},[95,1343,1347],{"className":1344,"code":1345,"filename":1346,"language":1312,"meta":101,"style":101},"language-nginx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","    server {\n        listen 80 default_server;\n        listen [::]:80 default_server;\n        server_name _;\n\n        # Security Headers\n        add_header X-Frame-Options \"SAMEORIGIN\";\n        add_header X-Content-Type-Options \"nosniff\";\n\n        # Proxy Pass to Node.js App\n        location \u002F {\n            proxy_pass http:\u002F\u002Fapp:3000; # app is the name of our app service name in docker\n            proxy_http_version 1.1;\n            proxy_set_header Upgrade $http_upgrade;\n            proxy_set_header Connection 'upgrade';\n            proxy_set_header Host $host;\n            proxy_cache_bypass $http_upgrade;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n        }\n\n        # Error Handling\n        error_log \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log;\n        access_log \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log;\n    }\n","default.conf",[103,1348,1349,1354,1359,1364,1369,1373,1378,1383,1388,1392,1397,1402,1407,1412,1417,1422,1427,1432,1437,1442,1447,1451,1456,1461,1466],{"__ignoreMap":101},[106,1350,1351],{"class":108,"line":109},[106,1352,1353],{},"    server {\n",[106,1355,1356],{"class":108,"line":116},[106,1357,1358],{},"        listen 80 default_server;\n",[106,1360,1361],{"class":108,"line":131},[106,1362,1363],{},"        listen [::]:80 default_server;\n",[106,1365,1366],{"class":108,"line":144},[106,1367,1368],{},"        server_name _;\n",[106,1370,1371],{"class":108,"line":154},[106,1372,158],{"emptyLinePlaceholder":157},[106,1374,1375],{"class":108,"line":161},[106,1376,1377],{},"        # Security Headers\n",[106,1379,1380],{"class":108,"line":167},[106,1381,1382],{},"        add_header X-Frame-Options \"SAMEORIGIN\";\n",[106,1384,1385],{"class":108,"line":181},[106,1386,1387],{},"        add_header X-Content-Type-Options \"nosniff\";\n",[106,1389,1390],{"class":108,"line":201},[106,1391,158],{"emptyLinePlaceholder":157},[106,1393,1394],{"class":108,"line":207},[106,1395,1396],{},"        # Proxy Pass to Node.js App\n",[106,1398,1399],{"class":108,"line":223},[106,1400,1401],{},"        location \u002F {\n",[106,1403,1404],{"class":108,"line":245},[106,1405,1406],{},"            proxy_pass http:\u002F\u002Fapp:3000; # app is the name of our app service name in docker\n",[106,1408,1409],{"class":108,"line":253},[106,1410,1411],{},"            proxy_http_version 1.1;\n",[106,1413,1414],{"class":108,"line":310},[106,1415,1416],{},"            proxy_set_header Upgrade $http_upgrade;\n",[106,1418,1419],{"class":108,"line":330},[106,1420,1421],{},"            proxy_set_header Connection 'upgrade';\n",[106,1423,1424],{"class":108,"line":359},[106,1425,1426],{},"            proxy_set_header Host $host;\n",[106,1428,1429],{"class":108,"line":377},[106,1430,1431],{},"            proxy_cache_bypass $http_upgrade;\n",[106,1433,1434],{"class":108,"line":409},[106,1435,1436],{},"            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",[106,1438,1439],{"class":108,"line":418},[106,1440,1441],{},"            proxy_set_header X-Forwarded-Proto $scheme;\n",[106,1443,1444],{"class":108,"line":424},[106,1445,1446],{},"        }\n",[106,1448,1449],{"class":108,"line":430},[106,1450,158],{"emptyLinePlaceholder":157},[106,1452,1453],{"class":108,"line":442},[106,1454,1455],{},"        # Error Handling\n",[106,1457,1458],{"class":108,"line":448},[106,1459,1460],{},"        error_log \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log;\n",[106,1462,1463],{"class":108,"line":453},[106,1464,1465],{},"        access_log \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log;\n",[106,1467,1468],{"class":108,"line":458},[106,1469,427],{},[15,1471,1472,1473,886,1476,1479,1480,886,1483,1486],{},"Cette configuration Nginx écoute le port 80 pour le trafic HTTP et supporte à la fois IPv4 et\nIPv6. Elle est configurée comme serveur catch-all par défaut, répondant à toute requête HTTP,\net inclut des en-têtes de sécurité importants : ",[103,1474,1475],{},"X-Frame-Options",[103,1477,1478],{},"SAMEORIGIN"," pour prévenir\nles attaques par clickjacking, et ",[103,1481,1482],{},"X-Content-Type-Options",[103,1484,1485],{},"nosniff"," pour empêcher le\nnavigateur de faire du MIME-sniffing sur des réponses qui ne correspondent pas au type de\ncontenu déclaré.",[15,1488,1489],{},"D'autres options de configuration incluent le cache de fichiers statiques (dossiers\nd'uploads), la configuration SSL\u002FTLS, et — pourquoi pas — des rate limits. On les couvrira\npeut-être dans une autre itération de ce projet.",[10,1491,1493],{"id":1492},"docker-compose","Docker Compose",[15,1495,1496,1499],{},[22,1497,1493],{"href":1498,"target":25},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002F"," est un outil\npour créer et gérer des applications Docker multi-conteneurs. Il permet de configurer les\nservices, réseaux et volumes de ton application à l'aide d'un fichier YAML. Puis, avec une\nseule commande, tu peux exécuter tous les services listés dans ta configuration.",[63,1501,1503],{"id":1502},"notre-docker-compose","Notre Docker Compose",[95,1505,1510],{"className":1506,"code":1507,"filename":1508,"language":1509,"meta":101,"style":101},"language-yml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","services:\n  mongo:\n    image: 'mongo:7.0-jammy'\n    networks:\n      - express\n    volumes:\n      - '$PWD\u002Fdocker\u002Fmongo\u002Finit.js:\u002Fdocker-entrypoint-initdb.d\u002Fmongo-init.js'\n      - 'mongo-data:\u002Fdata\u002Fdb'\n  app:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    networks:\n      - express\n    environment:\n      MONGODB_HOST: 'mongodb:\u002F\u002Fexpress:password@mongo:27017\u002Fexpress'\n      NODE_ENV: development\n    volumes:\n      - 'app-data:\u002Fapp'\n    depends_on:\n      - mongo\n  nginx:\n    image: 'nginx:stable-alpine3.17-slim'\n    networks:\n      - express\n    ports:\n      - '${NGINX_PORT:-80}:80'\n    volumes:\n      - '$PWD\u002Fdocker\u002Fnginx\u002Fnginx.conf:\u002Fetc\u002Fnginx\u002Fnginx.conf:ro'\n      - 'nginx-logs:\u002Fvar\u002Flogs\u002Fnginx'\n    depends_on:\n      - app\nnetworks:\n  express:\n    driver: bridge\nvolumes:\n  mongo-data:\n  app-data:\n  nginx-logs:\n\n","docker-compose.yml","yml",[103,1511,1512,1520,1527,1542,1549,1557,1564,1575,1586,1593,1600,1610,1620,1626,1632,1639,1653,1663,1669,1680,1687,1694,1701,1714,1720,1726,1733,1744,1750,1761,1772,1778,1785,1792,1799,1809,1816,1824,1832],{"__ignoreMap":101},[106,1513,1514,1517],{"class":108,"line":109},[106,1515,1516],{"class":137},"services",[106,1518,1519],{"class":127},":\n",[106,1521,1522,1525],{"class":108,"line":116},[106,1523,1524],{"class":137},"  mongo",[106,1526,1519],{"class":127},[106,1528,1529,1532,1534,1536,1539],{"class":108,"line":131},[106,1530,1531],{"class":137},"    image",[106,1533,291],{"class":127},[106,1535,954],{"class":127},[106,1537,1538],{"class":277},"mongo:7.0-jammy",[106,1540,1541],{"class":127},"'\n",[106,1543,1544,1547],{"class":108,"line":144},[106,1545,1546],{"class":137},"    networks",[106,1548,1519],{"class":127},[106,1550,1551,1554],{"class":108,"line":154},[106,1552,1553],{"class":127},"      -",[106,1555,1556],{"class":277}," express\n",[106,1558,1559,1562],{"class":108,"line":161},[106,1560,1561],{"class":137},"    volumes",[106,1563,1519],{"class":127},[106,1565,1566,1568,1570,1573],{"class":108,"line":167},[106,1567,1553],{"class":127},[106,1569,954],{"class":127},[106,1571,1572],{"class":277},"$PWD\u002Fdocker\u002Fmongo\u002Finit.js:\u002Fdocker-entrypoint-initdb.d\u002Fmongo-init.js",[106,1574,1541],{"class":127},[106,1576,1577,1579,1581,1584],{"class":108,"line":181},[106,1578,1553],{"class":127},[106,1580,954],{"class":127},[106,1582,1583],{"class":277},"mongo-data:\u002Fdata\u002Fdb",[106,1585,1541],{"class":127},[106,1587,1588,1591],{"class":108,"line":201},[106,1589,1590],{"class":137},"  app",[106,1592,1519],{"class":127},[106,1594,1595,1598],{"class":108,"line":207},[106,1596,1597],{"class":137},"    build",[106,1599,1519],{"class":127},[106,1601,1602,1605,1607],{"class":108,"line":223},[106,1603,1604],{"class":137},"      context",[106,1606,291],{"class":127},[106,1608,1609],{"class":1147}," .\n",[106,1611,1612,1615,1617],{"class":108,"line":245},[106,1613,1614],{"class":137},"      dockerfile",[106,1616,291],{"class":127},[106,1618,1619],{"class":277}," Dockerfile\n",[106,1621,1622,1624],{"class":108,"line":253},[106,1623,1546],{"class":137},[106,1625,1519],{"class":127},[106,1627,1628,1630],{"class":108,"line":310},[106,1629,1553],{"class":127},[106,1631,1556],{"class":277},[106,1633,1634,1637],{"class":108,"line":330},[106,1635,1636],{"class":137},"    environment",[106,1638,1519],{"class":127},[106,1640,1641,1644,1646,1648,1651],{"class":108,"line":359},[106,1642,1643],{"class":137},"      MONGODB_HOST",[106,1645,291],{"class":127},[106,1647,954],{"class":127},[106,1649,1650],{"class":277},"mongodb:\u002F\u002Fexpress:password@mongo:27017\u002Fexpress",[106,1652,1541],{"class":127},[106,1654,1655,1658,1660],{"class":108,"line":377},[106,1656,1657],{"class":137},"      NODE_ENV",[106,1659,291],{"class":127},[106,1661,1662],{"class":277}," development\n",[106,1664,1665,1667],{"class":108,"line":409},[106,1666,1561],{"class":137},[106,1668,1519],{"class":127},[106,1670,1671,1673,1675,1678],{"class":108,"line":418},[106,1672,1553],{"class":127},[106,1674,954],{"class":127},[106,1676,1677],{"class":277},"app-data:\u002Fapp",[106,1679,1541],{"class":127},[106,1681,1682,1685],{"class":108,"line":424},[106,1683,1684],{"class":137},"    depends_on",[106,1686,1519],{"class":127},[106,1688,1689,1691],{"class":108,"line":430},[106,1690,1553],{"class":127},[106,1692,1693],{"class":277}," mongo\n",[106,1695,1696,1699],{"class":108,"line":442},[106,1697,1698],{"class":137},"  nginx",[106,1700,1519],{"class":127},[106,1702,1703,1705,1707,1709,1712],{"class":108,"line":448},[106,1704,1531],{"class":137},[106,1706,291],{"class":127},[106,1708,954],{"class":127},[106,1710,1711],{"class":277},"nginx:stable-alpine3.17-slim",[106,1713,1541],{"class":127},[106,1715,1716,1718],{"class":108,"line":453},[106,1717,1546],{"class":137},[106,1719,1519],{"class":127},[106,1721,1722,1724],{"class":108,"line":458},[106,1723,1553],{"class":127},[106,1725,1556],{"class":277},[106,1727,1728,1731],{"class":108,"line":464},[106,1729,1730],{"class":137},"    ports",[106,1732,1519],{"class":127},[106,1734,1735,1737,1739,1742],{"class":108,"line":473},[106,1736,1553],{"class":127},[106,1738,954],{"class":127},[106,1740,1741],{"class":277},"${NGINX_PORT:-80}:80",[106,1743,1541],{"class":127},[106,1745,1746,1748],{"class":108,"line":490},[106,1747,1561],{"class":137},[106,1749,1519],{"class":127},[106,1751,1752,1754,1756,1759],{"class":108,"line":495},[106,1753,1553],{"class":127},[106,1755,954],{"class":127},[106,1757,1758],{"class":277},"$PWD\u002Fdocker\u002Fnginx\u002Fnginx.conf:\u002Fetc\u002Fnginx\u002Fnginx.conf:ro",[106,1760,1541],{"class":127},[106,1762,1763,1765,1767,1770],{"class":108,"line":509},[106,1764,1553],{"class":127},[106,1766,954],{"class":127},[106,1768,1769],{"class":277},"nginx-logs:\u002Fvar\u002Flogs\u002Fnginx",[106,1771,1541],{"class":127},[106,1773,1774,1776],{"class":108,"line":525},[106,1775,1684],{"class":137},[106,1777,1519],{"class":127},[106,1779,1780,1782],{"class":108,"line":546},[106,1781,1553],{"class":127},[106,1783,1784],{"class":277}," app\n",[106,1786,1787,1790],{"class":108,"line":578},[106,1788,1789],{"class":137},"networks",[106,1791,1519],{"class":127},[106,1793,1794,1797],{"class":108,"line":583},[106,1795,1796],{"class":137},"  express",[106,1798,1519],{"class":127},[106,1800,1801,1804,1806],{"class":108,"line":593},[106,1802,1803],{"class":137},"    driver",[106,1805,291],{"class":127},[106,1807,1808],{"class":277}," bridge\n",[106,1810,1811,1814],{"class":108,"line":598},[106,1812,1813],{"class":137},"volumes",[106,1815,1519],{"class":127},[106,1817,1819,1822],{"class":108,"line":1818},37,[106,1820,1821],{"class":137},"  mongo-data",[106,1823,1519],{"class":127},[106,1825,1827,1830],{"class":108,"line":1826},38,[106,1828,1829],{"class":137},"  app-data",[106,1831,1519],{"class":127},[106,1833,1835,1838],{"class":108,"line":1834},39,[106,1836,1837],{"class":137},"  nginx-logs",[106,1839,1519],{"class":127},[15,1841,1842,1843,1845,1846,841,1848,1851],{},"Notre Docker Compose inclut trois services (",[103,1844,1280],{},", ",[103,1847,1312],{},[103,1849,1850],{},"app",") connectés via un\nréseau docker pour isoler notre application des autres projets. Le service Node.js est servi\nvia le serveur Nginx, qui écoute par défaut le port 80 (tu peux utiliser 8000 pour le\ndéveloppement). On inclut également des volumes pour stocker les données de l'application.\nC'est critique pour la base Mongo puisqu'on peut avoir besoin de réaliser des opérations de\nbackup. La rétention long-terme des logs applicatifs peut nécessiter des volumes pour les\nservices nginx et app.",[10,1853,1855],{"id":1854},"conclusion","Conclusion",[15,1857,1858],{},"Pour résumer, cet article t'a guidé à travers une technique complète de déploiement d'une\napplication Express avec Docker, en se concentrant sur des aspects clés comme la performance\nMongoDB, les builds Docker multi-stage, les tests end-to-end avec Jest, et l'utilisation de\nNginx comme reverse proxy. On a vu comment Docker peut aider à accélérer le process de\ndéveloppement et de déploiement tout en maintenant la cohérence entre les environnements. Le\nstyle Singleton de MongoDB garantit une connexion stable et efficace, tandis que les builds\nDocker multi-stage réduisent la taille de l'image finale sans sacrifier la sécurité ou les\nfonctionnalités. De plus, incorporer Jest pour les tests end-to-end garantit que l'application\nest fiable et résiliente avant sa mise en production. Enfin, Nginx en reverse proxy améliore\nles performances tout en apportant une couche de protection supplémentaire.",[15,1860,1861],{},"Que tu sois un développeur expérimenté ou nouveau sur Docker, ce guide est conçu pour\néquilibrer simplicité, sécurité et performance, ce qui en fait un excellent point de départ\npour livrer des applications web scalables et efficaces.",[1863,1864,1865],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s6hCs, html code.shiki .s6hCs{--shiki-light:#9C3EDA;--shiki-light-font-style:italic;--shiki-default:#C792EA;--shiki-default-font-style:italic;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sFweD, html code.shiki .sFweD{--shiki-light:#E2931D;--shiki-light-font-style:italic;--shiki-default:#FFCB6B;--shiki-default-font-style:italic;--shiki-dark:#FFCB6B;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":101,"searchDepth":116,"depth":116,"links":1867},[1868,1869,1870,1871,1875,1880,1881,1884,1887],{"id":12,"depth":116,"text":13},{"id":30,"depth":116,"text":31},{"id":42,"depth":116,"text":43},{"id":52,"depth":116,"text":53,"children":1872},[1873,1874],{"id":65,"depth":131,"text":66},{"id":92,"depth":131,"text":93},{"id":626,"depth":116,"text":627,"children":1876},[1877,1878,1879],{"id":636,"depth":131,"text":637},{"id":651,"depth":131,"text":652},{"id":684,"depth":131,"text":685},{"id":899,"depth":116,"text":900},{"id":1312,"depth":116,"text":1313,"children":1882},[1883],{"id":1331,"depth":131,"text":1332},{"id":1492,"depth":116,"text":1493,"children":1885},[1886],{"id":1502,"depth":131,"text":1503},{"id":1854,"depth":116,"text":1855},"2024-04-11","Comment déployer une API REST Express.js avec Docker, avec un focus sur les performances MongoDB, les builds Docker multi-stage, Jest pour les tests, et Nginx comme reverse proxy.","md","https:\u002F\u002Fres.cloudinary.com\u002Fdpdwhd6ka\u002Fimage\u002Fupload\u002Ff_auto,q_auto\u002Fv1\u002FBlog\u002Farticles\u002Fdocker-nodejs-mongodb",{},"\u002Fdevops\u002Fdeploy-expressjs-api-using-docker.fr",{"title":5,"description":1889},"deploy-expressjs-api-using-docker","devops\u002F1.deploy-expressjs-api-using-docker.fr",[1898,1899,1900,1901,1902,627],"Express.JS","API","Node.js","Mongo","CI\u002FCD",[1904,1905],"backend","devops","hJ_MlCMxsyleUu0AOTv2Glxw2YHMWyizxKcjRSTb4y8",{"id":1908,"title":1909,"body":1910,"date":1888,"description":3411,"extension":1890,"img":1891,"meta":3412,"navigation":157,"path":3413,"seo":3414,"slug":1895,"stem":3415,"tags":3416,"topics":3417,"__hash__":3418},"content\u002Fdevops\u002F1.deploy-expressjs-api-using-docker.md","Deploy Express.js API using Docker",{"type":7,"value":1911,"toc":3389},[1912,1914,1917,1924,1926,1931,1933,1938,1942,1949,1953,1964,1968,2344,2347,2367,2369,2374,2376,2385,2389,2392,2403,2408,2412,2496,2499,2562,2566,2569,2580,2586,2589,2919,2921,2926,2929,2932,2935,2939,2945,3049,3064,3067,3070,3075,3079,3367,3378,3380,3383,3386],[10,1913,13],{"id":12},[15,1915,1916],{},"In today's technological landscape, delivering apps swiftly and reliably is critical. Docker, with its containerization\ntechnology, provides an easy way to deploy Node.js apps. This post discusses how to deploy an Express.js API\nusing MongoDB, focusing on Docker containers recommended practices, and testing methodologies. We'll skip the basics of\nbuilding an Express.js application and connecting to MongoDB. Instead, we're concentrating on using Docker's\ncapabilities, following MongoDB best practices, creating thorough testing with Jest, and using Nginx as a reverse proxy.",[15,1918,1919,1920,1923],{},"The whole code ",[22,1921,1922],{"href":24,"target":25},"repository on GitHub",",\nserves as a practical illustration of the concepts and practices covered in this guide.",[10,1925,31],{"id":30},[15,1927,1928,1929,39],{},"Express.js is a popular Node.js framework that speeds up and facilitates the development of web applications and APIs.\nIt provides a powerful collection of capabilities that simplify the server creation process,\nallowing the developers to set up complicated routes, middlewares and server-side features with less code.\nBecause of its wide popularity, Express.js is supported by a big community, which provides a set of middleware that\nimproves its capability, making it a popular choice among developers wishing to build high-performance web applications.\nIf you're not familiar with Express.js, check the ",[22,1930,38],{"href":37,"target":25},[10,1932,43],{"id":42},[15,1934,1935,1936,39],{},"MongoDB is a NoSQL database built for simple development and scaling. It is known as a document database and stores\ndata in flexible, JSON-like documents, which means that fields can differ from document to document and data structures\ncan change over time. This architecture allows you to easily define hierarchical relationships, store arrays, and create\nother more complicated structures. MongoDB is well-known for its agility, high availability, and security oriented,\nmaking it a popular choice for modern web applications which require rapid access to huge amounts of data.\nIf you're new to MongoDB, check the ",[22,1937,38],{"href":49,"target":25},[10,1939,1941],{"id":1940},"singleton-pattern","Singleton Pattern",[15,1943,1944,1945,1948],{},"The Singleton pattern is a software design pattern that assures a class has only one instance while also giving a global\npoint of access to it. According to ",[22,1946,1947],{"href":59,"target":25},"\nRefactoring Guru",", the Singleton pattern is frequently used when handling database\nconnections since it allows a class to be instantiated only once. This is especially beneficial when a single shared\nresource, such as a database connection, is required to conduct activities across multiple components of an application.\nBy using the Singleton pattern, we can avoid mistakenly creating several instances of a class, saving resources\nand ensuring consistent behavior throughout the program.",[63,1950,1952],{"id":1951},"benefits-of-the-singleton-for-mongodb-client","Benefits of the Singleton for MongoDB client",[68,1954,1955,1958,1961],{},[71,1956,1957],{},"Consistent connection: Maintaining a single MongoDB connection avoids the overhead of opening and closing multiple\nconnections, enhancing performance.",[71,1959,1960],{},"Resource optimization: Singleton ensures optimal use of resources, preventing the pitfalls of redundant connections.",[71,1962,1963],{},"Avoid connection leaks: You may avoid potential connection leaks caused by separate components of an application\ninappropriately handling individual connection instances. A connection leak can drain the database server's resources,\nresulting in performance degradation.",[63,1965,1967],{"id":1966},"implement-singleton-pattern-for-mongodb-client","Implement singleton pattern for MongoDB client",[95,1969,1970],{"className":97,"code":98,"filename":99,"language":100,"meta":101,"style":101},[103,1971,1972,1976,1984,1992,2000,2004,2008,2016,2030,2034,2046,2060,2066,2106,2122,2144,2158,2186,2192,2196,2200,2210,2214,2218,2222,2226,2234,2248,2252,2264,2278,2296,2324,2328,2336,2340],{"__ignoreMap":101},[106,1973,1974],{"class":108,"line":109},[106,1975,113],{"class":112},[106,1977,1978,1980,1982],{"class":108,"line":116},[106,1979,120],{"class":119},[106,1981,124],{"class":123},[106,1983,128],{"class":127},[106,1985,1986,1988,1990],{"class":108,"line":131},[106,1987,134],{"class":119},[106,1989,138],{"class":137},[106,1991,141],{"class":127},[106,1993,1994,1996,1998],{"class":108,"line":144},[106,1995,134],{"class":119},[106,1997,149],{"class":137},[106,1999,141],{"class":127},[106,2001,2002],{"class":108,"line":154},[106,2003,158],{"emptyLinePlaceholder":157},[106,2005,2006],{"class":108,"line":161},[106,2007,164],{"class":112},[106,2009,2010,2012,2014],{"class":108,"line":167},[106,2011,170],{"class":112},[106,2013,174],{"class":173},[106,2015,178],{"class":177},[106,2017,2018,2020,2022,2024,2026,2028],{"class":108,"line":181},[106,2019,170],{"class":112},[106,2021,174],{"class":173},[106,2023,188],{"class":177},[106,2025,191],{"class":173},[106,2027,195],{"class":194},[106,2029,198],{"class":173},[106,2031,2032],{"class":108,"line":201},[106,2033,204],{"class":112},[106,2035,2036,2038,2040,2042,2044],{"class":108,"line":207},[106,2037,134],{"class":119},[106,2039,212],{"class":119},[106,2041,215],{"class":137},[106,2043,218],{"class":127},[106,2045,128],{"class":127},[106,2047,2048,2050,2052,2054,2056,2058],{"class":108,"line":223},[106,2049,226],{"class":173},[106,2051,229],{"class":137},[106,2053,232],{"class":127},[106,2055,236],{"class":235},[106,2057,239],{"class":137},[106,2059,242],{"class":127},[106,2061,2062,2064],{"class":108,"line":245},[106,2063,248],{"class":173},[106,2065,128],{"class":127},[106,2067,2068,2070,2072,2074,2076,2078,2080,2082,2084,2086,2088,2090,2092,2094,2096,2098,2100,2102,2104],{"class":108,"line":253},[106,2069,256],{"class":127},[106,2071,236],{"class":235},[106,2073,261],{"class":127},[106,2075,264],{"class":127},[106,2077,268],{"class":267},[106,2079,271],{"class":137},[106,2081,274],{"class":127},[106,2083,278],{"class":277},[106,2085,274],{"class":127},[106,2087,283],{"class":127},[106,2089,191],{"class":127},[106,2091,288],{"class":137},[106,2093,291],{"class":127},[106,2095,294],{"class":235},[106,2097,39],{"class":127},[106,2099,299],{"class":235},[106,2101,302],{"class":127},[106,2103,305],{"class":137},[106,2105,141],{"class":127},[106,2107,2108,2110,2112,2114,2116,2118,2120],{"class":108,"line":310},[106,2109,313],{"class":173},[106,2111,316],{"class":127},[106,2113,236],{"class":235},[106,2115,39],{"class":127},[106,2117,323],{"class":267},[106,2119,218],{"class":137},[106,2121,141],{"class":127},[106,2123,2124,2126,2128,2130,2132,2134,2136,2138,2140,2142],{"class":108,"line":330},[106,2125,333],{"class":235},[106,2127,39],{"class":127},[106,2129,338],{"class":267},[106,2131,271],{"class":137},[106,2133,343],{"class":127},[106,2135,346],{"class":277},[106,2137,343],{"class":127},[106,2139,305],{"class":137},[106,2141,353],{"class":127},[106,2143,356],{"class":112},[106,2145,2146,2148,2150,2152,2154,2156],{"class":108,"line":359},[106,2147,362],{"class":127},[106,2149,365],{"class":173},[106,2151,229],{"class":137},[106,2153,370],{"class":235},[106,2155,239],{"class":137},[106,2157,242],{"class":127},[106,2159,2160,2162,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184],{"class":108,"line":377},[106,2161,333],{"class":235},[106,2163,39],{"class":127},[106,2165,370],{"class":267},[106,2167,271],{"class":137},[106,2169,274],{"class":127},[106,2171,390],{"class":277},[106,2173,274],{"class":127},[106,2175,283],{"class":127},[106,2177,397],{"class":235},[106,2179,39],{"class":127},[106,2181,402],{"class":235},[106,2183,305],{"class":137},[106,2185,141],{"class":127},[106,2187,2188,2190],{"class":108,"line":409},[106,2189,412],{"class":173},[106,2191,415],{"class":235},[106,2193,2194],{"class":108,"line":418},[106,2195,421],{"class":127},[106,2197,2198],{"class":108,"line":424},[106,2199,427],{"class":127},[106,2201,2202,2204,2206,2208],{"class":108,"line":430},[106,2203,433],{"class":173},[106,2205,316],{"class":127},[106,2207,236],{"class":235},[106,2209,141],{"class":127},[106,2211,2212],{"class":108,"line":442},[106,2213,445],{"class":127},[106,2215,2216],{"class":108,"line":448},[106,2217,158],{"emptyLinePlaceholder":157},[106,2219,2220],{"class":108,"line":453},[106,2221,164],{"class":112},[106,2223,2224],{"class":108,"line":458},[106,2225,461],{"class":112},[106,2227,2228,2230,2232],{"class":108,"line":464},[106,2229,170],{"class":112},[106,2231,174],{"class":173},[106,2233,178],{"class":177},[106,2235,2236,2238,2240,2242,2244,2246],{"class":108,"line":473},[106,2237,170],{"class":112},[106,2239,174],{"class":173},[106,2241,480],{"class":177},[106,2243,191],{"class":173},[106,2245,485],{"class":194},[106,2247,198],{"class":173},[106,2249,2250],{"class":108,"line":490},[106,2251,204],{"class":112},[106,2253,2254,2256,2258,2260,2262],{"class":108,"line":495},[106,2255,134],{"class":119},[106,2257,212],{"class":119},[106,2259,502],{"class":137},[106,2261,218],{"class":127},[106,2263,128],{"class":127},[106,2265,2266,2268,2270,2272,2274,2276],{"class":108,"line":509},[106,2267,226],{"class":173},[106,2269,229],{"class":137},[106,2271,232],{"class":127},[106,2273,518],{"class":235},[106,2275,239],{"class":137},[106,2277,242],{"class":127},[106,2279,2280,2282,2284,2286,2288,2290,2292,2294],{"class":108,"line":525},[106,2281,528],{"class":119},[106,2283,138],{"class":235},[106,2285,261],{"class":127},[106,2287,535],{"class":173},[106,2289,316],{"class":127},[106,2291,323],{"class":267},[106,2293,218],{"class":137},[106,2295,141],{"class":127},[106,2297,2298,2300,2302,2304,2306,2308,2310,2312,2314,2316,2318,2320,2322],{"class":108,"line":546},[106,2299,549],{"class":127},[106,2301,518],{"class":235},[106,2303,261],{"class":127},[106,2305,138],{"class":235},[106,2307,39],{"class":127},[106,2309,518],{"class":267},[106,2311,271],{"class":137},[106,2313,274],{"class":127},[106,2315,566],{"class":277},[106,2317,274],{"class":127},[106,2319,305],{"class":137},[106,2321,353],{"class":127},[106,2323,575],{"class":112},[106,2325,2326],{"class":108,"line":578},[106,2327,427],{"class":127},[106,2329,2330,2332,2334],{"class":108,"line":583},[106,2331,433],{"class":173},[106,2333,316],{"class":127},[106,2335,590],{"class":235},[106,2337,2338],{"class":108,"line":593},[106,2339,445],{"class":127},[106,2341,2342],{"class":108,"line":598},[106,2343,198],{"class":127},[15,2345,2346],{},"This code makes sure that throughout your application, you're working with the same instance of the MongoDB client\nwhenever you need it.",[68,2348,2349,2355,2361],{},[71,2350,2351,2354],{},[74,2352,2353],{},"Static Properties",": For storing single instances of MongoClient, the database (Db)",[71,2356,2357,2360],{},[74,2358,2359],{},"Connect Method",": Establishes a connection to MongoDB, ensuring only one MongoClient instance is active",[71,2362,2363,2366],{},[74,2364,2365],{},"GetDB Method",": For retrieving the database while maintaining the Singleton pattern",[10,2368,627],{"id":626},[15,2370,2371,2373],{},[22,2372,627],{"href":632,"target":25}," is a powerful platform that makes it\neasy to create, deploy, and operate applications via containers.\nContainers allow developers to bundle a program with all of its elements, including as libraries and other dependencies,\nand ship it all out as one package.",[63,2375,637],{"id":636},[15,2377,2378,2379,2381,2382,39],{},"A Dockerfile is a text document that contains all the necessary commands that a user can use on the command line to\nbuild an image. It serves as a blueprint for creating Docker images. The Dockerfile includes directives like ",[103,2380,643],{}," for\ncreating a new build stage from a base image. Many examples can be found on the\nDocker ",[22,2383,2384],{"href":647,"target":25},"documentation page",[63,2386,2388],{"id":2387},"multistage-layer","Multistage layer",[15,2390,2391],{},"Docker multistage build is a feature that enables you to build an image in multiple stages using a single Dockerfile.\nEach stage can use a different basis image and build on the work of previous stages, selecting just the artifacts\nrequired for the next level.\nThis is very beneficial for optimizing Dockerfiles, making them more efficient and easier to manage.\nHere are some benefits of using multistage builds:",[68,2393,2394,2397,2400],{},[71,2395,2396],{},"Smaller image sizes: Using multistage builds allows you to considerably reduce the size of the final image.\nUnnecessary files and dependencies from earlier stages are not required in the final image,\nresulting in a smaller deployment artifact.",[71,2398,2399],{},"Security Improvements: Because the final image contains only the necessities, it reduces the attack surface area,\nwhich\nimproves security.\nLess runtime dependencies equal fewer opportunities for vulnerabilities.",[71,2401,2402],{},"Faster Build Times:\nBy dividing Dockerfiles into many stages, you can cache and reuse previous stages without rebuilding\nthe complete image.\nThis accelerates the build process, particularly during development and testing.",[15,2404,2405,2406,39],{},"You can read more about Docker multistage build through\nthe ",[22,2407,38],{"href":681,"target":25},[63,2409,2411],{"id":2410},"our-expressjs-api-dockerfile","Our Express.js API Dockerfile",[95,2413,2414],{"className":688,"code":689,"filename":690,"language":626,"meta":101,"style":101},[103,2415,2416,2420,2424,2428,2432,2436,2440,2444,2448,2452,2456,2460,2464,2468,2472,2476,2480,2484,2488,2492],{"__ignoreMap":101},[106,2417,2418],{"class":108,"line":109},[106,2419,697],{},[106,2421,2422],{"class":108,"line":116},[106,2423,702],{},[106,2425,2426],{"class":108,"line":131},[106,2427,707],{},[106,2429,2430],{"class":108,"line":144},[106,2431,158],{"emptyLinePlaceholder":157},[106,2433,2434],{"class":108,"line":154},[106,2435,716],{},[106,2437,2438],{"class":108,"line":161},[106,2439,721],{},[106,2441,2442],{"class":108,"line":167},[106,2443,726],{},[106,2445,2446],{"class":108,"line":181},[106,2447,158],{"emptyLinePlaceholder":157},[106,2449,2450],{"class":108,"line":201},[106,2451,735],{},[106,2453,2454],{"class":108,"line":207},[106,2455,740],{},[106,2457,2458],{"class":108,"line":223},[106,2459,158],{"emptyLinePlaceholder":157},[106,2461,2462],{"class":108,"line":245},[106,2463,749],{},[106,2465,2466],{"class":108,"line":253},[106,2467,754],{},[106,2469,2470],{"class":108,"line":310},[106,2471,759],{},[106,2473,2474],{"class":108,"line":330},[106,2475,764],{},[106,2477,2478],{"class":108,"line":359},[106,2479,769],{},[106,2481,2482],{"class":108,"line":377},[106,2483,774],{},[106,2485,2486],{"class":108,"line":409},[106,2487,779],{},[106,2489,2490],{"class":108,"line":418},[106,2491,784],{},[106,2493,2494],{"class":108,"line":424},[106,2495,789],{},[15,2497,2498],{},"Here’s a breakdown of the provided Dockerfile:",[794,2500,2501,2517,2530,2540],{},[71,2502,2503,2506],{},[74,2504,2505],{},"Base stage",[68,2507,2508,2511,2514],{},[71,2509,2510],{},"Base Image: Use node:lts-alpine for a lightweight Node.js environment",[71,2512,2513],{},"Essential Packages: Installs libc6-compat for compatibility and dumb-init for process management.",[71,2515,2516],{},"Working Directory: Sets \u002Fapp as the working directory for later instructions.",[71,2518,2519,2522],{},[74,2520,2521],{},"Dependencies stage",[68,2523,2524,2527],{},[71,2525,2526],{},"Copy both package.json and package-lock.json.",[71,2528,2529],{},"Installs only production dependencies",[71,2531,2532,2535],{},[74,2533,2534],{},"Prune stage",[68,2536,2537],{},[71,2538,2539],{},"Removes extraneous files and development dependencies to further minimize the size of node_modules.",[71,2541,2542,2545],{},[74,2543,2544],{},"Production stage",[68,2546,2547,2550,2553,2556,2559],{},[71,2548,2549],{},"Base Image Reuse: starts again from the base stage to ensure a clean environment",[71,2551,2552],{},"Modules and Code: Adds the pruned node_modules and copies the application source code into the container",[71,2554,2555],{},"Security: Set up a non-root user to enhance security, avoiding running the container with root privileges",[71,2557,2558],{},"Configuration: Sets NODE_ENV to production to optimize the Node.js environment for production",[71,2560,2561],{},"Runtime Setup: Configures dumb-init as the entry point to manage the main process, ensuring clean startup and\nshutdown",[10,2563,2565],{"id":2564},"e2e-testing-with-jest","E2E Testing with Jest",[15,2567,2568],{},"E2E tests evaluate the application's workflow from start to finish. This sort of testing validates the system's\nintegration with other interfaces, evaluates its dependent on other environments, and guarantees all pieces of the\nsystem work together as intended under changing situations.",[15,2570,2571,2572,911,2574,911,2576,911,2578],{},"End-to-end (E2E) tests can be performed on an Express.js API using a variety of tools. These tools allow you to\nreplicate real-world usage by sending HTTP queries to the API and verifying the answers, ensuring that the entire system\nworks properly. Commonly used tools for E2E testing of Express.js applications include\n",[22,2573,910],{"href":909,"target":25},[22,2575,915],{"href":914,"target":25},[22,2577,919],{"href":918,"target":25},[22,2579,923],{"href":922,"target":25},[15,2581,2582,2583,2585],{},"For this guide, we will go through JestJS, known as a unit testing framework for JavaScript. We'll pair it\nto ",[22,2584,930],{"href":929,"target":25}," to handle our E2E tests, since It\nincludes a clear syntax for\nauthoring tests and decent support for asynchronous test handling.",[15,2587,2588],{},"Here's a test case that ensures our server is up and functioning.",[95,2590,2591],{"className":97,"code":937,"filename":938,"language":100,"meta":101,"style":101},[103,2592,2593,2609,2625,2629,2649,2663,2679,2687,2691,2713,2747,2773,2803,2839,2869,2903,2911],{"__ignoreMap":101},[106,2594,2595,2597,2599,2601,2603,2605,2607],{"class":108,"line":109},[106,2596,945],{"class":173},[106,2598,948],{"class":235},[106,2600,951],{"class":173},[106,2602,954],{"class":127},[106,2604,957],{"class":277},[106,2606,343],{"class":127},[106,2608,141],{"class":127},[106,2610,2611,2613,2615,2617,2619,2621,2623],{"class":108,"line":116},[106,2612,945],{"class":173},[106,2614,968],{"class":235},[106,2616,951],{"class":173},[106,2618,954],{"class":127},[106,2620,975],{"class":277},[106,2622,343],{"class":127},[106,2624,141],{"class":127},[106,2626,2627],{"class":108,"line":131},[106,2628,158],{"emptyLinePlaceholder":157},[106,2630,2631,2633,2635,2637,2639,2641,2643,2645,2647],{"class":108,"line":144},[106,2632,988],{"class":267},[106,2634,271],{"class":235},[106,2636,343],{"class":127},[106,2638,995],{"class":277},[106,2640,343],{"class":127},[106,2642,283],{"class":127},[106,2644,1002],{"class":127},[106,2646,1005],{"class":119},[106,2648,128],{"class":127},[106,2650,2651,2653,2655,2657,2659,2661],{"class":108,"line":154},[106,2652,1012],{"class":267},[106,2654,271],{"class":137},[106,2656,1017],{"class":119},[106,2658,1002],{"class":127},[106,2660,1005],{"class":119},[106,2662,128],{"class":127},[106,2664,2665,2667,2669,2671,2673,2675,2677],{"class":108,"line":161},[106,2666,1028],{"class":173},[106,2668,1031],{"class":235},[106,2670,39],{"class":127},[106,2672,1036],{"class":267},[106,2674,218],{"class":137},[106,2676,353],{"class":127},[106,2678,1043],{"class":112},[106,2680,2681,2683,2685],{"class":108,"line":167},[106,2682,1048],{"class":127},[106,2684,305],{"class":137},[106,2686,141],{"class":127},[106,2688,2689],{"class":108,"line":181},[106,2690,158],{"emptyLinePlaceholder":157},[106,2692,2693,2695,2697,2699,2701,2703,2705,2707,2709,2711],{"class":108,"line":201},[106,2694,1061],{"class":267},[106,2696,271],{"class":137},[106,2698,343],{"class":127},[106,2700,1068],{"class":277},[106,2702,343],{"class":127},[106,2704,283],{"class":127},[106,2706,212],{"class":119},[106,2708,1002],{"class":127},[106,2710,1005],{"class":119},[106,2712,128],{"class":127},[106,2714,2715,2717,2719,2721,2723,2725,2727,2729,2731,2733,2735,2737,2739,2741,2743,2745],{"class":108,"line":207},[106,2716,1085],{"class":119},[106,2718,1088],{"class":235},[106,2720,261],{"class":127},[106,2722,535],{"class":173},[106,2724,1095],{"class":267},[106,2726,271],{"class":137},[106,2728,1100],{"class":235},[106,2730,305],{"class":137},[106,2732,39],{"class":127},[106,2734,1107],{"class":267},[106,2736,271],{"class":137},[106,2738,343],{"class":127},[106,2740,1114],{"class":277},[106,2742,343],{"class":127},[106,2744,305],{"class":137},[106,2746,141],{"class":127},[106,2748,2749,2751,2753,2755,2757,2759,2761,2763,2765,2767,2769,2771],{"class":108,"line":223},[106,2750,1125],{"class":267},[106,2752,271],{"class":137},[106,2754,1130],{"class":235},[106,2756,39],{"class":127},[106,2758,1135],{"class":235},[106,2760,305],{"class":137},[106,2762,39],{"class":127},[106,2764,1142],{"class":267},[106,2766,271],{"class":137},[106,2768,1148],{"class":1147},[106,2770,305],{"class":137},[106,2772,141],{"class":127},[106,2774,2775,2777,2779,2781,2783,2785,2787,2789,2791,2793,2795,2797,2799,2801],{"class":108,"line":245},[106,2776,1125],{"class":267},[106,2778,271],{"class":137},[106,2780,1130],{"class":235},[106,2782,39],{"class":127},[106,2784,1165],{"class":235},[106,2786,305],{"class":137},[106,2788,39],{"class":127},[106,2790,1172],{"class":267},[106,2792,271],{"class":137},[106,2794,274],{"class":127},[106,2796,1179],{"class":277},[106,2798,274],{"class":127},[106,2800,305],{"class":137},[106,2802,141],{"class":127},[106,2804,2805,2807,2809,2811,2813,2815,2817,2819,2821,2823,2825,2827,2829,2831,2833,2835,2837],{"class":108,"line":253},[106,2806,1125],{"class":267},[106,2808,271],{"class":137},[106,2810,1194],{"class":127},[106,2812,1088],{"class":235},[106,2814,39],{"class":127},[106,2816,1165],{"class":235},[106,2818,39],{"class":127},[106,2820,1179],{"class":235},[106,2822,305],{"class":137},[106,2824,39],{"class":127},[106,2826,1142],{"class":267},[106,2828,271],{"class":137},[106,2830,343],{"class":127},[106,2832,1217],{"class":277},[106,2834,343],{"class":127},[106,2836,305],{"class":137},[106,2838,141],{"class":127},[106,2840,2841,2843,2845,2847,2849,2851,2853,2855,2857,2859,2861,2863,2865,2867],{"class":108,"line":310},[106,2842,1125],{"class":267},[106,2844,271],{"class":137},[106,2846,1130],{"class":235},[106,2848,39],{"class":127},[106,2850,1165],{"class":235},[106,2852,39],{"class":127},[106,2854,1179],{"class":235},[106,2856,305],{"class":137},[106,2858,39],{"class":127},[106,2860,1246],{"class":267},[106,2862,271],{"class":137},[106,2864,1251],{"class":1147},[106,2866,305],{"class":137},[106,2868,141],{"class":127},[106,2870,2871,2873,2875,2877,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2901],{"class":108,"line":330},[106,2872,1125],{"class":267},[106,2874,271],{"class":137},[106,2876,1130],{"class":235},[106,2878,39],{"class":127},[106,2880,1165],{"class":235},[106,2882,305],{"class":137},[106,2884,39],{"class":127},[106,2886,1172],{"class":267},[106,2888,271],{"class":137},[106,2890,274],{"class":127},[106,2892,1280],{"class":277},[106,2894,274],{"class":127},[106,2896,283],{"class":127},[106,2898,1288],{"class":1287},[106,2900,305],{"class":137},[106,2902,141],{"class":127},[106,2904,2905,2907,2909],{"class":108,"line":359},[106,2906,1048],{"class":127},[106,2908,305],{"class":137},[106,2910,141],{"class":127},[106,2912,2913,2915,2917],{"class":108,"line":377},[106,2914,1305],{"class":127},[106,2916,305],{"class":235},[106,2918,141],{"class":127},[10,2920,1313],{"id":1312},[15,2922,2923,2925],{},[22,2924,1313],{"href":1318,"target":25}," is a powerful, high-performance software that acts as a\nweb server and reverse proxy.",[15,2927,2928],{},"Nginx, as a web server, can handle HTTP\u002FHTTPS requests and provide static content quickly by sending files from disk to\nnetwork. It is quite effective at delivering static content such as pictures, JavaScript, and CSS files.",[15,2930,2931],{},"Nginx serves as a reverse proxy, directing traffic to different backend services based on URLs or headers. It also\nmanages load balancing across multiple servers. This is particularly useful in microservice designs, where several\nservices handle different portions of a web application.",[15,2933,2934],{},"Thus, using Nginx as a reverse proxy for an Express.js API provides a robust, secure, and efficient way to manage client\nconnections, security, and static content delivery, all of which contribute to a more scalable and maintainable\napplication architecture.",[63,2936,2938],{"id":2937},"setting-up-nginx-configuration-file","Setting up Nginx configuration file",[15,2940,2941,2942,2944],{},"The ",[103,2943,1338],{}," file is the primary configuration file for Nginx. It specifies how the server responds to incoming\nHTTP requests, manages many virtual servers, processes SSL\u002FTLS settings, directs requests to backend apps, and more.\nHere is the server block definition of our nginx.conf file.",[95,2946,2947],{"className":1344,"code":1345,"filename":1346,"language":1312,"meta":101,"style":101},[103,2948,2949,2953,2957,2961,2965,2969,2973,2977,2981,2985,2989,2993,2997,3001,3005,3009,3013,3017,3021,3025,3029,3033,3037,3041,3045],{"__ignoreMap":101},[106,2950,2951],{"class":108,"line":109},[106,2952,1353],{},[106,2954,2955],{"class":108,"line":116},[106,2956,1358],{},[106,2958,2959],{"class":108,"line":131},[106,2960,1363],{},[106,2962,2963],{"class":108,"line":144},[106,2964,1368],{},[106,2966,2967],{"class":108,"line":154},[106,2968,158],{"emptyLinePlaceholder":157},[106,2970,2971],{"class":108,"line":161},[106,2972,1377],{},[106,2974,2975],{"class":108,"line":167},[106,2976,1382],{},[106,2978,2979],{"class":108,"line":181},[106,2980,1387],{},[106,2982,2983],{"class":108,"line":201},[106,2984,158],{"emptyLinePlaceholder":157},[106,2986,2987],{"class":108,"line":207},[106,2988,1396],{},[106,2990,2991],{"class":108,"line":223},[106,2992,1401],{},[106,2994,2995],{"class":108,"line":245},[106,2996,1406],{},[106,2998,2999],{"class":108,"line":253},[106,3000,1411],{},[106,3002,3003],{"class":108,"line":310},[106,3004,1416],{},[106,3006,3007],{"class":108,"line":330},[106,3008,1421],{},[106,3010,3011],{"class":108,"line":359},[106,3012,1426],{},[106,3014,3015],{"class":108,"line":377},[106,3016,1431],{},[106,3018,3019],{"class":108,"line":409},[106,3020,1436],{},[106,3022,3023],{"class":108,"line":418},[106,3024,1441],{},[106,3026,3027],{"class":108,"line":424},[106,3028,1446],{},[106,3030,3031],{"class":108,"line":430},[106,3032,158],{"emptyLinePlaceholder":157},[106,3034,3035],{"class":108,"line":442},[106,3036,1455],{},[106,3038,3039],{"class":108,"line":448},[106,3040,1460],{},[106,3042,3043],{"class":108,"line":453},[106,3044,1465],{},[106,3046,3047],{"class":108,"line":458},[106,3048,427],{},[15,3050,3051,3052,3054,3055,3057,3058,3060,3061,3063],{},"This Nginx configuration listens to port 80 for HTTP traffic and supports both IPv4 and IPv6 connections. It's\nconfigured as a default catch-all server, responding to any HTTP request, and include important security headers:\n",[103,3053,1475],{}," set to ",[103,3056,1478],{}," to prevent against clickjacking attacks, and ",[103,3059,1482],{}," to ",[103,3062,1485],{},"\nto prevent the browser from MIME-sniffing responses that do not match the defined content type.",[15,3065,3066],{},"Additional setting options include caching static files such as uploads folders, SSL\u002FTLS configuration, and, why not,\nrate limits. Maybe we'll cover them in another iteration of this project.",[10,3068,3069],{"id":1492},"Docker compose",[15,3071,3072,3074],{},[22,3073,1493],{"href":1498,"target":25}," is a tool for creating and managing\nmulti-container Docker\napplications. It allows you to configure your application's services, networks, and volumes using a YAML file. Then,\nusing a single command, you can run all the\nservices listed in your configuration.",[63,3076,3078],{"id":3077},"our-project-docker-compose","Our project Docker compose",[95,3080,3081],{"className":1506,"code":1507,"filename":1508,"language":1509,"meta":101,"style":101},[103,3082,3083,3089,3095,3107,3113,3119,3125,3135,3145,3151,3157,3165,3173,3179,3185,3191,3203,3211,3217,3227,3233,3239,3245,3257,3263,3269,3275,3285,3291,3301,3311,3317,3323,3329,3335,3343,3349,3355,3361],{"__ignoreMap":101},[106,3084,3085,3087],{"class":108,"line":109},[106,3086,1516],{"class":137},[106,3088,1519],{"class":127},[106,3090,3091,3093],{"class":108,"line":116},[106,3092,1524],{"class":137},[106,3094,1519],{"class":127},[106,3096,3097,3099,3101,3103,3105],{"class":108,"line":131},[106,3098,1531],{"class":137},[106,3100,291],{"class":127},[106,3102,954],{"class":127},[106,3104,1538],{"class":277},[106,3106,1541],{"class":127},[106,3108,3109,3111],{"class":108,"line":144},[106,3110,1546],{"class":137},[106,3112,1519],{"class":127},[106,3114,3115,3117],{"class":108,"line":154},[106,3116,1553],{"class":127},[106,3118,1556],{"class":277},[106,3120,3121,3123],{"class":108,"line":161},[106,3122,1561],{"class":137},[106,3124,1519],{"class":127},[106,3126,3127,3129,3131,3133],{"class":108,"line":167},[106,3128,1553],{"class":127},[106,3130,954],{"class":127},[106,3132,1572],{"class":277},[106,3134,1541],{"class":127},[106,3136,3137,3139,3141,3143],{"class":108,"line":181},[106,3138,1553],{"class":127},[106,3140,954],{"class":127},[106,3142,1583],{"class":277},[106,3144,1541],{"class":127},[106,3146,3147,3149],{"class":108,"line":201},[106,3148,1590],{"class":137},[106,3150,1519],{"class":127},[106,3152,3153,3155],{"class":108,"line":207},[106,3154,1597],{"class":137},[106,3156,1519],{"class":127},[106,3158,3159,3161,3163],{"class":108,"line":223},[106,3160,1604],{"class":137},[106,3162,291],{"class":127},[106,3164,1609],{"class":1147},[106,3166,3167,3169,3171],{"class":108,"line":245},[106,3168,1614],{"class":137},[106,3170,291],{"class":127},[106,3172,1619],{"class":277},[106,3174,3175,3177],{"class":108,"line":253},[106,3176,1546],{"class":137},[106,3178,1519],{"class":127},[106,3180,3181,3183],{"class":108,"line":310},[106,3182,1553],{"class":127},[106,3184,1556],{"class":277},[106,3186,3187,3189],{"class":108,"line":330},[106,3188,1636],{"class":137},[106,3190,1519],{"class":127},[106,3192,3193,3195,3197,3199,3201],{"class":108,"line":359},[106,3194,1643],{"class":137},[106,3196,291],{"class":127},[106,3198,954],{"class":127},[106,3200,1650],{"class":277},[106,3202,1541],{"class":127},[106,3204,3205,3207,3209],{"class":108,"line":377},[106,3206,1657],{"class":137},[106,3208,291],{"class":127},[106,3210,1662],{"class":277},[106,3212,3213,3215],{"class":108,"line":409},[106,3214,1561],{"class":137},[106,3216,1519],{"class":127},[106,3218,3219,3221,3223,3225],{"class":108,"line":418},[106,3220,1553],{"class":127},[106,3222,954],{"class":127},[106,3224,1677],{"class":277},[106,3226,1541],{"class":127},[106,3228,3229,3231],{"class":108,"line":424},[106,3230,1684],{"class":137},[106,3232,1519],{"class":127},[106,3234,3235,3237],{"class":108,"line":430},[106,3236,1553],{"class":127},[106,3238,1693],{"class":277},[106,3240,3241,3243],{"class":108,"line":442},[106,3242,1698],{"class":137},[106,3244,1519],{"class":127},[106,3246,3247,3249,3251,3253,3255],{"class":108,"line":448},[106,3248,1531],{"class":137},[106,3250,291],{"class":127},[106,3252,954],{"class":127},[106,3254,1711],{"class":277},[106,3256,1541],{"class":127},[106,3258,3259,3261],{"class":108,"line":453},[106,3260,1546],{"class":137},[106,3262,1519],{"class":127},[106,3264,3265,3267],{"class":108,"line":458},[106,3266,1553],{"class":127},[106,3268,1556],{"class":277},[106,3270,3271,3273],{"class":108,"line":464},[106,3272,1730],{"class":137},[106,3274,1519],{"class":127},[106,3276,3277,3279,3281,3283],{"class":108,"line":473},[106,3278,1553],{"class":127},[106,3280,954],{"class":127},[106,3282,1741],{"class":277},[106,3284,1541],{"class":127},[106,3286,3287,3289],{"class":108,"line":490},[106,3288,1561],{"class":137},[106,3290,1519],{"class":127},[106,3292,3293,3295,3297,3299],{"class":108,"line":495},[106,3294,1553],{"class":127},[106,3296,954],{"class":127},[106,3298,1758],{"class":277},[106,3300,1541],{"class":127},[106,3302,3303,3305,3307,3309],{"class":108,"line":509},[106,3304,1553],{"class":127},[106,3306,954],{"class":127},[106,3308,1769],{"class":277},[106,3310,1541],{"class":127},[106,3312,3313,3315],{"class":108,"line":525},[106,3314,1684],{"class":137},[106,3316,1519],{"class":127},[106,3318,3319,3321],{"class":108,"line":546},[106,3320,1553],{"class":127},[106,3322,1784],{"class":277},[106,3324,3325,3327],{"class":108,"line":578},[106,3326,1789],{"class":137},[106,3328,1519],{"class":127},[106,3330,3331,3333],{"class":108,"line":583},[106,3332,1796],{"class":137},[106,3334,1519],{"class":127},[106,3336,3337,3339,3341],{"class":108,"line":593},[106,3338,1803],{"class":137},[106,3340,291],{"class":127},[106,3342,1808],{"class":277},[106,3344,3345,3347],{"class":108,"line":598},[106,3346,1813],{"class":137},[106,3348,1519],{"class":127},[106,3350,3351,3353],{"class":108,"line":1818},[106,3352,1821],{"class":137},[106,3354,1519],{"class":127},[106,3356,3357,3359],{"class":108,"line":1826},[106,3358,1829],{"class":137},[106,3360,1519],{"class":127},[106,3362,3363,3365],{"class":108,"line":1834},[106,3364,1837],{"class":137},[106,3366,1519],{"class":127},[15,3368,3369,3370,1845,3372,3374,3375,3377],{},"Our Docker compose includes three services (",[103,3371,1280],{},[103,3373,1312],{},", and ",[103,3376,1850],{},") connected via a docker network to isolate our\napplication from other projects. The Node.js service is served via the Nginx server, which listens to port 80 by\ndefault (you can use 8000 for development). We also include volumes to store application data. This is critical\nfor the Mongo database since we may need to do backup operations. Long-term retention of application logs may require\nvolumes for nginx and app service.",[10,3379,1855],{"id":1854},[15,3381,3382],{},"To summarize, this post has guided you through a complete technique to deploying an Express using Docker,\nfocusing on key aspects such as MongoDB performance, multi-stage Docker builds, end-to-end testing using Jest, and using\nNginx as a reverse proxy. We've seen how Docker can help to speed the development and deployment process while also\nmaintaining consistency across environments. MongoDB's Singleton style ensures a steady and efficient connection, while\nmulti-stage Docker builds reduce final image size without sacrificing security or functionality. Furthermore,\nincorporating Jest for end-to-end testing ensures that the application is reliable and resilient before it goes live.\nFinally, Nginx as a reverse proxy improves performance while also providing an added layer of protection.",[15,3384,3385],{},"Whether you're an experienced developer or new to Docker, this guide is intended to strike\na balance between simplicity, security, and performance, making it an excellent starting point for delivering scalable\nand efficient web apps.",[1863,3387,3388],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s6hCs, html code.shiki .s6hCs{--shiki-light:#9C3EDA;--shiki-light-font-style:italic;--shiki-default:#C792EA;--shiki-default-font-style:italic;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sFweD, html code.shiki .sFweD{--shiki-light:#E2931D;--shiki-light-font-style:italic;--shiki-default:#FFCB6B;--shiki-default-font-style:italic;--shiki-dark:#FFCB6B;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":101,"searchDepth":116,"depth":116,"links":3390},[3391,3392,3393,3394,3398,3403,3404,3407,3410],{"id":12,"depth":116,"text":13},{"id":30,"depth":116,"text":31},{"id":42,"depth":116,"text":43},{"id":1940,"depth":116,"text":1941,"children":3395},[3396,3397],{"id":1951,"depth":131,"text":1952},{"id":1966,"depth":131,"text":1967},{"id":626,"depth":116,"text":627,"children":3399},[3400,3401,3402],{"id":636,"depth":131,"text":637},{"id":2387,"depth":131,"text":2388},{"id":2410,"depth":131,"text":2411},{"id":2564,"depth":116,"text":2565},{"id":1312,"depth":116,"text":1313,"children":3405},[3406],{"id":2937,"depth":131,"text":2938},{"id":1492,"depth":116,"text":3069,"children":3408},[3409],{"id":3077,"depth":131,"text":3078},{"id":1854,"depth":116,"text":1855}," How to deploy Express.js RESTFull API using Docker, with a focus on MongoDB performance, docker multi-stage builds, Jest for testing, and Nginx as a reverse proxy.",{},"\u002Fdevops\u002Fdeploy-expressjs-api-using-docker",{"title":1909,"description":3411},"devops\u002F1.deploy-expressjs-api-using-docker",[1898,1899,1900,1901,1902,627],[1904,1905],"Eo7TM6ggHf7TWPukwN6WUbKL5pWMn_LGZbXst24UHhg",[3420,3423],{"title":3421,"path":3422},"Mon parcours vers la certification AWS Cloud Practitioner","\u002Fcloud\u002Faws\u002Fhow-i-passed-clf-exam.fr",{"title":3424,"path":3425},"Mettre en place un cluster MongoDB Replica Set à 3 nœuds avec Docker Compose","\u002Fdevops\u002Fset-up-mongodb-replica-with-docker.fr",[3427,3437,3443],{"path":3428,"title":3429,"description":3430,"date":3431,"tags":3432,"topics":3436},"\u002Fdevops\u002Fbackup-and-restore-mongodb-in-docker-environment.fr","Sauvegarder et restaurer MongoDB dans un environnement Docker","Comment créer une sauvegarde complète d'une base MongoDB qui tourne dans un conteneur Docker et restaurer la sauvegarde dans un nouveau conteneur MongoDB.","2024-07-18",[43,627,3433,3434,3435],"Docker-compose","Backup","Restore",[1905,626,42],{"path":3425,"title":3424,"description":3438,"date":3439,"tags":3440,"topics":3442},"Comment mettre en place un cluster MongoDB replica set à 3 nœuds avec Docker Compose. Apprends ce qu'est un replica set MongoDB, les prérequis, et les étapes pour créer un fichier Docker Compose qui le configure.","2024-07-17",[43,3441,627,3433],"Replica-Set",[1905,626,42],{"path":3444,"title":3445,"description":3446,"date":3447,"tags":3448,"topics":3451},"\u002Fbackend\u002Fnest-js\u002Funlocking-the-power-of-relationships-with-typeorm.fr","Maîtriser NestJS : libérer la puissance des relations avec TypeORM et les bases SQL","Libère la puissance des relations de données avec NestJS, TypeORM et les bases SQL. Maîtrise l'art de construire des structures de données complexes et des interactions fluides. Idéal pour les développeurs NestJS expérimentés comme pour les débutants qui veulent créer des applications à la pointe.","2023-10-18",[3449,3450,1899],"Nest-JS","Mirco-service",[3452,1904],"nest-js",1780074488338]