Skip to content

RESTful API to manage sales, users, clients and products, built with AdonisJs and very much love.

Notifications You must be signed in to change notification settings

mairess/desafio-back-end

Repository files navigation

Back-end Challenge from BeMobile

Challenge

This project implements a RESTful API to manage users, clients, products, and sales. The API allows authenticated users to perform CRUD operations on these entities and stores data in a relational database.

🚀 Installation and Setup

Prerequisites

Make sure you have Docker installed on your machine:

Also set up the environment variables:

TZ=UTC
PORT=3333
HOST=0.0.0.0
LOG_LEVEL=info
APP_KEY=MSCLKHNZ5o35eMhTIAJRJ-IlFn4Xz-q-
NODE_ENV=development
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=root
DB_DATABASE=adonis_db

And the test environment variables .env.test:

TZ=UTC
PORT=3333
HOST=0.0.0.0
LOG_LEVEL=info
APP_KEY=mSCOaHNF5o35eMhTIAJRJ-AfPb2Rw-q-
NODE_ENV=test
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=root
DB_DATABASE=test_db

Run with Docker

Steps:

  1. Clone repository and install dependencies:
git clone [email protected]:mairess/desafio-back-end.git && cd desafio-back-end && npm install
  1. Run application:
docker compose up -d
  1. Run tests:
npm test

Run locally

Steps:

  1. Clone repository and install dependencies:
git clone [email protected]:mairess/desafio-back-end.git && cd desafio-back-end && npm install
  1. Run database:
docker compose up -d database
  1. Run project:
# before run the project, you have to await for database health check

npm run dev
  1. Run tests:
npm test

📚 API Documentation

Authentication

POST /auth/signup

Request:

{
  "fullName": "Marcos Oliveira de Cardoso",
  "email": "[email protected]",
  "password": "password123"
}

Response:

{
  "fullName": "Marcos Oliveira de Cardoso",
  "email": "[email protected]",
  "id": 4
}

POST /auth/login

Request:

{
  "email": "[email protected]",
  "password": "12345678"
}

Response:

{
	"token": "oat_NA.TmFERV9JT1ZOZ3dTdFVpTkJXY1dhLWFpY2hxMWxhTVRzUlFkRUR2NDUyMzY0MzAwMw"
}

GET /auth/me

Response:

{
	"id": 2,
	"fullName": "Juliana Silva",
	"email": "[email protected]",
	"createdAt": "2024-11-21T22:29:39.000+00:00",
	"updatedAt": "2024-11-21T22:29:39.000+00:00"
}

DELETE /auth/me

Response:

{
	"message": "Logged out successfully!"
}
Customers

Customers

GET /customers?page=1&limit=5

Response:

{
	"meta": {
		"total": 66,
		"perPage": 5,
		"currentPage": 1,
		"lastPage": 14,
		"firstPage": 1,
		"firstPageUrl": "/?page=1",
		"lastPageUrl": "/?page=14",
		"nextPageUrl": "/?page=2",
		"previousPageUrl": null
	},
	"data": [
		{
			"id": 1,
			"fullName": "Jão Cabral",
			"cpf": "00011122233",
			"email": "[email protected]"
		},
		{
			"id": 2,
			"fullName": "Juliano Marques de Souza",
			"cpf": "11122222222",
			"email": "[email protected]"
		},
		{
			"id": 3,
			"fullName": "Pedro Souza",
			"cpf": "98765432101",
			"email": "[email protected]"
		},
		{
			"id": 4,
			"fullName": "Ana Costa",
			"cpf": "10293847562",
			"email": "[email protected]"
		},
		{
			"id": 5,
			"fullName": "Lucas Pereira",
			"cpf": "56473829101",
			"email": "[email protected]"
		}
	]
}

GET /customers/2?year=2024&month=11

Response:

{
	"id": 2,
	"fullName": "Maires Rocha de Souza",
	"cpf": "11122222222",
	"email": "[email protected]",
	"createdAt": "2024-11-21T22:29:39.000+00:00",
	"updatedAt": "2024-11-21T22:34:13.000+00:00",
	"addresses": [
		{
			"id": 2,
			"street": "Rua das Laranjeiras",
			"number": "101",
			"neighborhood": "Laranjeiras",
			"city": "Rio de Janeiro",
			"state": "RJ",
			"zipCode": "02000-001",
			"country": "Brasil",
			"createdAt": "2024-11-21T22:29:39.000+00:00",
			"updatedAt": "2024-11-21T22:29:39.000+00:00"
		}
	],
	"phones": [
		{
			"id": 2,
			"phoneNumber": "11900000002",
			"createdAt": "2024-11-21T22:29:39.000+00:00",
			"updatedAt": "2024-11-21T22:29:39.000+00:00"
		}
	],
	"sales": [
		{
			"id": 6,
			"quantity": 1,
			"unitPrice": "150.00",
			"totalPrice": "150.00",
			"createdAt": "2024-11-21T22:29:39.000+00:00",
			"product": {
				"id": 6,
				"name": "Product 6",
				"description": "Descrição do produto 6",
				"price": "150.00"
			}
		},
		{
			"id": 7,
			"quantity": 6,
			"unitPrice": "25.00",
			"totalPrice": "150.00",
			"createdAt": "2024-11-21T22:29:39.000+00:00",
			"product": {
				"id": 7,
				"name": "Product 7",
				"description": "Descrição do produto 7",
				"price": "25.00"
			}
		},
		{
			"id": 8,
			"quantity": 3,
			"unitPrice": "75.00",
			"totalPrice": "225.00",
			"createdAt": "2024-11-21T22:29:39.000+00:00",
			"product": {
				"id": 8,
				"name": "Product 8",
				"description": "Descrição do produto 8",
				"price": "75.00"
			}
		}
	]
}

POST /customers

Request:

{
	"fullName": "Maires Souza",
	"cpf": "120.100.101-00",
	"email": "[email protected]"
}

Response:

{
	"fullName": "Maires Souza",
	"cpf": "120.100.101-00",
	"email": "[email protected]",
	"id": 67
}

PATCH /customers/2

Request:

{
	"fullName": "Maires Rocha de Souza",
	"cpf": "11122222222",
	"email": "[email protected]"
}

Response:

{
	"id": 2,
	"fullName": "Maires Rocha de Souza",
	"cpf": "11122222222",
	"email": "[email protected]"
}

DELETE /customers/2

Response:

{
	"message": "Customer deleted successfully!"
}
Products

GET /products?page=1&limit=15

Response:

{
	"meta": {
		"total": 15,
		"perPage": 5,
		"currentPage": 1,
		"lastPage": 3,
		"firstPage": 1,
		"firstPageUrl": "/?page=1",
		"lastPageUrl": "/?page=3",
		"nextPageUrl": "/?page=2",
		"previousPageUrl": null
	},
	"data": [
		{
			"id": 1,
			"name": "Product 1",
			"description": "Descrição do produto 1",
			"price": "100.00"
		},
		{
			"id": 10,
			"name": "Product 10",
			"description": "Descrição do produto 10",
			"price": "40.00"
		},
		{
			"id": 11,
			"name": "Product 11",
			"description": "Descrição do produto 11",
			"price": "90.00"
		},
		{
			"id": 12,
			"name": "Product 12",
			"description": "Descrição do produto 12",
			"price": "120.00"
		},
		{
			"id": 13,
			"name": "Product 13",
			"description": "Descrição do produto 13",
			"price": "180.00"
		}
	]
}

GET /products

Response:

{
	"id": 15,
	"name": "Product 15",
	"description": "Descrição do produto 15",
	"price": "55.00",
	"stock": 25,
	"createdAt": "2024-11-21T22:29:39.000+00:00",
	"updatedAt": "2024-11-21T22:29:39.000+00:00",
	"deletedAt": null
}

POST /products

Request:

{
  "name": "Super Blender",
  "description": "High-performance blender for making smoothies, soups, and more.",
  "price": 299.99,
  "stock": 15
}

Response:

{
	"name": "Super Blender",
	"description": "High-performance blender for making smoothies, soups, and more.",
	"price": 299.99,
	"stock": 15,
	"id": 16
}

PATCH /products/16

Request:

{
	"name": "Bicycle",
	"description": "A nice bicycle",
	"price": 450,
	"stock": 80
}

Response:

{
	"id": 16,
	"name": "Bicycle",
	"description": "A nice bicycle",
	"price": 450,
	"stock": 80
}

DELETE /products/16

Response:

{
	"message": "Product deleted successfully!"
}
Sales

GET /sales?page=1&limit=2

Response:

{
	"meta": {
		"total": 57,
		"perPage": 2,
		"currentPage": 1,
		"lastPage": 29,
		"firstPage": 1,
		"firstPageUrl": "/?page=1",
		"lastPageUrl": "/?page=29",
		"nextPageUrl": "/?page=2",
		"previousPageUrl": null
	},
	"data": [
		{
			"id": 1,
			"customerId": 1,
			"productId": 1,
			"quantity": 2,
			"unitPrice": "100.00",
			"totalPrice": "200.00",
			"createdAt": "2024-11-21T22:29:39.000+00:00"
		},
		{
			"id": 2,
			"customerId": 1,
			"productId": 2,
			"quantity": 3,
			"unitPrice": "50.00",
			"totalPrice": "150.00",
			"createdAt": "2024-11-21T22:29:39.000+00:00"
		}
	]
}

GET /sales/57

Response:

{
	"id": 57,
	"quantity": 2,
	"unitPrice": "120.00",
	"totalPrice": "240.00",
	"createdAt": "2024-11-21T22:29:39.000+00:00",
	"updatedAt": "2024-11-21T22:29:39.000+00:00",
	"customer": {
		"id": 21,
		"fullName": "Renato Souza",
		"cpf": "45678902303",
		"email": "[email protected]"
	},
	"product": {
		"id": 12,
		"name": "Product 12",
		"description": "Descrição do produto 12",
		"price": "120.00",
		"stock": 30
	}
}

POST /sales

Request:

{
	"customerId": 66,
	"productId": 11,
	"quantity": 1
}

Response:

{
	"customerId": 66,
	"productId": 11,
	"quantity": 1,
	"unitPrice": "90.00",
	"totalPrice": 90,
	"id": 58
}
Phones

POST /phones/customers/1

Request:

{
	"phoneNumber": "07401000001"
}

Response:

{
	"phoneNumber": "07401000001",
	"id": 66
}

PATCH /phones/66/customers/1

Request:

{
	"phoneNumber": "00000035222"
}

Response:

{
	"id": 66,
	"customerId": 1,
	"phoneNumber": "00000035222"
}

DELETE /phones/1

Response:

{
	"message": "Phone deleted successfully!"
}
USers

GET /users

Response:

{
	"meta": {
		"total": 3,
		"perPage": 50,
		"currentPage": 1,
		"lastPage": 1,
		"firstPage": 1,
		"firstPageUrl": "/?page=1",
		"lastPageUrl": "/?page=1",
		"nextPageUrl": null,
		"previousPageUrl": null
	},
	"data": [
		{
			"id": 1,
			"fullName": "Mirosmar Gleidson",
			"email": "[email protected]"
		},
		{
			"id": 2,
			"fullName": "Juliana Silva",
			"email": "[email protected]"
		},
		{
			"id": 3,
			"fullName": "Maires Rocha de Souza",
			"email": "[email protected]"
		}
	]
}

PATCH /users/1

Request:

{
	"fullName": "Mirosmar Gleidson de Souza",
	"email": "[email protected]"
}

Response:

{
	"id": 1,
	"fullName": "Mirosmar Gleidson de Souza",
	"email": "[email protected]"
}

DELETE /users/1

Response:

{
	"message": "User deleted successfully!"
}
Addresses

POST /addresses/customers/1

Request:

{
	"street": "Green Flowers",
	"number": 39,
	"neighborhood": "Garden",
	"city": "Rio de Janeiro",
	"state": "RJ",
	"zipCode": "46470000",
	"country": "Brasil"
}

Response:

{
	"street": "Green Flowers",
	"number": 39,
	"neighborhood": "Garden",
	"city": "Rio de Janeiro",
	"state": "RJ",
	"zipCode": "46470000",
	"country": "Brasil",
	"customerId": 1,
	"id": 66
}

PATCH /addresses/1/customers/1

Request:

{
	"street": "oi",
	"number": 222,
	"neighborhood": "oi",
	"city": "oi",
	"state": "PI",
	"zipCode": "46470000",
	"country": "Brasil meu país amado"
}

Response:

{
	"id": 1,
	"customerId": 1,
	"street": "oi",
	"number": 222,
	"neighborhood": "oi",
	"city": "oi",
	"state": "PP",
	"zipCode": "46470000",
	"country": "Brasil meu país amado"
}

DELETE /addresses/1/customers/1

Response:

{
	"message": "Address deleted successfully!"
}

🛠 Technologies Used

  • AdonisJS: Framework for Node.js.

  • MySQL: Relational database.

  • JWT: For authentication.

  • Node.js: Back-end runtime environment.

  • Japa: Back-end testing framework for Node.js.

About

RESTful API to manage sales, users, clients and products, built with AdonisJs and very much love.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages