The project includes a REST API that has been implemented in accordance with clean architecture. Leonardo Giordani's work inspired me very much during the development of this application. Especially I mean his book, which can be found here. Excellent book with very good examples, I highly recommend it.
The second source that is definitely worth mentioning here is the repository/book CosmicPython π.
The fastest way to start an application is to use the Makefile. Run this command in
project root directory.
make build
make upTo add the startup data to the database, just use this command:
make seed-dbTo turn everything off:
make downTo run all tests, use this command:
make testapp
βββ __init__.py
βββ adapters
βΒ Β βββ __init__.py
βΒ Β βββ orm.py
βΒ Β βββ repositories.py
βΒ Β βββ unit_of_work.py
βββ application
βΒ Β βββ __init__.py
βΒ Β βββ course
βΒ Β βΒ Β βββ __init__.py
βΒ Β βΒ Β βββ commands.py
βΒ Β βΒ Β βββ queries.py
βΒ Β βββ user
βΒ Β β βββ __init__.py
βΒ Β β βββ commands.py
βΒ Β β βββ queries.py
βΒ Β βββ interfaces
βΒ Β βΒ Β βββ __init__.py
βΒ Β βΒ Β βββ iunit_of_work.py
βΒ Β βββ exceptions.py
βββ domain
βΒ Β βββ __init__.py
βΒ Β βββ course.py
βΒ Β βββ user.py
βββ response_objects
βΒ Β βββ __init__.py
βΒ Β βββ responses.py
βββ service
βββ __init__.py
βββ config.py
βββ course
βΒ Β βββ __init__.py
βΒ Β βββ serializers.py
βΒ Β βββ views.py
βββ user
β βββ __init__.py
β βββ serializers.py
β βββ views.py
βββ extensions.py
βββ parser.py
βββ schemas.py
βββ status_codes.py
At the domain layer, two entities have been implemented:
User and Course.
As you might expect, one user can be enrolled in many
courses and courses can also have many different users.
All functionalities have been broken down into a number of independent commands and queries.
The adapters that have been implemented are mainly Repository for interacting with the database and mapping objects from the database to domain objects. Additionally, the Unit of Work pattern was used here to ensure transactionality.
The REST API was made with the very popular Flask micro-framework. It is very minimalistic and is based primarily on the application layer.
Errors are raised in the application layer in specific commands and queries - this is where business rules can determine what the error really is.
One of the best methods for testing the APIs is HTTPie. In this section, I will use commands using exactly this CLI.
GET - get a list of all users.
http :5000/api/usershttp :5000/api/users include==courses
POST - create new user.
http POST :5000/api/users email='[email protected]'GET - get details of a specific user.
http :5000/api/users/123 http :5000/api/users/123 include==coursesSample response:
{
"_links": {
"collection": "/api/users",
"courses": "/api/users/4aa841d3-a852-408e-bd3f-e23b726b8d1a/courses",
"self": "/api/users/4aa841d3-a852-408e-bd3f-e23b726b8d1a"
},
"courses": [
{
"_links": {
"collection": "/api/courses",
"enroll_user": "/api/courses/3ad9b870-b752-4854-9708-4fc6b703c64d/users",
"self": "/api/courses/3ad9b870-b752-4854-9708-4fc6b703c64d"
},
"id": "3ad9b870-b752-4854-9708-4fc6b703c64d",
"name": "Test Course"
},
{
"_links": {
"collection": "/api/courses",
"enroll_user": "/api/courses/b39fefaa-a143-475c-9b4d-751b0843aaa8/users",
"self": "/api/courses/b39fefaa-a143-475c-9b4d-751b0843aaa8"
},
"id": "b39fefaa-a143-475c-9b4d-751b0843aaa8",
"name": "Sample Course"
}
],
"email": "[email protected]",
"id": "4aa841d3-a852-408e-bd3f-e23b726b8d1a"
}
DELETE - delete user.
http DELETE :5000/api/users/123 GET - get a list of courses for a specific user.
http :5000/api/users/123/coursesGET - get a list of all courses.
http :5000/api/courseshttp :5000/api/courses include==enrollments
POST - create new course.
http POST :5000/api/courses name='Test Course'GET - get details of a specific course.
http :5000/api/courses/123http :5000/api/courses/123 include==enrollmentsSample response:
{
"_links": {
"collection": "/api/courses",
"enroll_user": "/api/courses/3ad9b870-b752-4854-9708-4fc6b703c64d/users",
"self": "/api/courses/3ad9b870-b752-4854-9708-4fc6b703c64d"
},
"enrollments": [
{
"_links": {
"collection": "/api/users",
"courses": "/api/users/9c2f4dee-8db5-4045-95bb-c487d6d52e5b/courses",
"self": "/api/users/9c2f4dee-8db5-4045-95bb-c487d6d52e5b"
},
"email": "[email protected]",
"id": "9c2f4dee-8db5-4045-95bb-c487d6d52e5b"
},
{
"_links": {
"collection": "/api/users",
"courses": "/api/users/4aa841d3-a852-408e-bd3f-e23b726b8d1a/courses",
"self": "/api/users/4aa841d3-a852-408e-bd3f-e23b726b8d1a"
},
"email": "[email protected]",
"id": "4aa841d3-a852-408e-bd3f-e23b726b8d1a"
}
],
"enrollments_count": 2,
"id": "3ad9b870-b752-4854-9708-4fc6b703c64d",
"name": "Test Course"
}
DELETE - delete course.
http DELETE :5000/api/courses/123POST - enroll a user on the course.
http POST :5000/api/courses/123/users user_id=321DELETE - withdraw a user enrollment from a course.
http DELETE :5000/api/courses/123/users/321- Add authentication layer with JWT.
- Implement OpenAPI specification.
- Create a K8S setup.
- Add NGINX as a rivers proxy to the architecture.