JSON:API Support for Pydantic
Project description
PyDANJA
JSON:API (or JSONAPI) Suport for Pydantic
This is a series of classes that can be included into your Pydantic project that act as a container format for outputting and verifying JSON:API compliant content.
This library makes use of BaseModel generics to contain either a single resource or a list of resources as further BaseModels.
Installation
pip install pydanja
Requirements
This will support the oldest non-EOL Python (3.8 as of the writing of this document)
Usage
With pydantic
from pydanja import DANJAResource
class TestType(BaseModel):
"""A simple Pydantic BaseModel"""
# We use an extra resource_id to indicate the ID for JSON:API
testtype_id: Optional[int] = Field(
alias="id",
default=None,
json_schema_extra={
"resource_id": True
}
)
name: str
description: str
resource_container = DANJAResource.from_basemodel(TestType(
id=1,
name="Stuff!",
description="This is desc!"
))
print(resource_container.model_dump_json(indent=2))
# The BaseModel contained resource can be acquired by
resource = resource_container.resource
This basic example shows a Pydantic BaseModel being contained within a DANJAResource
object. The model_dump_json
will output JSON:API:
{
"data": {
"id": "1",
"type": "testtype",
"lid": null,
"attributes": {
"testtype_id": 1,
"name": "Stuff!",
"description": "This is desc!"
},
"relationships": null,
"links": null,
"meta": null
},
"links": null,
"meta": null,
"included": null
}
Note that all JSON:API fields are included in the output of the model dump. If you are using an API framework like FastAPI, you use the response_model_exclude_none
to suppress fields with no values.
FastAPI example
from typing import Optional, Union
from pydantic import BaseModel, Field, ConfigDict
from fastapi import FastAPI
from pydanja import DANJAResource, DANJAResourceList, DANJAError
app = FastAPI()
# Example BaseModel
class TestType(BaseModel):
# If we use ID, then we must alias it to avoid clashes with Python
testtype_id: Optional[int] = Field(
alias="id",
default=None,
json_schema_extra={
"resource_id": True
}
)
name: str
description: str
@app.post("/", response_model_exclude_none=True)
async def test_func(payload: DANJAResource[TestType]) -> Union[DANJAResource[TestType], DANJAError]:
"""
payload will be verified correctly for inbound JSON:API content
The Union includes a reference to the JSON:API error object that this could throw
"""
res = TestType(
id=1,
name="Stuff!",
description="This is description!"
)
return DANJAResource.from_basemodel(res)
@app.get("/", response_model_exclude_none=True)
async def test_get() -> Union[DANJAResourceList[TestType], DANJAError]:
values = [
TestType(id=1, name="One", description="Desc One"),
TestType(id=2, name="Two", description="Desc Two"),
TestType(id=3, name="Three", description="Desc Three"),
TestType(id=4, name="Four", description="Desc Four"),
]
return DANJAResourceList.from_basemodel_list(values)
This library supports:
- Single resources (
DANJAResource
) - Lists of resources (
DANJAResourceList
) - Error objects (
DANJAErrorList
/DANJAError
) - Link objects (
DANJALink
)
There are more examples, including FastAPI code in the src/examples
directory.
Future Enhancements
- At the moment, the schema output from FastAPI includes the intermediary objects needed for the heirarchy in JSON:API, these should be suppressed
- The type names in the API output also include the full canonical generic class names and the contained class name, this should reduce to just the contained class name
Contributing
This project uses PDM for dependency and virtual environment management.
It aims to use the lowest supported Python version (3.8 as of the writing of this document)
There are currently three build steps in the actions workflow:
- Unit test
- Linting
- Type checking
These can be run through PDM by using:
pdm run lint
pdm run test
pdm run typecheck
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.