repository
0.0.0-20240402040952-1190e815909d
Repository: https://github.com/pintoter/warehouse-api.git
Documentation: pkg.go.dev
# README
warehouse-api
Examples
Warehouse API
A simple design and implementation of JSON API with RPC-like operations as test task
Navigation
Task
- Design and implement API methods for working with
Products
in manyWarehouse
. Please note that an API call can be made simultaneously from different systems and they can work with the same products. API methods can be extended by parameters at your discretion.
Entity
- Warehouse
- name
- availability
- Product
- name
- size
- code
- quantity
API
- ReserveProducts:
{
[
{
"code": "12345", // default parameter, possible to set several codes
"quantity": 8 // extended parameter by me for reserving any number of products
}
]
}
- ReleaseProducts:
{
[
{
"reservation_id": "422ab5fa-fbf1-461a-99dc-2c6a49c323f1" // extended parameter by me for working with products that can be located in several warehouses
"code": "12345", // default parameter, possible to set several codes
"quantity": 8 // extended parameter by me for releasing any number of products
}
]
}
- GetProductsByWarehouse:
{
"warehouse_id": 3 // default parameter
}
Requirement | Result |
---|---|
Use go fmt + goimports | Done (for check: make lint ) |
Effective Go | Try to follow |
JSON-API with RPC-like methods | Done |
Use PostgreSQL or MySQL | Done PostrgeSQL |
make up to deploy the service | Done |
.http / curl in README.md / Postman collections | Done (curl in README.md + ./examples/*.http) |
Testing code | Few Unit-tests in Repository's layer |
Reasoning for choosing packages in go.mod | File packages.md |
Installation
git clone https://github.com/pintoter/warehouse-api.git
Getting started
- Create .env file with filename ".env" in the project root and setting up environment your own variables:
# Database
DB_USER = "user"
DB_PASSWORD = "123456"
DB_HOST = "postgres"
DB_PORT = 5432
DB_NAME = "dbname"
DB_SSLMODE = "disable"
# Local database
LOCAL_DB_PORT = 5432
Hint: if you are running the project using Docker, set
DB_HOST
to "postgres" (as the service name of Postgres in the docker-compose).
- Compile and run the project:
make up
- Service's structure
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
│ └── warehouse-api
│ └── main.go
├── configs
│ └── main.yml
├── cover.out
├── docker-compose.yml
├── examples
│ ├── releaseproducts.http
│ ├── reserveproducts.http
│ └── showproducts.http
├── go.mod
├── go.sum
├── internal
│ ├── app
│ │ └── app.go
│ ├── config
│ │ └── config.go
│ ├── dbutil
│ │ ├── db.go
│ │ └── transaction
│ │ └── txmanager.go
│ ├── migrations
│ │ └── migrations.go
│ ├── repository
│ │ ├── model
│ │ │ └── products.go
│ │ ├── product
│ │ │ ├── repository.go
│ │ │ ├── reservation_create.go
│ │ │ ├── reservation_create_test.go
│ │ │ ├── reservation_get.go
│ │ │ ├── reservation_get_test.go
│ │ │ ├── reservation_update.go
│ │ │ ├── reservation_update_test.go
│ │ │ ├── warehouses_get.go
│ │ │ ├── warehouses_get_test.go
│ │ │ ├── warehouses_update.go
│ │ │ └── warehouses_update_test.go
│ │ └── repository.go
│ ├── server
│ │ └── server.go
│ ├── service
│ │ ├── model
│ │ │ ├── errors.go
│ │ │ ├── product.go
│ │ │ └── req.go
│ │ ├── product
│ │ │ └── service.go
│ │ └── service.go
│ └── transport
│ └── handler.go
├── migrations
│ ├── 20240228134525_init.down.sql
│ └── 20240228134525_init.up.sql
├── packages.md
└── pkg
├── database
│ └── postgres
│ └── postgres.go
└── logger
└── logger.go
Examples of requests
All submitted queries are executed one by one
on the data that is lifted in the migration
1. Reserve products
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.ReserveProducts",
"params": [{"products":[{"code": "12345", "quantity": 5}]}],
"id": "coola"
}'
- Response example:
{
"result": {
"reservation_id": "51ef143e-4c4d-4b8b-a4dc-700ede2832e2",
"reservation_products_info": [
{
"code": "12345",
"status": "reserved"
}
]
},
"error": null,
"id": "coola"
}
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.ReserveProducts",
"params": [{"products":[{"code": "12345", "quantity": 5}]}],
"id": "coola"
}'
- Response example:
{
"result": {
"reservation_id": "e216385f-74f0-4cb7-b3e4-532c11f6c428",
"reservation_products_info": [
{
"code": "12345",
"status": "rejected: required quantity of products is missing"
}
]
},
"error": null,
"id": "coola"
}
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.ReserveProducts",
"params": [{"products":[{"code": "12345", "quantity": 5}, {"code": "12346", "quantity": 4}]}],
"id": "coola"
}'
- Response example:
{
"result": {
"reservation_id": "ef99828c-b077-463a-82cc-4bc9abaffab1",
"reservation_products_info": [
{
"code": "12345",
"status": "rejected: required quantity of products is missing"
},
{
"code": "12346",
"status": "reserved"
}
]
},
"error": null,
"id": "coola"
}
2. Release products
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.ReleaseProducts",
"params": [{"products":[{"reservation_id":"422ab5fa-fbf1-461a-99dc-2c6a49c323f1","code": "12345", "quantity": 2}]}],
"id": "coola"
}'
- Response example:
{
"result": {
"release_products_info": [
{
"reservation_id": "422ab5fa-fbf1-461a-99dc-2c6a49c323f1",
"code": "12345",
"status": "released"
}
]
},
"error": null,
"id": "coola"
}
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.ReleaseProducts",
"params": [{"products":
[
{"reservation_id":"422ab5fa-fbf1-461a-99dc-2c6a49c323f1","code": "12345", "quantity": 2},
{"reservation_id":"965ac486-0451-4e87-be55-2f985cdbf292","code": "12346", "quantity": 2}
]
}],
"id": "coola"
}'
- Response example:
{
"result": {
"release_products_info": [
{
"reservation_id": "965ac486-0451-4e87-be55-2f985cdbf292",
"code": "12346",
"status": "released"
},
{
"reservation_id": "422ab5fa-fbf1-461a-99dc-2c6a49c323f1",
"code": "12345",
"status": "released"
}
]
},
"error": null,
"id": "coola"
}
3. Get products by warehouse
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.GetProductsByWarehouse",
"params": [{"warehouse_id": 1}],
"id": "coola"
}'
- Response example:
{
"result": [
{
"id": 1,
"name": "Lacoste T-Shirt",
"size": "XS",
"code": "12345",
"quantity": 2
},
{
"id": 2,
"name": "Lacoste T-Shirt",
"size": "S",
"code": "12346",
"quantity": 3
},
{
"id": 3,
"name": "Lacoste T-Shirt",
"size": "M",
"code": "12347",
"quantity": 1
},
{
"id": 4,
"name": "Lacoste T-Shirt",
"size": "L",
"code": "12348",
"quantity": 2
}
],
"error": null,
"id": "coola"
}
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.GetProductsByWarehouse",
"params": [{"warehouse_id": 2}],
"id": "coola"
}'
- Response example:
{
"result": [
{
"id": 1,
"name": "Lacoste T-Shirt",
"size": "XS",
"code": "12345",
"quantity": 3
},
{
"id": 5,
"name": "Lacoste T-Shirt",
"size": "XL",
"code": "12349",
"quantity": 3
},
{
"id": 6,
"name": "Dads pants",
"size": "L",
"code": "1337",
"quantity": 5
},
{
"id": 7,
"name": "Dads pants",
"size": "XL",
"code": "1338",
"quantity": 1
},
{
"id": 8,
"name": "Dads pants",
"size": "XXL",
"code": "1339",
"quantity": 2
}
],
"error": null,
"id": "coola"
}
- Request example:
curl -X 'POST' \
'http://localhost:8080/rpc' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"method": "ProductService.GetProductsByWarehouse",
"params": [{"warehouse_id": 3}],
"id": "coola"
}'
- Response example:
{
"result": [
{
"id": 1,
"name": "Lacoste T-Shirt",
"size": "XS",
"code": "12345",
"quantity": 3
},
{
"id": 9,
"name": "Adidas Hoodie",
"size": "L",
"code": "10101011",
"quantity": 3
},
{
"id": 10,
"name": "Adidas Hoodie",
"size": "XL",
"code": "10101012",
"quantity": 5
},
{
"id": 11,
"name": "Adidas Hoodie",
"size": "XXL",
"code": "10101013",
"quantity": 1
},
{
"id": 12,
"name": "Nike Longsleeve",
"size": "S",
"code": "1111131231",
"quantity": 2
}
],
"error": null,
"id": "coola"
}
Additional features
- Run tests
make test
- Stop all running containers
make stop
- Run linter
make lint