IceCream API - Docker, Go, REST, JWT, Mongo
Info
A JSON Web Token (JWT) authenticated REST API, to perform CRUD operations on a pre-seeded MongoDB of various icecream products, is developed. The code is completely containerized using Docker images.
Repository
The repository contains the following:
- Dockerfile
- Dockercompose
- Go code
- REST API (CRUD operation)
- MongoDB (with authentication)
- JSON Web Token Authentication
Project Structure
The project structure is as follows:
project # Assumed to be located at C:/goWorkspace/
└── src #
└── icecreamapi # Main folder
├── seeddata # To import initial data into MongoDB
│ ├── Dockerfile # To build image for initializing MongoDB
│ └── icecream.json # Seed data
├── vendor # Folder containing dependencies
│ ├── credentials # Dependant package `credentials`
│ │ ├── jwtoken.go # Create and authenticate JWT
│ │ └── login.go # Hash and compare login passwords
│ ├── database # Dependant package `database`
│ │ ├── connection.go # Generic database connection function
│ │ └── product.go # Database CRUD operations
│ ├── document # Dependant package `document`
│ │ └── icecream.go # `icecream` document to be stored in MongoDB
│ └── handler # Dependant package `handler`
│ └── respond.go # Generic http response functions
├── Docker-compose.yml # To compose 3 containerized services
├── Dockerfile # Dockerfile to build `icecream` api image
├── handlers.go # Handlers for RESTful operation
├── main.go # Main file of Go code
└── verify.go # Verify user login and obtain claims
Instructions
- Setup Docker
- Source code
- Unzip
icecreamapi.zip
source code into a folder. For example, assume it is unzipped intoC:/goWorkspace/src/icecreamapi
folder.
- Unzip
- Build 2 Docker Images (requires internet connectivity)
- In a bash terminal, navigate to the project folder, i.e.,
C:/goWorkspace/src/icecreamapi
. - Build a docker image of
icecream
from its Dockerfile by excuting:docker build -t "icecream" .
- Navigate to the
seeddata
subdirectory in the project folder, i.e.,C:/goWorkspace/src/icecreamapi/seeddata
, by executing:cd seeddata/
- Build a docker image of
seeddata
from its Dockerfile by excuting:docker build -t "seeddata" .
- In a bash terminal, navigate to the project folder, i.e.,
- Run Docker-Compose to Start IceCream Application (requires internet connectivity)
- In a bash terminal, navigate to the project folder, i.e.
C:/goWorkspace/src/icecreamapi
. Start the application by running docker-compose.docker-compose up
- In a bash terminal, navigate to the project folder, i.e.
- Functional API Testing
- Use an API development environment tool such as Postman to test the RESTful API endpoints.
- LOGIN into the
icecream
application by postingname
andpassword
in Postman. Currently, the application only has one authorized user with the following authentication details.POST http://localhost:8080/login BODY { "name" : "user1", "password" : "1234" }
A JWT with a validity for 5 minutes, will be returned in the http response, such as:
{ "tokenString": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mzk1OTIxNDUsImlzcyI6IkhvbWVCYXNlIn0.r9JlDX_FmoPnRMzf_yox_oCw0Lj0Obyql2Liz8gpE10" }
Please do not use the above token string in your testing as it has exceeded its 5 minutes validity period.
- Copy and paste the JWT string into the
Token
field underAuth
->Bearer Token
in Postman, to be used for subsequent operations. - POST a new product into the
icecream
database. New products are posted byname
and thus the fieldname
is mandatory.POST http://localhost:8080/product BODY { "name" : "ChocolateLava", "image_closed" : "", "image_open" : "", "description" : "Molten chocolate", "story" : "Erupting volcano", "sourcing_values" : ["Non-GMO"], "ingredients" : ["koko","sugar"], "allergy_info" : "none", "dietary_certifications" : "Halal", "productID" : "9870" }
The database enforces unique product
name
andproductID
indexes. Hence, products with samename
and/orproductID
cannot be inserted into the database. - UPDATE a product in the database. Products are updated by
name
, thus the fieldname
is mandatory and must match an existing product in the database.PUT http://localhost:8080/product BODY { "name" : "ChocolateLava", "image_closed" : "", "image_open" : "", "description" : "Molten chocolate", "story" : "Erupting volcano", "sourcing_values" : ["Non-GMO"], "ingredients" : ["koko","sugar, milk, eggs"], "allergy_info" : "contains milk, eggs", "dietary_certifications" : "Halal", "productID" : "9870" }
Upon successfully updating the database, a http response is received as:
{ "Result": "Successfully updated" }
- GET a single product from the database. Products are retrieved by
name
, thus the fieldname
is mandatory and must match an existing product in the database.GET http://localhost:8080/product/?doc=ChocolateLava
The retrieved product is returned in the http response as:
{ "name" : "ChocolateLava", "image_closed" : "", "image_open" : "", "description" : "Molten chocolate", "story" : "Erupting volcano", "sourcing_values" : ["Non-GMO"], "ingredients" : ["koko","sugar, milk, eggs"], "allergy_info" : "contains milk, eggs", "dietary_certifications" : "Halal", "productID" : "9870" }
- DELETE a single product from the database. Products are deleted by
name
, thus the fieldname
is mandatory and must match an existing product in the database.DELETE http://localhost:8080/product/?doc=ChocolateLava
Upon successfully deleting the product, a http response is received as:
{ "Result": "Successfully deleted" }
- GET all products from the database.
GET http://localhost:8080/product
All products from the databse is returned in the http response in JSON format.
Notes on Solution
- Language and Structure
- The code is written in Golang.
- MongoDB is used as the store database.
- A server with REST endpoints listens at port
localhost:8080
. - The code is completely containerized for easy deployment, with 3 docker images. Namely,
mongo
- to create Mongo database, this image will be directly pulled via internet from the Docker Hub,seeddata
- to initialize the database with seed data, andicecream
- for CRUD operations.
- Authentication
- Only authorized users are able to access the REST endpoints to perform CRUD operations on the database.
- Users are authenticated using JWT mechanism, as it is advantageous for scalability.
- Currently, only one authenticated user is present:
{"name":"user1","password":"1234"}
. Passwords stored in the source code are hashed using bcrypt algorithm. - Additionally, MongoDB access is protected with an username and password.
--username admin1 --password abcd --authenticationDatabase admin
- Docker Notes
- When docker-compose is run with Docker-Toolbox, go to
192.168.99.100:8080/
to interact with the application.192.168.99.100
is the IP address of your docker-machine. Executedocker-machine ip
to get IP address of your docker-machine. - To tear down current containers and stored volume:
docker-compose down -v
- To prune all dangling containers, networks, and build caches:
docker system prune
- When docker-compose is run with Docker-Toolbox, go to
Leave a comment