El objetivo de este ejercicio es crear una API para gestionar eventos, productos y pedidos. El entregable es el código de la API subido a un repositorio de GitHub. Vuestro entregable deberá funcionar con la colección de Postman que tenéis disponible.
- Todas las rutas están bajo el ámbito de una empresa (company).
- Todas las rutas (excepto auth y crear un pedido) requieren un token JWT válido en la cabecera de autorización:
Authorization: Bearer {token}
- Todos los precios se manejan en céntimos de euro.
- Todas las fechas se manejan en formato ISO 8601. (YYYY-MM-DD)
- Podéis utilizar cualquier sistema de organización: Linear, Trello, Notion, una app de notas, un fichero Markdown, un folio, o directamente nada.
- Mi recomendación es que tengais algo, lo que sea, pero os va a ayudar a que os sea más fácil organizaros y gestionar el ejercicio.
- El código debe estar correctamente organizado por capas (routers, controllers, services, repositories, models)
- No tendría ni que comentarlo, pero para que quede claro: El código debe de estar correectamente indentado
- Añadir un fichero .gitignore para no subir el .env ni el node_modules
- No hace falta que generéis un QR, de momento lo podemos dejar vacío
- Podéis usar cualquier referencia de los proyectos en los que hemos trabajado en clase:
Authorization: Bearer <token>http://localhost:3000/api
POST /auth/register
Content-Type: application/json
{
"name": "string",
"email": "string",
"password": "string",
"company": {
"name": "string",
"description": "string",
"cif": "string"
}
}
POST /auth/login
Content-Type: application/json
{
"email": "string",
"password": "string"
}Todas las rutas de eventos están bajo el ámbito de una empresa (company):
GET /company/:companyId/events
GET /company/:companyId/events/:id
POST /company/:companyId/events
Content-Type: application/json
{
"name": "string",
"description": "string",
"start_at": "2024-03-20T19:00:00.000Z",
"ends_at": "2024-03-20T23:00:00.000Z",
"booking_available": true,
"max_tickets_for_order": 4,
"address": "string"
}
PUT /company/:companyId/events/:id
Content-Type: application/json
{
"name": "string",
"description": "string",
"start_at": "2024-03-20T19:00:00.000Z",
"ends_at": "2024-03-20T23:00:00.000Z",
"booking_available": true,
"max_tickets_for_order": 4,
"address": "string"
}
DELETE /company/:companyId/events/:id
Query params de consulta para GET /events:
- booking: "open" | "closed"
- start_at: FechaLos productos están bajo el ámbito de los eventos:
GET /company/:companyId/events/:eventId/products
GET /company/:companyId/events/:eventId/products/:id
POST /company/:companyId/events/:eventId/products
Content-Type: application/json
{
"name": "string",
"description": "string",
"price": 25.99,
"max_sales": 100
}
PUT /company/:companyId/events/:eventId/products/:id
Content-Type: application/json
{
"name": "string",
"description": "string",
"price": 2599,
"max_sales": 100
}
DELETE /company/:companyId/events/:eventId/products/:idLos pedidos están bajo el ámbito de los eventos:
GET /company/:companyId/events/:eventId/orders
GET /company/:companyId/events/:eventId/orders/:id
POST /company/:companyId/events/:eventId/orders
Content-Type: application/json
{
"items": [
{
"product_id": "65f1a2b3c4d5e6f7g8h9i0j1",
"name": "string",
"email": "string",
"price": "number",
"identification_number": "string"
}
]
}
PUT /company/:companyId/events/:eventId/orders/:id
Content-Type: application/json
{
"status": "confirmed"
}
DELETE /company/:companyId/events/:eventId/orders/:id
POST /company/:companyId/events/:eventId/orders/redeem/:id- Relación uno a uno con Company
- Campos:
id(ObjectId)name(String, requerido)email(String, requerido, único)password(String, requerido)company_id(ObjectId, ref: Company)- Marcas de tiempo:
created_at,updated_at
- Relación uno a muchos con Users
- Campos:
id(ObjectId)name(String, requerido)description(String, requerido)cif(String, requerido, único)slug(String, único, auto-generado)- Marcas de tiempo:
created_at,updated_at
- Pertenece a Company
- Tiene muchos Products
- Campos:
id(ObjectId)name(String, requerido)description(String, requerido)start_at(Date, requerido)ends_at(Date, requerido)company_id(ObjectId, ref: Company)booking_available(Boolean, por defecto: false)max_tickets_for_order(Number, requerido)slug(String, único, auto-generado)address(String, requerido)- Marcas de tiempo:
created_at,updated_at
- Pertenece a Event
- Campos:
id(ObjectId)name(String, requerido)description(String, requerido)price(Number, requerido)event_id(ObjectId, ref: Event)max_sales(Number, requerido)- Marcas de tiempo:
created_at,updated_at
- Pertenece a Event
- Tiene muchos OrderItems
- Tiene muchas Activities
- Campos:
id(ObjectId)event_id(ObjectId, ref: Event)total_price(Number, requerido)total_items(Number, requerido)status(String, enum: ['pending', 'confirmed', 'cancelled'])- Marcas de tiempo:
created_at,updated_at
- Pertenece a Order
- Campos:
id(ObjectId)order_id(ObjectId, ref: Order)product_id(ObjectId, ref: Product)name(String, requerido)email(String, requerido)identification_number(String, requerido)price(Number, requerido)redeemed_at(Date)qr(String, único, auto-generado)- Marcas de tiempo:
created_at,updated_at
- Pertenece a Order
- Campos:
id(ObjectId)order_id(ObjectId, ref: Order)message(String, requerido)event(String, enum: ['created', 'updated', 'deleted'])properties(Un objeto con los campos relevantes que valoréis cada uno)- Marcas de tiempo:
created_at
200 OK: Solicitud exitosa201 Created: Recurso creado204 No Content: Recurso eliminado
400 Bad Request: Entrada inválida401 Unauthorized: Token faltante o inválido403 Forbidden: Token válido pero permisos insuficientes404 Not Found: Recurso no encontrado500 Internal Server Error: Error del servidor
Las respuestas de error incluyen un mensaje:
{
"message": "Descripción del error"
}Podéis probar la api en postman utilizando el endpoint https://eventos.tesserapass.es/api
