Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dibot55 committed Mar 1, 2023
0 parents commit 6a02e23
Show file tree
Hide file tree
Showing 17 changed files with 447 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env"], // Ejecuta compila y ejecuta el codigo
"plugins": ["@babel/plugin-transform-runtime"] // Crea el "dist"
}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
node_modules
.vscode
dist
package-lock.json
Binary file added img/API.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/Client.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/ENV.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/REST.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "rest-api",
"version": "1.0.0",
"description": "REST API con NodeJs y MongoDB",
"main": "index.js",
"scripts": {
"test": "nodemon ./src/index.js --exec babel-node",
"build": "babel src -d dist ",
"start": "node ./dist/index.js"
},
"author": "dibot55",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.21.0",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"mongoose": "^6.10.0",
"mongoose-paginate-v2": "^1.7.1",
"morgan": "^1.10.0"
},
"devDependencies": {
"@babel/cli": "^7.21.0",
"@babel/core": "^7.21.0",
"@babel/node": "^7.20.7",
"@babel/plugin-transform-runtime": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"ncp": "^2.0.0",
"nodemon": "^2.0.20"
}
}
60 changes: 60 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# API REST con NodeJS y Mongo DB

![Crud Imagen](./img/API.png)

## Descripción

Una API REST con NodeJS y MongoDB usando un Babel como compilador para que la API funcione en sistemas legacy.

<div align="center">
<img src="https://github.com/devicons/devicon/blob/master/icons/nodejs/nodejs-original.svg" title="NodeJS" alt="Node" width="40" height="40"/>
<img src="https://github.com/devicons/devicon/blob/master/icons/mongodb/mongodb-original.svg" title="MongoDB" alt="Mongo" width="40" height="40"/>
<img src="https://github.com/devicons/devicon/blob/master/icons/babel/babel-original.svg" title="BabelJS" alt="Babel" width="40" height="40"/>
</div>

## Instrucciones

Para Ejecutar el proyecto debes seguir los pasos siguientes:

- Tener REST Client instalado en VS CODE o cualquier API Tester

<div align = "center">

![dist](./img/rest.png)

</div>

- Ejecutar el comando:

```
$ npm install
```

- Crear un archivo .env en la raiz del proyecto y agregar las variables PORT y MONGO_URI

<div align = "center">

![dist](./img/env.png)

</div>

- Ejecutar babel para producción

```
$ npm run build
```

- Ejecutar el Proyecto


```
$ npm run start
```

- Puedes ejecutar las peticiones de la carpeta "request" o hacer las tuyas.

<div align = "center">

![dist](./img/client.png)

</div>
42 changes: 42 additions & 0 deletions requests/task.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Petición de REST API Client
###
GET http://localhost:5000/api/tasks
###
// Guardar datos con una peticion POST
POST http://localhost:5000/api/tasks
// Enviar datos a travez de una peticion POST
Content-Type: application/json

{
"title": "Test 9",
"description": "Hacer una REST API",
"done": "true"
}
###
// Solicitar un dato por el id como parametro
GET http://localhost:5000/api/tasks/63fbd5c221bd52252ffffe41
###
// Actualizar un dato por el id como parametro
PUT http://localhost:5000/api/tasks/63fbe9aa39c0d3f275b5c9df
Content-Type: application/json

{
"title": "Test 8",
"description": "Ver False",
"done": "false"
}
###
// Eliminar un dato por el id como parametro
DELETE http://localhost:5000/api/tasks/63fbe216ccea6c5a7adcd1ab
###
// Mostrar todas las tareas que tengan la propiedad "done : true"
GET http://localhost:5000/api/tasks/done
###
// Consultas
GET http://localhost:5000/api/tasks/?page=0&size=3
###
GET http://localhost:5000/api/tasks/?page=2&size=3
###
GET http://localhost:5000/api/tasks/?page=3&size=3
###
GET http://localhost:5000/api/tasks/?page=0&size=3&title=test
40 changes: 40 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Configuracion de express
import express from "express";
import morgan from "morgan";
import cors from "cors";
import indexRoutes from "./routes/index.routes";


const app = express();

// Puerto del servidor
app.set("port", process.env.PORT || 3000);


// ------------------------------------- Middlewares -----------------

// Se usa morgan para visualizar las peticiones por terminal
app.use(morgan('dev'));

// Para que express entienda metodos JSON de lo contrario da "undefined"
app.use(express.json());

// Para que reciba datos de un formulario HTML sin problema
app.use(express.urlencoded({extended: false}));

// CORS restriccion de peticiones http a otro servidor
app.use(cors({
origin: '*'
}));

// ------------------------------------------------------------------

// Raiz
app.get("/", (req, res) => {
res.json({ message: "Bienvenidos a mi aplicación" });
});

// Se concatena /api con las rutas /api/routes
app.use("/api/tasks", indexRoutes);

export default app;
8 changes: 8 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Variables de entorno
import { config } from 'dotenv';

config();

export default {
mongo_uri: process.env.MONGO_URI || "mongodb://127.0.0.1:27017/restapi?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.7.1"
}
151 changes: 151 additions & 0 deletions src/controllers/task.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import modeltask from "../models/Task"; // Modelo de datos
import { getPaginate } from "../libs/getPagination"; // las Options de .paginate

// Read
export const findalltask = async (req, res) => {
// try {
// // Ver toda la lista de datos guardadas en la base de datos
// const taskfind = await modeltask.find();
// res.json(taskfind);
// } catch (error) {
// res.status(500).json({
// message: error.message || 'Algo salio mal recibiendo las tareas'
// });
// }

try {
// con el req.query obtengo las clave-valor de la query por URL
const { page, size, title} = req.query;

// Pasando los parametros
const { offset, limit } = getPaginate(page, size);

// Relacionar el title de la consulta con el title de la base de datos
const conditionTitle = title ? {
// $regex = crea una expresión regular utilizando el constructor RegExp /titulo/
// $options : "i" = busca una coincidencia con el texto del título de forma insensible a mayúsculas y minúsculas
title: {$regex: new RegExp(title), $options: "i" }
} : {};
console.log(conditionTitle);

// Ver toda la lista de datos guardadas en la base de datos usando mongoose-paginate-v2
const taskfind = await modeltask.paginate(conditionTitle, { offset, limit });

// si quieres ver todos las propiedades de taskfind entonces quita el objeto y ponle taskfind
res.json({
totalItems: taskfind.totalDocs,
task: taskfind.docs,
totalPages: taskfind.totalPages,
currentPage: taskfind.page -1
});
} catch (error) {
res.status(500).json({
message: error.message || 'Algo salio mal recibiendo las tareas'
});
}
};

// Create
export const savetasks = async (req, res) => {

// Valida que el titulo existe antes de hacer la peticion
if(!req.body.title){
res.status(404).json({
message: 'El contenido de la solicitud no puede estar vacio'
});
}

// Aqui se configuró el modelo para que las peticiones POST realizadas por el cliente REST sean guardadas
try {
// Puedes usar directamente req.body en lugar del objeto. Lo mostre para que se vea que es lo que se esta subiendo
const tasksv = new modeltask({
title: req.body.title,
description: req.body.description,
done: req.body.done ? req.body.done : false
});

// Guardar
const tasksaved = await tasksv.save();

res.json(tasksaved);

} catch (error) {
res.status(500).json({
message: error.message || 'Algo salio mal creando la tarea'
});
}
};

// READ by ID

export const findTaskById = async (req, res) => {

try {
const taskid = await modeltask.findById(req.params.id);

// Validación
if(!taskid){
res.status(404).json({
message: `El contenido solicidado no existe: ${req.params.id}`
});
}

res.json(taskid);

} catch (error) {
res.status(500).json({
message: error.message || `Error devoliendo el contenido : ${req.params.id}`
});
}
};

// UPDATE

export const updateTask = async (req, res) => {

try {
await modeltask.findByIdAndUpdate(req.params.id, req.body);

res.json({

message: `La terea fue actualizada exitosamente`
});

} catch (error) {
res.status(500).json({
message: error.message || `Error actualizando el contenido : ${req.params.id}`
});
}

};

// DELETE

export const deleteTask = async (req, res) => {

try {
await modeltask.findByIdAndDelete(req.params.id);

res.json({
message: "La tarea fue eliminada exitosamente",
});
} catch (error) {
res.status(500).json({
message: error.message || `Error borrando el contenido : ${req.params.id}`
});
}
};

// ALL TRUE

export const findTaskDone = async (req, res) => {
// Busca todos los elementos que tengan done: true
const taskfind = await modeltask.find({done : true});
// Validación
if(!taskfind){
res.status(404).json({
message : 'No hay tareas disponibles aún con las propiedades solicitadas'
});
}
res.json(taskfind);
};
24 changes: 24 additions & 0 deletions src/database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Conexión a MongoDB
import mongoose from "mongoose";
import config from "./config";

mongoose.set('strictQuery', false);

// Cadena de conexión

(async () => {

try {

const db = await mongoose.connect(config.mongo_uri, {
useNewUrlParser: true,
useUnifiedTopology: true
});
console.log('Base de datos conectada en: ', db.connection.name);

} catch (error) {
console.error(error);
}


})();
7 changes: 7 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Arranca la aplicación
import "./config"; // Variables de entorno
import app from "./app"; // Express
import "./database"; // MongoDB

// Servidor
app.listen(app.get('port'), () => console.log('Servidor escuchando en el puerto:', app.get('port') ));
10 changes: 10 additions & 0 deletions src/libs/getPagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Configuracion de .paginate (cantidad de paginas, Cantidad de objetos retornados por consulta)
export const getPaginate = (page, size) => {
// Si existe un tamaño definido lo conviertes a numero y si no entonces defines 3 por defecto
const limit = size ? +size : 3;

// Si me has pasado un numero de pagina devuelve/retorna esa pagina SIN repetir los mismos objetos y si no te paso un 0
const offset = page ? page * limit : 0;

return{ offset, limit }; // No importa el orden ya no ejecutamos la funcion de manera directa
};
Loading

0 comments on commit 6a02e23

Please sign in to comment.