{"id":16371037,"url":"https://github.com/srealmoreno/api-express","last_synced_at":"2026-04-13T14:33:31.080Z","repository":{"id":103556213,"uuid":"381904289","full_name":"srealmoreno/api-express","owner":"srealmoreno","description":"Crear API utilizando Nodejs con Express y mysql en docker","archived":false,"fork":false,"pushed_at":"2022-06-25T16:12:36.000Z","size":3374,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-01T04:25:17.406Z","etag":null,"topics":["api","docker","express","github","learn","mysql","node","student-vscode"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/srealmoreno.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-01T04:03:40.000Z","updated_at":"2022-08-01T06:23:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"d388efae-82ae-44c0-bfc3-bbf35f35c969","html_url":"https://github.com/srealmoreno/api-express","commit_stats":{"total_commits":19,"total_committers":1,"mean_commits":19.0,"dds":0.0,"last_synced_commit":"2a3e47b3c54adb80716ff4c9a67caf1ea12d9fad"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/srealmoreno/api-express","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srealmoreno%2Fapi-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srealmoreno%2Fapi-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srealmoreno%2Fapi-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srealmoreno%2Fapi-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/srealmoreno","download_url":"https://codeload.github.com/srealmoreno/api-express/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srealmoreno%2Fapi-express/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31757481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T13:27:56.013Z","status":"ssl_error","status_checked_at":"2026-04-13T13:21:23.512Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","docker","express","github","learn","mysql","node","student-vscode"],"created_at":"2024-10-11T03:06:49.125Z","updated_at":"2026-04-13T14:33:30.677Z","avatar_url":"https://github.com/srealmoreno.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"![#](https://img.shields.io/badge/%20-api-pink) ![#](https://img.shields.io/badge/%20-Node-grey) ![#](https://img.shields.io/badge/%20-Docker-blue) ![#](https://img.shields.io/badge/%20-Express-green) ![#](https://img.shields.io/badge/%20-Mysql-lightblue) ![#](https://img.shields.io/badge/Tutoriales-Srealmoreno-red?style=flat\u0026logo=github)\n\n# Crear una api utilizando express y mysql sobre docker\n\nEn este pequeño tutorial crearemos una api de usuarios utilizando Nodejs con express en **Ubuntu** 20.04 LTS.\nPor razones de entendimiento algunas cosas muy puntuales las dejaré en inglés y me limitaré a dar una explicación breve ya que este tutorial se haría muy extenso.\n\n## Indíce\n\n- [Conocimientos preliminares](#conocimientos-preliminares)\n- [Requisitos](#requisitos)\n- [Dependencias](#dependencias)\n  - [Instalación](#instalación-de-dependencias)\n  - [Extensiones de vscode](#instalar-extensiones-en-vscode)\n- [Iniciando el proyecto](#iniciando-el-proyecto)\n- [Añadir variables de entorno](#añadir-variables-de-entorno)\n- [Mysql](#mysql)\n  - [Crear conexión mysql en vscode](#crear-conexión-mysql-en-vscode)\n  - [Crear base de datos](#crear-base-de-datos-y-usuario-en-mysql)\n  - [Ejecutar script sql](#ejecutar-script-sql)\n  - [Módulo de mysql](#módulo-de-mysql)\n- [Index.js](#index.js)\n  - [Importación de módulos y declaración de constantes](#1-importación-de-módulos-y-declaración-de-constantes)\n  - [Declaración de formato de mensajes de respuesta](#2-declaración-de-formato-de-mensajes-de-respuesta)\n  - [Declaración de métodos de comprobación](#3-declaración-de-métodos-de-comprobación)\n  - [Manejo de excepciónes de la base de datos](#4-manejo-de-excepciónes-de-la-base-de-datos)\n  - [Declaración de métodos HTTP en nuestro servidor](#5-declaración-de-métodos-http-en-nuestro-servidor)\n    - [GET](#get)\n    - [POST](#post)\n    - [PUT](#get)\n    - [DELETE](#delete)\n  - [Poner en escucha el servidor](#6-poner-en-escucha-el-servidor)\n- [Código fuente completo](#código-fuente-completo)\n- [Poner en marcha nuestro servidor](#poner-en-marcha-nuestro-servidor)\n- [Pruebas](#pruebas)\n  - [Crear colección en Thunder Client](#crear-colección-en-thunder-client)\n    - [GET](#crear-solicitud-get)\n    - [POST](#crear-solicitud-post)\n    - [PUT](#crear-solicitud-put)\n    - [DELETE](#crear-solicitud-delete)\n  - [Colección completa de Thunder Client](#colección-completa-de-thunder-client)\n  - [Ejecución](#ejecución-de-pruebas)\n    - [POST](#ejecución-solicitud-post)\n    - [GET](#ejecución-solicitud-get)\n    - [PUT](#ejecución-solicitud-put)\n    - [DELETE](#ejecución-solicitud-delete)\n\n---\n\n## Conocimientos preliminares\n\nNecesitamos tener conocimientos acerca de algunos conceptos claves que utilizaremos en este proyecto:\n\nSi tienes conocimientos de estos temas, puedes omitir la lectura.\n\n- [Protocolo HTTP](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#protocolo-http)\n- [JavaScript](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#javascript)\n- [Mysql](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#mysql)\n- [Json](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#json)\n\nPuedes leerlos en la [WIKI](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares) del proyecto\n\n---\n\n## Requisitos\n\n- Distribución Debian, Ubuntu o derivados\n- Conocimientos básicos de operaciones CRUD en mysql\n- Conocimientos básicos HTTP/1.1\n- Conocimientos básicos de JavaScript (EcmaScript 6)\n- Visual studio code\n\n---\n\n## Dependencias\n\n1. Git\n2. Nodejs\n3. npm\n4. Docker\n\n---\n\n### Instalación de dependencias\n\nEl script se encargara de instalar las dependencias necesarias para el proyecto, en una terminal ejecutar lo siguiente:\n\n```bash\nsudo apt install git\n\ngit clone https://github.com/srealmoreno/api-express.git\n\ncd api-express\n\nchmod +x build/build.sh\n\nsudo build/build.sh\n```\n\n---\n\n### Instalar extensiones en vscode\n\nEn visual studio code debes de buscar e instalar las siguientes extensiones\n\n- ms-azuretools.vscode-docker\n\n![Instalar extensión Docker en vscode](assets/install_docker_extension.gif)\n\n- cweijan.vscode-mysql-client2\n\n![Instalar extensión Mysql en vscode](assets/install_mysql_extension.gif)\n\n- rangav.vscode-thunder-client\n\n![Instalar extensión Thunder cliente en vscode](assets/install_thunder_client_extension.gif)\n\n---\n\nSi deseas ahorrarte la creación del código fuente del proyecto, ejecuta esto en la terminal\n\n```bash\ngit checkout finished\n\nnpm install\n```\n\nLuego sigue solamente estos pasos:\n\n[Ir a rama finished](https://github.com/srealmoreno/api-express/tree/finished)\n\n- [Crear conexión mysql en vscode](https://github.com/srealmoreno/api-express/tree/finished#crear-conexión-mysql-en-vscode)\n- [Ejecutar script sql](https://github.com/srealmoreno/api-express/tree/finished#ejecutar-script-sql)\n- [Poner en marcha nuestro servidor](https://github.com/srealmoreno/api-express/tree/finished#poner-en-marcha-nuestro-servidor)\n- [Importar Tests Thunder en vscode](https://github.com/srealmoreno/api-express/tree/finished#colección-completa-de-thunder-client) (puedes encontrar el archivo en '**tests/thunder_test.json**')\n- [Ejecución de Test](https://github.com/srealmoreno/api-express/tree/finished#ejecución-de-pruebas)\n\n## Iniciando el proyecto\n\nDebemos inicializar un proyecto utilizando npm, instalar dependencias y crear los archivos **db.sql** **db.js** **index.js** **.env**, en la terminal que tenemos abierta ejecutar lo siguiente:\n\n```bash\nnpm init -y\nnpm install express mysql dotenv -E\nnpm install nodemon -E -D\ntouch db.sql db.js index.js .env\ncode .\n```\n\nModificar el archivo **package.json**, agregar la linea **\"start\"** y **\"dev\"**\n\n```json\n\"scripts\": {\n    \"start\": \"node index.js\",\n    \"dev\": \"nodemon node index.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\"\n}\n```\n\n---\n\n## Añadir variables de entorno\n\nDebemos definir algunas variables de entorno que necesitará nuestro proyecto, agrega el siguiente código en el archivo **.env**\n\n```env\nNODE_PORT=3000\nNODE_IP=127.0.0.1\n\nMYSQL_PORT=3306\nMYSQL_HOST=127.0.0.1\nMYSQL_USER=express_api\nMYSQL_PASSWORD=express_api\nMYSQL_DATABASE=express_api\n```\n\nPara poder obtener las variables debemos importar el módulo 'dotenv' en el archivo principal del proyecto (index.js) y accedemos a ellas escribiendo \"process.env.\" antes del nombre de la variable, e.j\n\n```javascript\nrequire('dotenv').config()\n\nconst IP = process.env.NODE_IP\nconst PORT = process.env.NODE_PORT\n```\n\n---\n\n## Comprobar conexión con docker\n\nEn el apartado de [docker](#instalar-extensiones-en-vscode) (icono de la ballena) debemos de tener un contenedor **mysql:8.0.25 node-mysql-api** como la siguiente imagen\n\n![Comprobar conexión con imagen de docker](assets/check_docker_connection.gif)\n\n---\n\n## Mysql\n\n### Crear conexión mysql en vscode\n\nEn el apartado de [EXPLORER:DATABASE](#instalar-extensiones-en-vscode) (icono del barril) debemos de crear una nueva conexión con mysql\n\n![Comprobar conexión con imagen de docker](assets/new_connection_mysql.gif)\n\nIngresar rellenar con los siguientes campos:\n\nLa contraseña es tu nombre de usuario. e.j: mi nombre de usuario es \"**srealmoreno**\" entonces la contraseña es **srealmoreno**\n\n|                       |             |\n| --------------------- | ----------- |\n| **Connection Name**   | mysql_root  |\n| **Connection Target** | global      |\n| **Database Type**     | mysql       |\n| **Host**              | 127.0.0.1   |\n| **Port**              | 3306        |\n| **Username**          | root        |\n| **Password**          | tu usuario  |\n| **Databases**         |             |\n| **Include Databases** |             |\n| **ConnectTimeout**    | 5000        |\n| **RequestTimeout**    | 10000       |\n| **Timezone**          | +00:00      |\n| **SSH Tunnel**        | desactivado |\n| **Use SSL**           | desactivado |\n\n![Comprobar conexión con imagen de docker](assets/new_connection_mysql_values.png)\n\n---\n\n### Crear base de datos y usuario en mysql\n\nDebemos crear un script sql que contenga las instrucciones para crear nuestra base de datos y nuestro usuario\n\nEn este tutorial crearemos una base de datos de usuarios, agrega el siguiente código al archivo **db.sql**\n\n```sql\n-- Crear base de datos solo si no existe llamada 'express_api'\nCREATE DATABASE IF NOT EXISTS express_api;\n\n-- Usar la base de datos anteriormente creada\nUSE express_api;\n\n-- Crear tabla si no existe llamada 'usuarios' con los siguientes atributos:\n-- 1. 'id' de tipo entero sin signo, que sea una llave primaria   y auto incrementable\n-- 2. 'nombre' de tipo varchar con longitud de 30 caracteres   y que no sea NULL\n-- 3. 'apellido' de tipo varchar con longitud de 30 caracteres y que no sea NULL\n-- 4. 'correo' de tipo varchar con longitud de 40 caracteres\nCREATE TABLE IF NOT EXISTS usuarios (\n    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n    nombre VARCHAR(30) NOT NULL,\n    apellido VARCHAR(30) NOT NULL,\n    correo VARCHAR(50)\n);\n\n-- Crear Usuario si no existe llamado 'express_api' y que\n-- sea accesible desde cualquier parte con contraseña nativa 'express_api'\nCREATE USER IF NOT EXISTS 'express_api' @'%' IDENTIFIED WITH mysql_native_password BY 'express_api';\n\n-- Otorgarle permisos totales (CREATE, DROP, DELETE, INSERT, SELECT, UPDATE)\n-- al usuario 'express_api' sobre la tabla anteriormente creada 'usuarios'\nGRANT ALL PRIVILEGES on usuarios TO 'express_api' @'%';\n\n-- Nota: si deseas utilizar el usuario solo en localhost, cambia\n-- el % por la palabra localhost en las dos consultas anteriores\n\n-- Recargar todos los permisos para actualizar el que hemos creado anteriormente\nFLUSH PRIVILEGES;\n```\n\n---\n\n### Ejecutar script sql\n\nEn vscode vamos a presionar las teclas \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eP\u003c/kbd\u003e, escribiremos **Change active database** y escogeremos \u003ckbd\u003emysql_root#mysql\u003c/kbd\u003e\n\n![Cambiar base de datos activa](assets/change_active_db.gif)\n\nPresionar las las teclas \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eEnter\u003c/kbd\u003e para ejecutar el script\n\n![Cambiar base de datos activa](assets/execute_sql_script.gif)\n\n### Utilizar base de datos creada\n\nAhora que tenemos la base de datos y el usuario creado, crear nueva conexión con los siguientes valores:\n\n|                       |             |\n| --------------------- | ----------- |\n| **Connection Name**   | mysql_api   |\n| **Connection Target** | global      |\n| **Database Type**     | mysql       |\n| **Host**              | 127.0.0.1   |\n| **Port**              | 3306        |\n| **Username**          | express_api |\n| **Password**          | express_api |\n| **Databases**         |             |\n| **Include Databases** | express_api |\n| **ConnectTimeout**    | 5000        |\n| **RequestTimeout**    | 10000       |\n| **Timezone**          | +00:00      |\n| **SSH Tunnel**        | desactivado |\n| **Use SSL**           | desactivado |\n\nAhora debemos cambiar la base de datos activa:  \n\u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eP\u003c/kbd\u003e, escribiremos **Change active database** y escogeremos \u003ckbd\u003emysql_api#express_api\u003c/kbd\u003e\n\n---\n\n### Módulo de mysql\n\nagrega el siguiente código al archivo **db.js**:\n\n```javascript\nconst { promisify } = require(\"util\")\nconst { createPool } = require(\"mysql\")\n\nconst credenciales = {\n  port: process.env.MYSQL_PORT,\n  host: process.env.MYSQL_HOST,\n  user: process.env.MYSQL_USER,\n  password: process.env.MYSQL_PASSWORD,\n  database: process.env.MYSQL_DATABASE\n}\n\nconst pool = createPool(credenciales)\n\npool.queryPromisify = promisify(pool.query)\n\nmodule.exports = pool\n```\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Por qué las variables se declaran con \u003ckbd\u003e{}\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#desestructuración)  \n\u003e [¿Qué significa **pool.queryPromisify** en el código?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#añadir-nuevo-método-a-un-objeto)  \n\u003e [¿Qué significa **process.env**?](#añadir-variables-de-entorno)  \n\u003e [¿Qué es **promisify** en Nodejs?](https://medium.com/@suyashmohan/util-promisify-in-node-js-v8-d07ef4ea8c53)  \n\u003e [¿Cúal es la diferencia entre utilizar un pool y una conexión a la base de datos?](https://es.stackoverflow.com/questions/359715/cu%C3%A1l-ser%C3%ADa-la-diferencia-entre-usar-un-pool-o-usar-una-conexion-tradicional-a-l)\n\n---\n\n## Index.js\n\nEl archivo index.js es nuestro archivo principal, en este declaramos nuestra API. abre el archivo **index.js** y sigue los siguientes pasos:\n\n---\n\n### 1. Importación de módulos y declaración de constantes\n\n- Importamos el módulo de express y [nuestro módulo](#módulo-de-mysql) de la conexión a la base de datos.  \n- Declaramos una dirección **IP** y un **Puerto** donde estará escuchando nuestra aplicación.  \n- Indicarle a express que decodifique los datos que nos envían a través de una [solicitud HTTP](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#protocolo-http)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\nrequire('dotenv').config()\nconst express = require(\"express\")\nconst database = require(\"./db.js\")\nconst { urlencoded, json } = express\nconst app = express()\n\nconst { NODE_IP: IP, NODE_PORT: PORT } = process.env\n\napp.use(urlencoded({ extended: false }))\napp.use(json())\n```\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Por qué las variables se declaran con \u003ckbd\u003e{}\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#desestructuración)  \n\u003e [¿Qué significa **process.env**?](#añadir-variables-de-entorno)  \n\u003e [¿Que significa **urlencoded()** y **json()**?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#insert-set)\n\n---\n\n### 2. Declaración de formato de mensajes de respuesta\n\n- Declaramos 2 [nuevos métodos](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#añadir-nuevo-método-a-un-objeto) para los objetos de tipo **response** que enviarán un [JSON](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#json) con la estructura de nuestros mensajes\n\n- Para el caso de [**éxito**](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#jsonapi)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\nexpress.response.sendMessage = function (data = undefined) {\n    const body = {\n        success: true,\n        status: \"success\"\n    }\n\n    if (data !== undefined)\n        body[\"data\"] = data\n\n    this.status(200).json(body)\n}\n```\n\n- Para el caso de [**error**](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#jsonapi)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\nexpress.response.sendError = function (code, message) {\n    const body = {\n        success: false,\n        status: \"failed\",\n        error: {\n            code: code,\n            message: message\n        }\n    }\n\n    this.status(code).json(body)\n}\n```\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **response**?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-mensaje-http)  \n\u003e [¿Que significa **status()**?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#códigos-de-estado-http)\n\n---\n\n### 3. Declaración de métodos de comprobación\n\n- Declaramos un [nuevo método](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#añadir-nuevo-método-a-un-objeto) para los objetos de tipo **request** que comprobarán si los [datos](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#http-request) que nos envían a través de un [POST](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http) o [PUT](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http) están vacíos\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\nexpress.request.isBodyEmpty = function () {\n    return Object.keys(this.body).length === 0\n}\n```\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **request**?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-mensaje-http)  \n\n---\n\n### 4. Manejo de excepciónes de la base de datos\n\n- Declaramos un objeto **mysqlErrors** que contiene un método para manejar una excepción especifica.\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\nconst mysqlErrors = {\n    ER_NO_DEFAULT_FOR_FIELD: (res, errorMessage) =\u003e {\n        res.sendError(400, \"Bad request, \" + errorMessage)\n    },\n\n    ER_BAD_FIELD_ERROR: (res, errorMessage) =\u003e {\n        res.sendError(400, \"Bad request, \" + errorMessage)\n    },\n\n    ER_DUP_ENTRY: (res, errorMessage) =\u003e {\n        res.sendError(409, \"Conflict, \" + errorMessage)\n    }\n}\n```\n\n| Error | Descripción |\n| --- | --- |\n| **ER_NO_DEFAULT_FOR_FIELD**| Este error ocurre cuando **omitimos** un campo y este está declarado como **NOT NULL** y además **NO** tiene un valor por defecto |\n| **ER_BAD_FIELD_ERROR**| Este error ocurre cuando se desea **asignar** un campo **desconocido** a una tabla\n| **ER_DUP_ENTRY**| Este error ocurre cuando se desea **actualizar** un **ID único** y otro registro ya lo tiene asignado\n\n---\n\n### 5. Declaración de métodos HTTP en nuestro servidor\n\nPara declarar los [métodos HTTP](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http) debemos de especificarlo con un \u003ckbd\u003e.\u003c/kbd\u003e seguido de el tipo de método.  \n\nCada [método HTTP](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http) debe de tener 2 argumentos:\n\n1. **string**: Path [URI](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#http-request)\n2. **método**: Manejador del método HTTP [arrow Functions](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#funciones-arrow)\n\nTodo manejador (handler) recibirá por lo menos 2 argumentos:\n\n1. **req** Un Objeto de tipo _express.[request](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-mensaje-http)_\n2. **res** Un Objeto de tipo _express.[request](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-mensaje-http)_\n\nPara acceder a las variables de los Objetos tipo request tenemos 3 maneras diferentes.\n\n| Manera        | Descripción                | Método HTTP | Ejemplo                                      |\n| ------------- | -------------------------- | ----------- | -------------------------------------------- |\n| req.body.id   | Variable en los datos HTTP | POST\\|PUT   | Enviar un formulario HTML con el método POST |\n| req.query.id  | Variable en la URL         | ANY         | /api/usuario?id=1                            |\n| req.params.id | Variable en la URI         | ANY         | /api/usuario/:id                             |\n\nNuestra [URI](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#http-request) será **\"/api/usuarios\"**\n\n---\n\n#### [GET](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\n// Obtener todos los usuarios\napp.get(\"/api/usuarios\", async (req, res) =\u003e {\n\n    console.log(\"Obtener todos los usuarios\")\n\n    try {\n        const usuarios = await database.queryPromisify(\"SELECT * FROM usuarios\")\n\n        if (usuarios.length === 0)\n            return res.sendError(404, \"Empty list\")\n\n        return res.sendMessage(usuarios)\n\n    } catch (error) {\n        console.error(error)\n\n        return res.sendError(500, \"Internal Server Error, \" + error.message)\n    }\n})\n\n// Obtener usuario por un ID pasado por la URL (req.params)\napp.get(\"/api/usuarios/:id\", async (req, res) =\u003e {\n    console.log(\"Obtener usuario por id \" + req.params.id)\n\n    try {\n        const [usuario] = await database.queryPromisify(\n            \"SELECT * FROM usuarios WHERE id = ?\", [req.params.id]\n        )\n\n        if (usuario ===  undefined)\n            return res.sendError(404, \"Not found\")\n\n        return res.sendMessage(usuario)\n    } catch (error) {\n        console.error(error)\n\n        return res.sendError(500, \"Internal Server Error, \" + error.message)\n    }\n})\n```\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **res** y **req**?](#5-declaración-de-métodos-http-en-nuestro-servidor)  \n\u003e [¿Qué significa **aync** y **await** en el código?](http://farzicoder.com/util-promisify-in-Node-js-v8/#Async-amp-Await)  \n\u003e [¿Qué significa **?** y el array en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#sql-injection)\n\n---\n\n#### [POST](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\n// Guardar un nuevo usuario (req.body)\napp.post(\"/api/usuarios\", async (req, res) =\u003e {\n\n    console.log(\"Guardar un nuevo usuario\")\n\n    if (req.isBodyEmpty())\n        return res.sendError(400, \"Bad request, empty data\")\n\n    try {\n        await database.queryPromisify(\"INSERT INTO usuarios SET ?\", [req.body])\n\n        return res.sendMessage()\n    } catch (error) {\n        console.error(error)\n\n        if (mysqlErrors[error.code])\n            return mysqlErrors[error.code](res, error.message)\n        else\n            return res.sendError(500, \"Internal Server Error, \" + error.message)\n    }\n})\n```\n\n**error.code**: es un String, es el **nombre del error**  \nComprobamos si el error **existe** en nuestro objeto mysqlErrors. **Si existe**, **ejecutamos** el método asociado a ese error. **Si no existe**, enviamos el error \"Internal Server Error\"\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **res** y **req**?](#5-declaración-de-métodos-http-en-nuestro-servidor)  \n\u003e [¿Qué significa **aync** y **await** en el código?](http://farzicoder.com/util-promisify-in-Node-js-v8/#Async-amp-Await)  \n\u003e [¿Qué significa **SET** en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#insert-set)  \n\u003e [¿Qué significa **?** y el array en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#sql-injection)\n\n---\n\n#### [PUT](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\n// Actualizar usuario por un ID pasado por la URL\napp.put(\"/api/usuarios/:id\", async (req, res) =\u003e {\n\n    console.log(\"Actualizar usuario por id \" + req.params.id)\n\n    if (req.isBodyEmpty())\n        return res.sendError(400, \"Bad request, empty data\")\n\n    try {\n\n        const { affectedRows } = await database.queryPromisify(\n            \"UPDATE usuarios SET ? WHERE id = ?\", [req.body, req.params.id]\n        )\n\n        if (affectedRows !== 0)\n            return res.sendMessage()\n        else\n            return res.sendError(404, \"Not found\")\n\n    } catch (error) {\n        console.error(error)\n\n        if (mysqlErrors[error.code])\n            return mysqlErrors[error.code](res, error.message)\n        else\n            return res.sendError(500, \"Internal Server Error, \" + error.message)\n    }\n})\n```\n\n**affectedRows**: (Filas afectadas) es un Int que nos indicará la cantidad de registros que fueron **actualizados**.  \nSi esa variable es **igual a _0_**, quiere decir que **no existe** ningún registro con el ID pasado por parámetro.\n\n**error.code**: es un String, es el **nombre del error**  \nComprobamos si el error **existe** en nuestro objeto mysqlErrors. **Si existe**, **ejecutamos** el método asociado a ese error. **Si no existe**, enviamos el error \"Internal Server Error\"\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **res** y **req**?](#5-declaración-de-métodos-http-en-nuestro-servidor)  \n\u003e [¿Por qué la variable **affectedRows** se declara entre \u003ckbd\u003e{}\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#desestructuración)  \n\u003e [¿Qué significa **aync** y **await** en el código?](http://farzicoder.com/util-promisify-in-Node-js-v8/#Async-amp-Await)  \n\u003e [¿Qué significa **SET** en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#insert-set)  \n\u003e [¿Qué significa **?** y el array en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#sql-injection)\n\n---\n\n#### [DELETE](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#tipos-de-métodos-http)\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\n// Eliminar un usuario por un ID pasado por la URL (req.params)\napp.delete(\"/api/usuarios/:id\", async (req, res) =\u003e {\n\n    console.log(\"Eliminar usuario por id \" + req.params.id)\n\n    try {\n\n        const { affectedRows } = await database.queryPromisify(\n            \"DELETE FROM usuarios WHERE id = ?\", [req.params.id]\n        )\n\n        if (affectedRows !== 0)\n            return res.sendMessage()\n        else\n            return res.sendError(404, \"Not found\")\n\n    } catch (error) {\n        console.error(error)\n\n        return res.sendError(500, \"Internal Server Error, \" + error.message)\n    }\n})\n```\n\n**affectedRows**: (Filas afectadas) es un Int que nos indicará la cantidad de registros que fueron **eliminados**.  \nSi esa variable es **igual a _0_**, quiere decir que **no existe** ningún registro con el ID pasado por parámetro.\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que significa **res** y **req**?](#5-declaración-de-métodos-http-en-nuestro-servidor)  \n\u003e [¿Por qué la variable **affectedRows** se declara entre \u003ckbd\u003e{}\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#desestructuración)  \n\u003e [¿Qué significa **aync** y **await** en el código?](http://farzicoder.com/util-promisify-in-Node-js-v8/#Async-amp-Await)  \n\u003e [¿Qué significa **SET** en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#insert-set)  \n\u003e [¿Qué significa **?** y el array en la consulta?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#sql-injection)\n\n---\n\n### 6. Poner en escucha el servidor\n\nDebemos de indicarle al servidor que este en modo listening en el puerto y dirección ip declarada en el paso 1 y además cuando llegue una ruta desconocida, enviará el el código 404 not found\n\nAgrega el siguiente código al archivo **index.js**\n\n```javascript\napp.use((req, res) =\u003e {\n    res.sendError(404, \"Not found, \" + req.path)\n})\n\napp.listen(PORT, IP, () =\u003e console.log(`Listening in http://${IP}:${PORT}`))\n```\n\n---\n\n## Código fuente completo\n\nPackage json: [package.json](https://github.com/srealmoreno/api-express/raw/finished/package.json)  \nScript sql: [db.sql](https://github.com/srealmoreno/api-express/raw/finished/db.sql)  \nMódulo de la base de datos: [db.js](https://github.com/srealmoreno/api-express/raw/finished/db.js)  \nArchivo principal: [index.js](https://github.com/srealmoreno/api-express/raw/finished/index.js)  \n\n---\n\n## Poner en marcha nuestro servidor\n\nEn vscode vamos a presionar las teclas \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eShift\u003c/kbd\u003e + \u003ckbd\u003eP\u003c/kbd\u003e, luego escribir 'Alternar Terminal'\n\nEjecutamos lo siguiente en la terminal:\n\n```bash\nnpm start\n```\n\n![Abrir terminal integrada](assets/open_integrated_terminal.gif)\n\nSi deseamos que nuestro servidor se reinicie automáticamente cada vez que modifiquemos cualquier archivo del proyecto ejecutamos\n\n```bash\nnpm run dev\n```\n\nSi podemos ver el texto 'Listening in [http://127.0.0.1:3000](##)' quiere decir que nuestro servidor inició correctamente.\n\nAhora debemos ocultar la terminal haciendo click en el botón \u003ckbd\u003eX\u003c/kbd\u003e\n\n![Ocultar terminal integrada](assets/close_integrated_terminal.gif)\n\n---\n\n## Pruebas\n\nAhora que tenemos nuestro servidor en funcionamiento debemos hacer unas pruebas.  \n\n---\n\n### Crear colección en Thunder Client\n\nUna colección es un grupo de solicitudes.  \nEn el apartado de [Thunder Client](#instalar-extensiones-en-vscode) (icono de rayo) debemos crear una nueva colección con nombre **Test node-api**\n\n![Nueva colección](assets/new_collection.gif)\n\n---\n\n#### Crear solicitud GET\n\nEn nuestra colección crearemos un nuevo request con nombre **Obtener Usuarios**\n\n![Nueva solicitud](assets/new_request.gif)\n\nRellena con los siguientes datos:\n\n|            |                                          |\n| ---------- | ---------------------------------------- |\n| **url**    | [http://127.0.0.1:3000/api/usuarios](##) |\n| **Método** | \u003ckbd\u003eGET\u003c/kbd\u003e                           |\n\nEn la pestaña de \u003ckbd\u003eHeaders\u003c/kbd\u003e rellena con los siguientes datos:\n\n|            |                             |\n| ---------  | --------------------------- |\n| **Accept** | \u003ckbd\u003eapplication/json\u003c/kbd\u003e |\n\n![GET](assets/request_get.gif)\n\nEn la pestaña de \u003ckbd\u003eTests\u003c/kbd\u003e rellena con los siguientes datos:\n\n|                         |                  |                                 |\n| ----------------------- | ---------------- | ------------------------------- |\n| \u003ckbd\u003eResponseCode\u003c/kbd\u003e | \u003ckbd\u003eEqual\u003c/kbd\u003e | 200                             |\n| \u003ckbd\u003eContentType\u003c/kbd\u003e  | \u003ckbd\u003eEqual\u003c/kbd\u003e | application/json; charset=utf-8 |\n| json.success            | \u003ckbd\u003eEqual\u003c/kbd\u003e | true                            |\n| json.status             | \u003ckbd\u003eEqual\u003c/kbd\u003e | sucess                          |\n\ny por último \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eS\u003c/kbd\u003e para guardar\n\n![Tests](assets/request_tests.gif)\n\n\u003e Algunas dudas que quizás tengas:  \n\u003e [¿Que es \u003ckbd\u003eResponseCode\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#http-response)  \n\u003e [¿Que es \u003ckbd\u003eContentType\u003c/kbd\u003e?](https://github.com/srealmoreno/api-express/wiki/Conocimientos-preliminares#http-response)  \n\u003e [¿Qué es json.success y json.status?](#2-declaración-de-formato-de-mensajes-de-respuesta)  \n\n---\n\n#### Crear solicitud POST\n\nDuplica el request anterior y cambiale el nombre a **Guardar Usuario**\n![Solicitud GET](assets/duplicate_request.gif)\n\nRellena con los siguientes datos:\n\n|            |                  |\n| ---------- | ---------------- |\n| **Método** | \u003ckbd\u003ePOST\u003c/kbd\u003e  |\n\nEn la pestaña de \u003ckbd\u003eBody\u003c/kbd\u003e, escogeremos la opción \u003ckbd\u003eForm-encodec\u003c/kbd\u003e y rellena con los siguientes datos:\n\n|              |               |\n| ------------ | ------------- |\n| **nombre**   | _Tu nombre_   |\n| **apellido** | _Tu apellido_ |\n| **correo**   | _Tu correo_   |\n\ny por último \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eS\u003c/kbd\u003e para guardar\n\n![Solicitud POST](assets/request_post.gif)\n\n---\n\n#### Crear solicitud PUT\n\nDuplica el request **Guardar Usuario** y cambiale el nombre a **Actualizar Usuario**\n\nRellena con los siguientes datos:\n\nRecuerda que en este método debemos de [indicarle el ID por la URL](#put) en este caso el ID será: **1**\n\n|            |                                            |\n| ---------- | ------------------------------------------ |\n| **url**    | [http://127.0.0.1:3000/api/usuarios/1](##) |\n| **Método** | \u003ckbd\u003ePUT\u003c/kbd\u003e                            |\n\nEn la pestaña de \u003ckbd\u003eBody\u003c/kbd\u003e, escogeremos la opción \u003ckbd\u003eForm-encodec\u003c/kbd\u003e y rellena con los siguientes datos:\n\n|              |                 |\n| ------------ | --------------- |\n| **nombre**   | _Otro nombre_   |\n| **apellido** | _Otro apellido_ |\n| **correo**   | _Otro correo_   |\n\ny por último \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eS\u003c/kbd\u003e para guardar\n\n![Solicitud PUT](assets/request_put.gif)\n\n---\n\n#### Crear solicitud DELETE\n\nDuplica el request **Obtener Usuarios** y cambiale el nombre a **Eliminar Usuario**  \n\nPara tener un orden arrastras el request con el mouse de la siguiente manera:\n\n![Solicitud POST](assets/move_request.gif)\n\nRellena con los siguientes datos:\n\nRecuerda que en este método debemos de [indicarle el ID por la URL](#delete) en este caso el ID será: **1**\n\n|            |                                            |\n| ---------- | ------------------------------------------ |\n| **url**    | [http://127.0.0.1:3000/api/usuarios/1](##) |\n| **Método** | \u003ckbd\u003eDELETE\u003c/kbd\u003e                          |\n\ny por último \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eS\u003c/kbd\u003e para guardar\n\n![Solicitud DELETE](assets/request_delete.gif)\n\n---\n\nAl final debería verse así:\n\n![Previsualización de collección](assets/preview_collection.png)\n\n---\n\n### Colección completa de Thunder Client\n\nTambién puedes [descargar](tests/thunder_test.json) e importar la colección que hicimos en el paso anterior\n\n![Importar colección](assets/import_collection.gif)\n\n### Ejecución de pruebas\n\nPara la ejecución de las pruebas es simple solo debemos ir a cada una de las solicitudes y hacer click en el botón \u003ckbd\u003eSend\u003c/kbd\u003e\n\nCuando ejecutemos las pruebas tendremos 2 pestañas importantes:\n\n\u003ckbd\u003eResponse\u003c/kbd\u003e: Es el Json con que responderá el servidor\n\n\u003ckbd\u003eTest Results\u003c/kbd\u003e: Serán el resultado de las pruebas, debemos obtener \u003ckbd\u003ePass\u003c/kbd\u003e en el resultado de cada prueba\n\nPara no obtener el [error \"Empty List\"](#get) primero vamos a guardar un nuevo usuario.\n\n---\n\n#### Ejecución solicitud POST\n\n![Ejecución solicitud POST](assets/run_request_post.gif)\n\n---\n\n#### Ejecución solicitud GET\n\nAquí veremos el usuario que se guardo en el test anterior\n\n![Ejecución solicitud GET](assets/run_request_get.gif)\n\n---\n\n#### Ejecución solicitud PUT\n\nAquí modificaremos el usuario que se guardó\n\n![Ejecución solicitud PUT](assets/run_request_put.gif)\n\nPara comprobarlo podemos a volver a ejecutar la [primer prueba](#ejecución-solicitud-get)\n\n![Ejecución solicitud PUT](assets/check_run_request_put.gif)\n\n---\n\n#### Ejecución solicitud DELETE\n\n![Ejecución solicitud DELETE](assets/run_request_delete.gif)\n\n---\n\n## Wiki\n\nHTTP:\n\n[HTTP Messages and Structure](https://developer.mozilla.org/es/docs/Web/HTTP/Messages)  \n[HTTP Request Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)  \n[HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)  \n\nJavaScript:\n\n[Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)  \n[Arrow Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)  \n[Monkey patch](https://en.wikipedia.org/wiki/Monkey_patch)\n\nBase de datos:\n\n[Express mysql](https://expressjs.com/es/guide/database-integration.html#mysql)  \n[Pool Connection](https://es.wikipedia.org/wiki/Connection_pool)  \n[Mysql pool](https://github.com/mysqljs/mysql#pooling-connections)  \n[Promisify in Node](https://medium.com/@suyashmohan/util-promisify-in-node-js-v8-d07ef4ea8c53)  \n[Mysql error codes](https://github.com/sambrmg/mysql-error-codes)  \n[Sql Injection](https://en.wikipedia.org/wiki/SQL_injection)  \n[Sql Injection in Nodejs](https://www.veracode.com/blog/secure-development/how-prevent-sql-injection-nodejs)\n\nJson:\n\n[Structure of Json](https://www.json.org/json-en.html)  \n[JsonAPI](https://jsonapi.org/)  \n\nDocker:\n\n[Install](https://docs.docker.com/engine/install/linux/)  \n[Docker Pull](https://docs.docker.com/engine/reference/commandline/pull/)  \n[Docker Image](https://docs.docker.com/engine/reference/commandline/image/)  \n[Docker Run](https://docs.docker.com/engine/reference/commandline/run/)  \n[Docker Start](https://docs.docker.com/engine/reference/commandline/start/)  \n[Docker Stop](https://docs.docker.com/engine/reference/commandline/stop/)  \n[Docker mysql](https://hub.docker.com/_/mysql)\n\nExpress:\n\n[Express api](https://expressjs.com/en/api.html)  \n[Express json](https://expressjs.com/en/api.html#res.json)  \n[Express urlencoded](https://expressjs.com/en/api.html#express.urlencoded)  \n[Express request body](https://expressjs.com/en/api.html#req.body)  \n[Express request query](https://expressjs.com/en/api.html#req.query)  \n[Express request param](https://expressjs.com/en/api.html#app.param)  \n[Express GET Method](https://expressjs.com/en/api.html#app.get.method)  \n[Express POST Method](https://expressjs.com/en/api.html#app.post.method)  \n[Express PUT Method](https://expressjs.com/en/api.html#app.put.method)  \n[Express DELETE Method](https://expressjs.com/en/api.html#app.delete.method)  \n[Express Response Status](https://expressjs.com/en/api.html#res.status)  \n\nExtensiones vscode:\n\n[Docker](https://github.com/microsoft/vscode-docker)  \n[Database Client](https://github.com/cweijan/vscode-database-client)  \n[Thunder Client](https://github.com/rangav/thunder-client-support)  \n\n---\n\n## Autor\n\n| ![Srealmoreno](https://github.com/srealmoreno.png?size=115) |  [srealmoreno](https://github.com/srealmoreno) |\n| :---: | :--: |\n\nTambién puedes mirar la lista de todos los [contribuyentes](https://github.com/srealmoreno/api-express/contributors) quíenes han participado en este proyecto.\n\n---\n\n## Licencia\n\nEste proyecto está bajo la Licencia GNU General Public License v3.0 - mira el archivo [LICENSE](LICENSE) para más detalles\n\n---\n\nProgramación en Android - Salvador real\n\n[![#](https://img.shields.io/github/followers/srealmoreno?label=Follow\u0026style=social)](https://github.com/srealmoreno/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrealmoreno%2Fapi-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsrealmoreno%2Fapi-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrealmoreno%2Fapi-express/lists"}