OpenAPI Integration
Arrest additionally offers integration to OpenAPI specification (formerly Swagger).
With it, you can generate the necessary boilerplates for Arrest services and resources directly from the API route specifications. Arrest uses datamodel-code-generator under the hood to generate the data transfer models in Pydantic, and add Arrest resource and service templates on top of that.
Note
this feature is experimental and does not quite cover the extensive range of features of OpenAPI specification. We will be gradually rolling out new features from OpenAPI specification that also suits the functionalities of Arrest.
Usage¶
pip install "arrest[openapi]"
poetry add 'arrest[openapi]'
This installs two additional dependencies.
Once installed, you can use the CLI interface to provide a OpenAPI Specification url (http or a filepath) and it will generate the files from the spec.
arrest --url https://petstore3.swagger.io/api/v3/openapi.json
This generates 3 files.
1. models.py
- a file containing all the schema definitions found in the OpenAPI Spec /components/schemas
, generated by datamodel-code-generator
-
resources.py
- a set of Arrest resource definitions based on the defined routes in the Spec/paths
-
services.py
- a list of Arrest services based on the Spec/servers
, if there is a server definition withserverVariables
, Arrest will generate as many service instance as there are unique server urls from all the combinations ofserverVariables
Example
>>> arrest --url https://petstore3.swagger.io/api/v3.1/openapi_3.1.json -o path/to/destination
this will create a directory named swagger_petstore_openapi_3_1
(based on the title
in the OpenAPI specification) in path/to/destination
, inside which it will generate the following
# swagger_petstore_openapi_3_1/models.py
# generated by datamodel-codegen:
# filename: <stdin>
# timestamp: 2024-01-29T18:57:34+00:00
from __future__ import annotations
from typing import List, Optional
from pydantic import BaseModel
class Pet(BaseModel):
id: int
name: str
tag: Optional[str] = None
class Pets(BaseModel):
__root__: List[Pet]
class Error(BaseModel):
code: int
message: str
# swagger_petstore_openapi_3_1/resources.py
from arrest import Resource
from .models import Pet, Pets
pets = Resource(
name="pets",
route="/pets",
handlers=[
("GET", "", None, Pets),
("POST", "", None, None),
("GET", "/{petId}", None, Pet),
]
)
# swagger_petstore_openapi_3_1/services.py
from arrest import Service
from .resources import pet, store, user
swagger_petstore_openapi_3_0 = Service(
name="swagger_petstore_openapi_3_0",
url="/api/v3",
resources=[pet, store, user]
)
The files generated are not black-formatted or isort-formatted. Hence further customization is left to the user.
CLI Arguments¶
usage:
arrest [options] --help
generate arrest services and resources from various definitions
options:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
output directory for generated files (default: current working directory)
--pydantic {v1,v2} pydantic version to generate the schema definitions
-u URL, --url URL HTTP or file url for the openapi schema
-d DIR, --dir DIR Folder containing the files (default: OpenAPI specification title)
By default Arrest will look for the title
of the specification and use that to name the directory that contains these files.
If it can't find one, it will use api
as the directory name instead.
Alternatively you can specify your own custom name by providing -d
or --dir
--pydantic
is used to denote the pydantic version (v1
or v2
) that the generated schema definitions will use (defaults to v1
)
What works and what does not¶
-
Currently, Arrest is able to only work on singular pydantic types and not types like
list[BaseModel]
ordict[str, BaseModel]
as request / response models. As a result, schema definitions in OpenAPI that are of the following types:are not parsed. Same for any schema definitions that don't have a{ "type": "array", "items": { "$ref": "#/components/Schemas/User" } }
$ref
to a model definition. -
Parameters
such as path or query or headers are not parsed currently. Although formatted path interpolation is available. If your path definition is something like/abc/{xyz}
, the Arrest resourceabc
will have a handler with path/{xyz}
and you can passxyz
as a kwarg when calling this route.
Example
abc = Resource(
name="abc",
route="/abc",
handlers=[
("GET", "/{xyz}", None, None),
]
)
await my_service.abc.get(xyz=123)
# or
await my_service.abc.get("/123")
- OpenAPI Security definitions are not parsed.
There is a bit of manual intervention needed if the extraction from the OpenAPI Spec is incomplete.
You can subclass the generated schema classes and add extra parameters as Header()
or Query()
parameters.
Additionally, you can use it as a module and extend its functionalities.
from arrest.openapi import OpenAPIGenerator
...
For more info, check the API Documentation