Programación, Tecnología y Más...

Programación, Tecnología y Más...

REST API Node.js con TypeScript y MongoDB Atlas

En este artículo estaremos creando una REST API usando Node js con TypeScript y MongoDB Atlas

Primeramente dejame contarte que ya tengo un tiempo programando en javascript(en el frontend)  y hace un par de meses he venido probando javascript para el backend(Node.js) pero como en mi trabajo actual(también en mis trabajos anteriores) programó en C# y mi mayor experiencia se centra en este lenguaje, por esta razón he querido usar en mi aprendizaje de Node.js TypeScript ya que la sintaxis es muy parecida a c#(también se parece a java) y me siento más cómodo que usando solo  javascript(de hecho usar ts te trae muchas ventajas que lo veremos en artículos posteriores)

Lo primero que tienes que hacer es instalar Node.js 
 
Una vez instalado node procedemos a instalar TypeScript de manera global

npm install -g typescript

Iniciamos un nuevo proyecto de node

npm init -y

Creamos el archivo configuración para  TypeScript

tsc --init

En el archivo de configuración de TypeScript realizaremos las siguientes modificaciones

"target": "es6", //usamos ECMAScript 6
"outDir": "./dist", //especificamos la carpeta donde se generara el codigo js cuando compilemos el codigo ts
Instalamos los módulos que estaremos usando en este proyecto

npm i express mongoose morgan cors helmet 
Instalar dependencias para desarrollo

npm install @types/node @types/mongoose @types/express @types/morgan nodemon typescript -D
La ultima configuracion que haremos será dentro del archivo package.json para no estar compilando nuestro código TypeScript y luego ejecutar el código js generado con node siempre que hagamos cambios haremos la siguiente configuración


 "scripts": {
    "ts": "tsc -w",
    "dev": "nodemon ./dist/server.js",
    "start": "tsc && node ./dist/server.js"
  },
Ahora bastará con que ejecutemos npm run ts para que nuestro código ts se compile automáticamente y npm run dev para que nuestra aplicación se reinicie automáticamente al detectar cambios en el código

La estructura del proyecto que crearemos será la siguiente 


Te explico rápidamente la estructura del proyecto
  • src carpeta donde estará todo nuestro desarrollo.
  • controller tendremos los controladores que son los encargados de procesar las peticiones  y retornar la información.
  • models contendrá los modelos que usaremos para manejar los datos de nuestra db.
  • routes es donde armaremos las rutas que tendrás nuestras peticiones.
  • services es donde realizaremos las consultas a la db.
  • server.ts es la clase de inicio de nuestra aplicación.
Como te lo mencione anteriormente estaremos usando MongoDB Atlas que prácticamente es un servicio que te permite tener tu servidor de mongodb en la nube(te permite poder probarlo gratis) así que deberás crear una cuenta MongoDB Atlas una vez registrado lo único que debes hacer es crear un cluster y con esto podrás obtener los datos para poder conectarte al servidor de mongodb, para este ejemplo yo cree el cluster con el nombre por defecto que es Cluster0 y cree una base de datos llamada api-db

Empezaremos primero en la carpeta models crearemos un archivo llamado Products.ts que representara la collection de nuestra db

import {Schema, model, Document} from 'mongoose';

export interface IProduct extends Document {
    name: string;
    category: string;
    price: Number;
};

const ProductSchema = new Schema(
    {
        name: {type: String, required: true},
        category: {type: String, required: true},
        price: {type: Number, required: true},
        createdAt: {type: Date, default: Date.now}

    }
);

export default model<IProduct>('Product', ProductSchema);
Una vez tenemos creado nuestro modelo que representa nuestra collection crearemos el servicio para poder hacer las consultas a la db, dentro de la carpeta services creamos el archivo productServices.ts

import Product, { IProduct } from "../models/Products";
import { ObjectID } from "mongodb";

export async function getProductsServices() {
  try {
    return await Product.find();
  } catch (error) {
    // Log Errors
    throw Error(error);
  }
}

export async function getProductServices(id: ObjectID) {
  try {
    return await Product.findOne({ _id: id });
  } catch (error) {
    // Log Errors
    throw Error(error);
  }
}

export async function createProductServices(product: IProduct) {
  try {
    await product.save();
    return product;
  } catch (error) {
    // Log Errors
    throw Error(error);
  }
}

export async function updateProductServices(id: ObjectID, product: IProduct) {
    try {
      await Product.findOneAndUpdate({ _id: id}, product);
      return product;
    } catch (error) {
      // Log Errors
      throw Error(error);
    }
  }

  export async function deleteProductServices(id: ObjectID) {
    try {
      return await Product.findOneAndRemove({_id: id});
    } catch (error) {
      // Log Errors
      throw Error(error);
    }
  }
Ahora crearemos el controlador que será el encargado de procesar las solicitudes y retornar la información correspondiente en la carpeta controller creamos el archivo productController.ts

import { Request, Response } from "express";
import Product, { IProduct } from "../models/Products";
import { ObjectID } from "mongodb";

import {
  getProductServices,
  getProductsServices,
  createProductServices,
  updateProductServices,
  deleteProductServices
} from "../services/productServices";

export async function getProductsController(req: Request, res: Response) {
  try {
    const products = await getProductsServices();
    console.log(products);
    res.json(products);
  } catch (error) {
    res.status(500).json({ status: 500, message: error.message });
  }
}

export async function getProductController(req: Request, res: Response) {
  try {
    const { id } = req.params;
    const product = await getProductServices(new ObjectID(id));
    console.log(product);
    res.json(product);
  } catch (error) {
    res.status(500).json({ status: 500, message: error.message });
  }
}

export async function createProductController(req: Request, res: Response) {
  try {
    const { name, category, price } = req.body;
    const newproduct: IProduct = new Product({ name, category, price });
    await createProductServices(newproduct);
    res.json(newproduct);
  } catch (error) {
    res.status(500).json({ status: 500, message: error.message });
  }
}

export async function updateProductController(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const product = await updateProductServices(new ObjectID(id), req.body);
      console.log(product);
      res.json(product);
    } catch (error) {
      res.status(500).json({ status: 500, message: error.message });
    }
  }

  export async function deleteProductController(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const product = await deleteProductServices(new ObjectID(id));
      console.log(product);
      res.json(product);
    } catch (error) {
      res.status(500).json({ status: 500, message: error.message });
    }
  }
Ahora definiremos las diferentes rutas que tendrá nuestra rest api en la carpeta routes creamos el archivo productRoutes.ts

import { Router } from "express";
import {
  getProductController,
  getProductsController,
  createProductController,
  updateProductController,
  deleteProductController
} from "../controller/productController";

class Product {
  public router: Router;
  constructor() {
    this.router = Router();
    this.routes();
  }

  routes() {
    this.router.get("/", getProductsController);
    this.router.get("/:id", getProductController);
    this.router.post("/", createProductController);
    this.router.put('/:id', updateProductController);
    this.router.delete('/:id', deleteProductController);
  }
}

const product = new Product();
export default product.router;
Por último nos falta crear nuestra clase principal en donde configuramos nuestra servidor express así que dentro de la carpeta src creamos el archivo server.ts

import express from "express";
import morgan from "morgan";
import routes from "./routes/index";
import productsRoutes from "./routes/productRoute";
import mongoose from "mongoose";
import cors from "cors";

class Server {
  public app: express.Application;
  constructor() {
    this.app = express();
    this.config();
    this.routes();
  }

  config() {
    //connection mongodb atlas
    const mongodb_atlas =
      "mongodb+srv://<user>:<password>@cluster0.fvcxm.mongodb.net/api-db?retryWrites=true&w=majority";
    mongoose.set("useFindAndModify", true);
    mongoose
      .connect(mongodb_atlas || process.env.MONGODB_URL, {
        useNewUrlParser: true,
        useCreateIndex: true,
      })
      .then((db) => console.log("Connected to database"))
      .catch((err) => {
        console.error(`Error connecting to the database. \n${err}`);
      });
    //Settings
    this.app.set("port", process.env.PORT || 3000);
    //Middlewares
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: false }));
    this.app.use(morgan("dev"));
    this.app.use(cors());
  }

  routes() {
    this.app.use("/api/products", productsRoutes);
  }

  start() {
    this.app.listen(this.app.get("port"), () => {
      console.log("Server on port:", this.app.get("port"));
    });
  }
}

const server = new Server();
server.start();
Ejecutamos nuestra aplicación

npm run ts
npm run dev
Ahora tenemos nuestra rest api lista, empecemos haciendo un post para crear un nuevo producto

Ahora probemos la petición get para devolver todos los productos

Consultemos un producto por su id

Actualicemos un producto put

Y por último eliminemos un producto delete

Nuestra REST API está funcionando perfectamente. Esta estructura te puede servir como partida inicial de tu próximo proyecto 

puedes descargar el código desde este repositorio


si quieren donarme para una café lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador...

Publicar un comentario

0 Comentarios