Main dependencies:
- Django (framework)
- djangorestframework (toolkit for building Web APIs)
- djoser (REST implementation of Django authentication system)
- drf-yasg (api documentation)
Features:
- API Restfull and Django Admin
- API Restfull documentation
- Versioning API Restfull routes
- Application versioning with changelogs
- Structured logs
- Cache and CacheLock configured for Redis
- Health check and Ping pong
- Unit testing and contract testing
- Dockerized application
Compatibility:
- Python 3.9.4
- Django 3.2.0
- RestFramework 3.12.2
- Development mode
- Docker
- Deploying in production
- Deploying on Heroku
- Create new app
- Migrate and migration
- Renderer and parser data
- Application route versioning
- Application code versioning
- Internationalization
- Logs
- Correlation ID
- Throttles
- Project structure
- Images
The development mode by default uses Postgres as a database and for cache uses Redis.
First, you must configure the virtual environment:
python -m venv venv
After that activate virtualenv:
source venv/bin/activate
Set the environment variables by cloning the .env-sample file to .env
Run the command to install the development dependencies:
make dependencies
Run the command to start the Postgres and Redis docker instances:
make docker-up
To remove them without losing the recorded data, perform make docker-down or make docker-downclear to remove and clear the data.
Now, run the command to create the tables in the database:
make migrate
To access the admin it is necessary to create the superuser. This can be done with the following command:
make superuser
To see which routes exist in the application, execute the command:
make urls
Now just run the command below to run the application:
make run
After running the command above, you can access the documentation and the administrative panel:
http://localhost:8000/v1/docs
http://localhost:8000/admin
http://localhost:8000/ping
http://localhost:8000/healthcheck/?format=json
This application makes use of Docker to facilitate during development in order to raise external dependencies (Postgres and Redis).
Before executing the commands, make sure you have the docker installed on your device.
See the commands available in the Makefile:
- make docker-up: Will create the docker image and run the container.
- make docker-down: Will remove all containers and networks from the docker for the project.
- make docker-downclear: Will remove all containers, networks and volumes from the docker for the project.
To deploy to production the following environment variables must be defined:
export SIMPLE_SETTINGS=project.core.settings.production
export SECRET_KEY="your_key_here"
export DATABASE_URL="sqlite:///db.sqlite3"
Optionals:
export ALLOWED_HOSTS="*;"
I am assuming that you already know Heroku and that you have already installed the CLI and logged in.
The first thing to do is to create the app on Heroku and this can be done with
the command heroku create <name-app>
. After creating the app, the CLI itself
will add git remote to you in your Django project.
The next step is to send your project to Heroku with the command
git push heroku master -f
.
Now it's time to set the environment variables in Heroku:
heroku config:set DEBUG="False"
heroku config:set SIMPLE_SETTINGS=project.core.settings.production
heroku config:set SECRET_KEY="your_key_here"
To configure the Postgres
database, simply run the command heroku addons:create heroku-postgresql:hobby-dev
.
To configure the Redis
database, simply run the command heroku addons:create heroku-redis:hobby-dev
.
By running the two commands above, Heroku will create two environment variables called DATABASE_URL and REDIS_URL.
As an option you can install Timber Logging
to access the application logs by running the command
heroku addons:create timber-logging:free
.
With the database configured, we can run migrations with the command
heroku run make migrate
.
The last step is to create the super user for Django Admin:
heroku run bash
make superuser
The first command we are accessing Heroku's bash and the second we are using to create the super user.
Other commands:
- heroku config view application environment variables
- heroku logs --tail view application logs
- heroku addons view installed addons
- heroku addons:open <name_addon> opens the panel for a particular addon
- heroku pg:psql open postgres shell
- heroku redis:cli open redis shell
Note:
Heroku looks at the file Procfile in order to detect the applications that should be run. It automatically identifies that it is a Django application and runs some commands during application startup, as well as collectfiles. In this file there is a release command, it will be executed after the application initialization and it is not a specific application. The runtime.txt file is used to specify the version of python that Heroku should use.
All new apps are created in the src/project directory and to create a new app you can run the following command:
make app name=clients
Note that the name parameter has been passed. It is used to inform the name of the application.
If you've just set up your model, it's time to create the schema to be applied to the database in the future. Notice that in your app there is a folder with the name of migrations, this is where the schematics of your model will stay.
To create the schema we need to execute the following command:
make migration
You can also create a blank layout, which in turn will not be related to any model at first:
make migration-empty app=clients
Note that the app parameter has been passed. It is used to tell which app the schema should be created in.
Now we need to apply this schema to the database and for that we execute the following command:
make migrate
- Json
To receive the data in json format you can send the Accept
header of type
application/json
or pass the format=json
parameter in the url.
If json data is sent you can set the Content-Type
header to
application/json
type.
- XML
To receive the data in xml format you can send the Accept
header of type
application/xml
or pass the format=xml
parameter in the url.
If xml data is sent you can set the Content-Type
header to
application/xml
type.
This application is prepared for new versions of routes. Usually a new route version is generated when the contract is changed. By default this application is in version 1.0 and you notice this when you make a request by passing /v1 in the url.
In the file project/urls.py
there is a list of urls called routers_v1
and in the list urlpatterns we include it informing the namespace equal
to v1.
In the basic settings of the application, there are the settings of REST_FRAMEWORK and we can find a parameter called DEFAULT_VERSION which is where we define the standard version of the application.
There is also another parameter called ALLOWED_VERSIONS which is where the versions supported by the application are informed and if you are going to create new versions, you must inform them in that parameter.
A good practice it is always good to create a changelog file in each completed task in order to keep a history of the change. For that we have some commands:
- changelog-feature: signifying a new feature
- changelog-bugfix: signifying a bug fix
- changelog-doc: signifying a documentation improvement
- changelog-removal: signifying a deprecation or removal of public API
Each of these commands expects the filename and message parameter. You can use them as follows:
make changelog-feature filename="create-crud-client" message="Adds CRUD for clients management"
When a story is finished it is time to create a new version for the application. All changelog files in existence will be converted to a single message that will be available in the CHANGELOG file.
There are three commands that we use to close the version. Are they:
- release-patch: create patch release eg 0.0.1
- release-minor: create minor release eg 0.1.0
- release-major: create major release eg 1.0.0
You can use them as follows:
make release-patch
After running the specific command, two new commits will be created, one referring to the generation of the changelog file and the other referring to the generation of the new version of the application. In addition to these new commits, a specific tag for the application version is also generated.
Finally, you can submit all changes to your git repository with the make push
command.
This application is configured to use the internationalization that Django offers and is fully compatible with the Rest Framework.
By default, internationalization is disabled in this project and to activate
it you must set the value True in the variable USE_I18N
located in
project/core/settings/base.py
.
The project/core/locales
directory is where the files with the translations are
located. Files with the extension .po are used to write the texts in the
specific language.
Django identifies that a text in the application must be consulted in the translation files as follows:
from django.utils.translation import gettext_lazy as _
default_detail = _('CLIENT_NOT_FOUND')
Note that we use a keyword inside __()_. This keyword will be automatically inserted in the translation files when we run the command:
python src/manage.py makemessages -l en -l pt_BR
In order to test the translation we need to compile the translation files with the following command:
python src/manage.py compilemessages
Django identifies which translation to use in some ways that you can see in this link .
The best case to use is passing in the requests, the header Accept-Language
with the language code. Ex .: Accept-Language: pt-br
The application logs are more powerful and less painful with the help of
structlog which is intermediated by structlog
. All logs made are
converted to JSON, thus facilitating their search, since they are keyed.
For you to use them just follow the code below:
import structlog
logger = structlog.get_logger(__name__)
logger.info("User logged in", user="test-user")
This application uses django-correlation-id to do the management.
The correlation is injected into the logs and returned in the header of each request. The user can send it in the request header (X-Correlation-ID) or if it is not found, the application will automatically generate it.
Throttles is one more security that you can configure in the application. With it you can limit the number of requests that the API can receive, either for seconds, minutes, hours or days, for registered or anonymous users.
By default, the application is configured to limit 50 requests per second for anonymous users. This setting is set in the settings in the REST_FRAMEWORK section.
For more information you can consult the official documentation.
.
└── root
├── .env-sample
├── runtime.txt
├── requirements.txt
├── setup.cpf
├── CHANGELOG.md
├── README.md
├── Procfile
├── Makefile
├── docker-compose.yml
├── pyproject.toml
├── towncrier_template.rst
├── nginx.conf
├── .gitignore
├── .dockerignore
├── .editorconfig
├── changelog
└── .gitignore
├── medias
└── .gitignore
├── .template
└── app_name.zip
├── .github
└── workflows
└── pythonapp.yml
└── src
├── __init__.py
├── manage.py
├── requirements
├── __init__.py
├── base.txt
├── dev.txt
├── prod.txt
└── test.txt
└── project
├── __init__.py
├── urls.py
├── conftest.py
├── backends
└── __init__.py
├── extensions
└── __init__.py
├── helpers
├── __init__.py
├── contracts.py
├── validators.py
└── tests
└── __init__.py
└── core
├── middlewares
├── __init__.py
└── version_header.py
├── throttles
└── __init__.py
├── logging
├── __init__.py
├── filters.py
└── processors.py
├── settings
├── __init__.py
├── base.py
├── development.py
├── production.py
├── sandbox.py
└── test.py
├── locales
└── .gitignore
├── templates
└── .gitignore
├── statics
└── .gitignore
├── models.py
├── swagger.py
├── exceptions.py
├── wsgi.py
└── asgi.py
- Admin
- Documentation
- Health Check
It can be ordered in JSON format as well. Just add the parameter ?format=json
to the end of the URL.