A pesar de la gran variedad de sitios web, prácticamente todo el desarrollo web se puede reducir a las operaciones CRUD. En esta lección, las conoceremos en detalle.
¿Qué es CRUD?
CRUD es un término ampliamente difundido que denota las cuatro operaciones estándar que se realizan con cualquier entidad. Consideremos el siguiente ejemplo:
- Crear (Create) — registro de usuario.
- Leer (Read) — visualización del perfil del usuario por otros usuarios del sitio o en la interfaz administrativa.
- Actualizar (Update) — actualización de datos personales, cambio de correo electrónico o contraseña.
- Eliminar (Delete) — eliminación de datos.
Al igual, se pueden describir acciones sobre cualquier otro recurso: fotos del usuario, sus amigos, mensajes, etc. Para crear un CRUD completo, debes realizar las siguientes acciones:
- Crear una entidad en el código (generalmente, es una clase).
- Agregar una tabla en la base de datos.
- Escribir pruebas para verificar los manejadores.
- Agregar manejadores.
- Agregar plantillas.
A continuación, repasaremos todo el proceso de creación de un CRUD de usuario, a excepción del trabajo con la base de datos y las pruebas.
Comenzaremos con el enrutamiento. Un CRUD completo de usuario incluye al menos siete rutas. Podría haber más, ya que cualquier acción puede repetirse más de una vez:
| Método | Ruta | Plantilla | Descripción |
|---|---|---|---|
| GET | /users | users/index.pug | Lista de usuarios |
| GET | /users/new | users/new.pug | Formulario para crear un nuevo usuario |
| GET | /users/:id | users/show.pug | Perfil de usuario |
| POST | /users | Creación de un nuevo usuario | |
| GET | /users/:id/edit | users/edit.pug | Formulario para editar un usuario |
| PATCH/PUT | /users/:id | Actualización de un usuario | |
| DELETE | /users/:id | Eliminación de un usuario |
Esta convención de nomenclatura de rutas apareció originalmente en el marco de trabajo Ruby On Rails, luego fue adaptada por muchos otros. Aquí lo usamos debido a su universalidad y claridad.
Vamos a desglosar las rutas principales y ejemplos de manejadores. Aquí está el código
import fastify from 'fastify';
import view from '@fastify/view';
import pug from 'pug';
const state = {
users: [
{
id: 1,
name: 'First User',
email: 'first@user.com,
},
{
id: 2,
name: 'Second User',
email: 'second@user.com,
},
],
};
const app = fastify();
const port = 3000;
await app.register(view, { engine: { pug }, root: 'src/views' });
// Vista de la lista de usuarios
app.get('/users', (req, res) => {
const data = {
users: state.users,
};
res.view('users/index.pug', data);
});
// Formulario para crear un nuevo usuario
app.get('/users/new', (req, res) => res.view('users/new.pug');
// Vista de un usuario específico
app.get('/users/:id', (req, res) => {
const { id } = req.params;
const user = state.users.find((item) => item.id === parseInt(id));
if (!user) {
res.code(404).send({ message: 'User not found' });
} else {
res.view('users/show.pug', { user });
}
});
// Creación de un usuario
app.post('/users', (req, res) => {
const user = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
};
state.users.push(user);
res.redirect('/users');
});
// Formulario para editar un usuario
app.get('/users/:id/edit', (req, res) => {
const { id } = req.params;
const user = state.users.find((item) => item.id === parseInt(id));
if (!user) {
res.code(404).send({ message: 'User not found' });
} else {
res.view('users/edit.pug', { user });
}
});
// Actualización de un usuario
app.patch('/users/:id', (req, res) => {
const { id } = req.params;
const { name, email, password, passwordConfirmation, } = req.body;
const userIndex = state.users.findIndex((item) => item.id === parseInt(id));
if (userIndex === -1) {
res.code(404).send({ message: 'User not found' });
} else {
state.users[userIndex] = { ...state.users[userIndex], name, email };
res.send(users[userIndex]);
res.redirect('/users');
}
});
// Eliminación de un usuario
app.delete('/users/:id', (req, res) => {
const { id } = req.params;
const userIndex = state.users.findIndex((item) => item.id === parseInt(id));
if (userIndex === -1) {
res.code(404).send({ message: 'User not found' });
} else {
state.users.splice(userIndex, 1);
res.redirect('/users');
}
});
app.listen({ port }, () => {
console.log(`Example app listening on port ${port}`);
});
Create - Crear
- Creación de un nuevo usuario
Esta acción se realiza mediante solicitudes POST. Son precisamente estas rutas las que procesan los datos de los formularios.
En el ejemplo anterior, obtenemos los datos y los guardamos. Aquí podrían haber controles adicionales para verificar la exactitud de los datos. Normalmente, los datos se guardan en una base de datos, pero aquí los guardamos en un array. Más tarde aprenderemos cómo trabajar con bases de datos.
Read - Leer
- Vista del perfil del usuario por otros usuarios del sitio
- Vista del usuario en la interfaz administrativa
Esta acción se lleva a cabo mediante solicitudes GET. En nuestro ejemplo, estas son dos rutas:
GET /users:visualización de la lista de usuarios. En el ejemplo, devolvemos el arrayusers().GET /users:id:vista de un usuario específico. En el ejemplo, buscamos al usuario por elidy lo devolvemos. Si no se encuentra al usuario, se devuelve el código404.
Update - Actualizar
- Actualización de datos personales.
- Cambio de correo electrónico.
- Cambio de contraseña.
Aquí se utilizan los verbos PUT y PATCH, ambos se utilizan para actualizar datos
PUTgeneralmente se usa para actualizar todo el objeto.PATCHse usa cuando solo necesitamos actualizar algunas partes de los datos del objeto.
En Fastify, se define un método para cada uno de estos verbos.
En nuestro ejemplo, obtenemos los datos del formulario req.body, luego buscamos al usuario requerido por el id. Si no se encuentra al usuario, devolvemos el código 404. Si encontramos al usuario, actualizamos los datos de este usuario. Ten en cuenta que no todos los datos pueden actualizarse, por lo que en el ejemplo se utiliza el operador rest { ...users[userIndex] }. En el manejador de esta solicitud, puede haber controles adicionales para verificar la exactitud de los datos.
Delete - Eliminar
Para eliminar, se utiliza el verbo DELETE, en Fastify se define un método similar para él.
En nuestro ejemplo, como en otros manejadores, verificamos la existencia del usuario y eliminamos al usuario si existe. Si no hay usuario, devolvemos el estado 404.
Puedes describir de la misma manera las acciones sobre cualquier otro recurso, las fotos de usuario, sus amigos, mensajes, etc.
Arquitectura de la aplicación
Las operaciones CRUD agrupan las rutas y sus manejadores en bloques lógicos alrededor de algunas entidades. Por ejemplo, el CRUD de cursos, ejercicios, lecciones, artículos de blog, etc. Esta estructura permite dividir la aplicación en archivos, de tal manera que, a medida que la aplicación crece, sea fácil de mantener.
En el desarrollo de Fastify, se acostumbra a agrupar las rutas y manejadores en archivos separados, cada uno relacionado con una entidad específica, y ubicar estos archivos en la carpeta routes:
.
└── routes
├── users.js
├── posts.js
└── root.js
En el ejemplo anterior, cada una de las rutas contiene lógica relacionada con una entidad específica:
- users.js — rutas para usuarios.
- posts.js — para publicaciones.
- root.js — rutas que no se relacionan con entidades. Por ejemplo, esta podría ser la ruta de la página principal.
Trabajo independiente
- Realiza los pasos del tutorial en tu propia computadora.
- Haz que las rutas coincidan con la tabla en la lección.
- Separa los controladores en archivos individuales y ajusta el enrutamiento.
- Haz lo mismo para la entidad de cursos.
- Sube los cambios a GitHub.
Para acceder completo a curso necesitas un plan básico
El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.