Meringue Api¤
This is an application with a set of various utilities for the API and in particular for the Django Rest Framework.
routers¤
MeringueRouter¤
It's a django rest framework router, with some additional specific functionality.
Root view¤
The router enables and disables the root view according to the API_ENABLE_ROOT_VIEW setting. By default, the parameter corresponds to the value of the DEBUG parameter and in production the root view is disabled.
Object predefined detail route¤
The router allows you to add ViewSet for predefined objects - that is, a ViewSet object for which it is known in advance, the simplest example is a profile. To manage a profile, it is often necessary to have a set of views - getting a profile, editing, deleting. The default behavior of DRF will either require you to use an id to request a profile, or make several separate views for this, this router allows you to use ViewSet for this. To implement such a ViewSet, you need to make a standard ViewSet and specify the flag m_object_detail = True
.
For example, ViewSet for a profile in general will look like this:
class ProfileViewSet(
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
GenericViewSet,
):
permission_classes = (ProfilePermission, )
queryset = User.objects.all()
serializer_class = ProfileSerializer
object_detail = True
def get_object(self):
user = self.request.user
self.check_object_permissions(self.request, user)
return user
def perform_destroy(self, instance):
self.request.user = AnonymousUser()
super().perform_destroy(instance)
Of course, for such a router, it will not work to use ListModelMixin
.
The router itself in use is exactly the same as a regular one:
from meringue.api.routers import MeringueRouter
router = MeringueRouter()
router.register('profile', ProfileViewSet, basename="profile")
urlpatterns = [
path('', include(router.urls)),
]
handlers¤
exception_handler¤
Error handler for django rest framework.
This handler returns errors in the format of code and error message pairs, this can be useful when it is necessary to implement different behavior on the front depending on the type of error (for example, in a certain case, show a popup with extended information about the cause of the error).
>>> from rest_framework import serializers
>>> from django.contrib.auth.models import User
>>> class UserSerializer(serializers.ModelSerializer):
>>> class Meta:
>>> model = User
>>> fields = ["username",]
>>> serializer = UserSerializer(data={})
>>> serializer.is_valid()
>>> print(serializer.errors)
{'username': [ErrorDetail(string='Required field.', code='required')]}
docs¤
When generating API documentation using drf-spectacular, it is possible to intervene in the resulting object in a limited and inconvenient way:
- Firstly, it is proposed to do all this in the settings, which no longer implies a large amount of data (or it will be terribly inconvenient);
- Secondly, it is difficult to do some manipulations "on the fly" (for example, depending on the environment, you may have a different set of authorization methods, or something else);
- Thirdly, if you have several apexes and, accordingly, documentation, you will not be able to do, for example, a different description for different apexes / documentation.
To solve all these problems, we implemented a patcher and a view to load it.
OpenAPISchemaPatcher¤
This is an OpenAPI3 schema patcher that makes it relatively easy to add data to the schema. Everything is quite simple and without much logic, just additional data is first registered, then the scheme is supplemented with them.
To register additional objects, there is the following set of methods:
register_security_scheme¤
Register security scheme.
Attributes:
-
name
–Security scheme name.
-
scheme
–Security scheme in Security Scheme Object or Reference Object format.
Example:
from meringue.api.docs import OpenAPISchemaPatcher
patcher = OpenAPISchemaPatcher()
patcher.register_security_scheme("name", { ... })
register_component_scheme¤
Register components scheme.
Attributes:
-
name
–Component name.
-
schema
–Formatted Component schema object.
Example:
from meringue.api.docs import OpenAPISchemaPatcher
patcher = OpenAPISchemaPatcher()
patcher.register_component_scheme("name", { ... })
register_tag¤
Example:
from meringue.api.docs import OpenAPISchemaPatcher
patcher = OpenAPISchemaPatcher()
patcher.register_tag({
"name": "meringue",
"x-displayName": "Meringue",
})
patch_description¤
Adds a list of servers from the openapi schema source servers to the description.
This method adds to the end of the description a list of servers that it takes from the corresponding section of the openapi schema.
Attributes:
-
openapi_schema
–OpenAPI Object.
Example:
>>> from meringue.api.docs import OpenAPISchemaPatcher
>>> patcher = OpenAPISchemaPatcher()
>>> schema = {
... "servers": [
... {
... "description": "Server 1",
... "url": "https://example-1.com",
... },
... {
... "description": "Server 2",
... "url": "example-2.com",
... },
... ],
... "info": {
... "description": "Test API",
... },
... }
>>> patcher.patch_description(schema)
>>> print(schema)
{
"servers": [
{
"description": "Server 1",
"url": "https://example-1.com",
},
{
"description": "Server 2",
"url": "example-2.com",
},
],
"info": {
"description": "Test API\n\nServer 1 API [example-1.com](https://example-1.com)\n\nServer 2 API [example-2.com](example-2.com)",
},
}
patch_security_schemes¤
Adds registered security schemes to the openapi schema.
Attributes:
-
openapi_schema
–OpenAPI Object.
Example:
>>> from meringue.api.docs import OpenAPISchemaPatcher
>>> patcher = OpenAPISchemaPatcher()
>>> patcher.register_security_scheme("name", { ... })
>>> schema = {}
>>> patcher.patch_security_schemes(schema)
>>> print(schema)
{
"components": {
"securitySchemes": {
"name": { ... },
},
},
}
patch_component_schemes¤
Adds registered components schemas to the openapi schema.
Attributes:
-
openapi_schema
–OpenAPI Object.
Example:
>>> from meringue.api.docs import OpenAPISchemaPatcher
>>> patcher = OpenAPISchemaPatcher()
>>> patcher.register_component_scheme("name", { ... })
>>> schema = {}
>>> patcher.patch_component_schemes(schema)
>>> print(schema)
{
"components": {
"schemas": {
"name": { ... },
},
},
}
patch_tags¤
Adds registered components schemas to the openapi schema.
Attributes:
-
openapi_schema
–OpenAPI Object.
Example:
>>> from meringue.api.docs import OpenAPISchemaPatcher
>>> schema = {
... "servers": [
... {
... "description": "Server 1",
... "url": "https://example-1.com",
... },
... {
... "description": "Server 2",
... "url": "example-2.com",
... },
... ],
... }
>>> patcher = OpenAPISchemaPatcher()
>>> patcher.register_tag({
... "name": "meringue",
... "x-displayName": "Meringue",
... })
>>> patcher.patch_tags(schema)
>>> print(schema)
{
"servers": [
{
"description": "Server 1",
"url": "https://example-1.com",
},
{
"description": "Server 2",
"url": "example-2.com",
},
],
"tags": [
{
"name": "meringue",
"x-displayName": "Meringue",
},
],
}
patch_schema¤
Fully patch the schema.
MeringueSpectacularAPIView¤
This view is a wrapper around the original SpectacularAPIView, but with the addition of a method that patches the OpenAPI schema.
from django.urls import path
from meringue.api.docs import OpenAPISchemaPatcher
from meringue.api.docs import MeringueSpectacularAPIView
patcher = OpenAPISchemaPatcher()
patcher.register_tag({
"name": "meringue",
"x-displayName": "Meringue",
})
urlpatterns = [
path("schema", MeringueSpectacularAPIView.as_view(patcher=patcher), name="schema"),
]