Prueba №12
Implementa una aplicación de una sola página (SPA) donde el usuario pueda registrarse y ver su información personal.
Para simplificar el desarrollo de esta aplicación, abajo se proporciona app.js
como la parte backend. No es necesario modificar ni complementar la parte backend. La autenticación y el registro en la parte backend se realizan mediante JSON Web Token.
Requisitos
La aplicación debe constar de las siguientes páginas:
/login
- Página con el formulario de inicio de sesión./register
Página con el formulario de registro./
- Página principal con la información del usuario.
Descripción de la página /login
- Contiene un formulario de autenticación para el usuario.
- Debe tener un botón para navegar a la página
/register
.
Descripción de la página /register
- Contiene un formulario de registro para el usuario.
- Debe tener un botón para navegar a la página
/login
.
Descripción de la página /
- Página principal
- Contiene la información del usuario: su avatar, un texto sobre él mismo y su nombre de usuario.
- Se recomienda presentar esta información en forma de tarjeta.
Requisitos técnicos
- Asegúrate de tener instalada la última versión LTS de Node.js: Node.js
- La aplicación debe estar escrita en
javascript
. - Framework utilizado:
Vue.js
- Biblioteca de componentes:
Vuetify.js
Instrucciones para iniciar el API
- Asegúrate de tener la última versión LTS de Node.js: Descargar Node.js
- En la consola, abra la carpeta
frontend
. - Instala las dependencias del API con el comando
npm install
. - Inicia el API con el comando
node app.js
.
Al ejecutar el API, verás un output en la consola.
El servidor con API ha iniciado en la dirección http://localhost:8080
Durante las solicitudes al API, se generarán logs en la consola, lo cual es útil para probar la aplicación.
Enviar solicitudes con el JWT
Para enviar una solicitud con el token, debe incluir el encabezado Authorization: Bearer ${token del usuario}
.
Notas
- La implementación de la parte frontend debe hacerse en un repositorio separado y no en este repositorio. Este repositorio solo contiene la parte backend en forma de API.
- Durante el desarrollo de la aplicación, no es necesario reinventar componentes. Para los componentes de formularios y tarjetas, utilice la biblioteca Vuetify.js.
- Al trabajar con Vue.js, use Vuex, Vue-cli y Vue-router.
- Al reiniciar la parte backend de la aplicación, la lista de usuarios se restablece a su estado original.
- Las pruebas unitarias/e2e son un plus. Utilice Jest para unit tests y Cypress para e2e tests.
- Utilizar sintaxis moderna de JavaScript (ES5+) es un plus.
Resultado del trabajo
El resultado de esta tarea debe publicarse en github.com como un repositorio con acceso público.
Descripción de los endpoints del API
A continuación, se presentan todos los endpoints disponibles en el API.
Notas importantes:
- Por defecto, el API se ejecuta en la dirección
http://localhost:8080
. - Al reiniciar el API, los usuarios se restablecen a su estado original.
- Para probar el API, puede utilizar Postman u otra herramienta que permita enviar solicitudes HTTP.
/login/
- autenticación de usuario
Este endpoint acepta solicitudes para la autenticación de usuarios. Método HTTP: POST
Cuerpo de la solicitud (en formato JSON)
Campo | Tipo | Obligatorio | Descripción |
---|---|---|---|
username | String | + | Nombre de usuario |
password | String | + | Contraseña |
Posibles respuestas del endpoint
200 - Autenticación exitosa
Campo | Tipo | Descripción | Valor |
---|---|---|---|
token | String | JWT-token del usuario | %token JWT generado% |
error | String | Error, si lo hay | null |
401 - Nombre de usuario o contraseña incorrectos
Campo | Tipo | Descripción | Valor |
---|---|---|---|
token | String | Token | null |
error | null | Error | "Ingresa un nombre de usuario o contraseña correctos" |
/register/
- Registro de usuario
Este endpoint acepta solicitudes para el registro de usuarios. Método HTTP: POST
.
Cuerpo de la solicitud (en formato JSON)
Campo | Tipo | Obligatorio | Descripción |
---|---|---|---|
username | String | + | Nombre de usuario |
password | String | + | Contraseña |
Posibles respuestas del endpoint
200 - Registro exitoso
Campo | Tipo | Descripción | Valor |
---|---|---|---|
message | String | Mensaje | "Usuario registrado exitosamente" |
401 - Registro fallido
Campo | Tipo | Descripción | Valor |
---|---|---|---|
message | String | Mensaje | "Ya existe un usuario con ese nombre" |
/about/
- Información del usuario
Este endpoint devuelve la información del usuario almacenada en el servidor. Método HTTP: GET
.
Posibles respuestas del endpoint
200 - Información obtenida con éxito
Campo | Tipo | Descripción | Valor |
---|---|---|---|
id | Integer | ID del usuario | %ID del usuario% |
username | String | Nombre de usuario | %Nombre de usuario% |
avatar | String | URL de la imagen del avatar | %avatar% |
about | String | Texto sobre el usuario | %Texto del API% |
401 - Usuario no autorizado
Si no se envía el token JWT en el encabezado o el token ha expirado, se devolverá la respuesta:
400 - не удалось получить информацию
Campo | Tipo | Descripción | Valor |
---|---|---|---|
message | String | Сообщение | No se pudo obtener la información del usuario |
Enlaces útiles
- https://vuejs.org/ - Vuejs
- https://cli.vuejs.org/ - Vue-cli
- https://vuetifyjs.com/ - Vuetifyjs
- https://router.vuejs.org/- Vue-router
- https://www.getpostman.com/ - postman
APP.JS
const express = require("express");
const bodyParser = require("body-parser");
const jwt = require("jsonwebtoken");
const exjwt = require("express-jwt");
const morgan = require("morgan");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(morgan("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// inicialización del middleware de express-jwt
const jwtMW = exjwt({
secret: "topsecretkey",
algorithms: ['HS256']
});
// base de datos simulada
// !!! con cada reinicio del API, el array users se establecerá en este estado!!
let users = [
{
id: 1,
username: "test",
password: "123",
avatar: `https://picsum.photos/id/1/200/200`,
about:
"Soy el usuario de prueba número uno. ¡Nunca desaparezco entre los reinicios del API!"
},
{
id: 2,
username: "test2",
avatar: `https://picsum.photos/id/2/200/200`,
password: "234",
about:
"Soy el usuario de prueba número dos. ¡Yo tampoco desaparezco entre los reinicios del API!"
}
];
app.post("/login", (req, res) => {
const { username, password } = req.body;
const user = users.find(
user => user.username == username && user.password == password
);
if (user) {
// si se encuentra al usuario en el array users
const token = jwt.sign(
{ id: user.id, username: user.username },
"topsecretkey",
{ expiresIn: 129600 }
);
res.json({
error: null,
token
});
} else {
res.status(401).json({
token: null,
error: "Ingrese un nombre de usuario/contraseña correctos"
});
}
});
app.get("/about", jwtMW, (req, res) => {
const { id } = req.user;
const user = users.find(user => user.id == id);
if (user) {
const { password, ...info } = user;
res.json({
data: info
});
} else {
res.status(400).json({
error: "No se pudo obtener información del usuario"
});
}
});
app.post("/register", (req, res) => {
const { username, password } = req.body;
const isRegistered = users.some(user => user.username == username);
if (isRegistered) {
res.status(400).json({
error: "El usuario con ese nombre ya está registrado"
});
return;
}
if (username.length < 3) {
res.status(400).json({
error: "¡Nombre demasiado corto!"
});
return;
}
if (password.length < 4) {
res.status(400).json({
error: "¡Contraseña demasiado corta!"
});
return;
}
const id = users.length + 1;
users.push({
id,
username,
password,
avatar: `https://picsum.photos/id/${id}/200/200`,
about: null
});
res.json({
message: "Usuario registrado exitosamente"
});
});
// manejo de errores
app.use((error, req, res, next) => {
if (error.name === "UnauthorizedError") {
// si el usuario no está autorizado, enviamos un error indicando que no está autorizado
res.status(401).json({
message: "Usuario no autorizado"
});
} else {
next(error);
}
});
// puerto predeterminado de la aplicación
const PORT = 8080;
app.listen(PORT, () => {
// eslint-disable-next-line
console.log(`El servidor API ha iniciado en http://localhost:${PORT}`);
});