![build workflow](https://github.com/Centurix/pydanja/actions/workflows/python-app.yml/badge.svg)
![pypi](https://img.shields.io/pypi/v/pydanja)
![licence](https://img.shields.io/github/license/Centurix/pydanja.svg)
![status](https://img.shields.io/pypi/status/pydanja)
![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)
# PyDANJA
**PyDAN**<sub>tic</sub> **J**<sub>SON</sub>**A**<sub>PI</sub>
[JSON:API (or JSONAPI)](https://jsonapi.org/format/) Suport for [Pydantic](https://docs.pydantic.dev/latest/)
Output [JSONAPI](https://jsonapi.org/format/) from your [FastAPI](https://fastapi.tiangolo.com/) or [PyDantic](https://docs.pydantic.dev/latest/) based application with very little code.
This is a series of classes that can be included into your [Pydantic](https://docs.pydantic.dev/latest/) project that act as a container format for outputting and verifying [JSON:API](https://jsonapi.org/format/) 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](https://docs.pydantic.dev/latest/) BaseModel being contained within a `DANJAResource` object. The `model_dump_json` will output [JSON:API](https://jsonapi.org/format/):
```
{
"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](https://jsonapi.org/format/) fields are included in the output of the model dump. If you are using an API framework like [FastAPI](https://fastapi.tiangolo.com/), 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, danja_openapi
from fastapi.openapi.utils import get_openapi
app = FastAPI()
# Optional: Clear up the OpenAPI documentation by de-cluttering schema
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="FastAPI",
version="2.5.0",
summary="FastAPI",
description="FastAPI",
routes=app.routes,
)
app.openapi_schema = danja_openapi(openapi_schema)
return app.openapi_schema
app.openapi = custom_openapi
# 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](https://fastapi.tiangolo.com/) code in the `src/examples` directory.
### Contributing
This project uses [PDM](https://pdm.fming.dev/latest/) 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`
Raw data
{
"_id": null,
"home_page": "https://github.com/Centurix/pydanja",
"name": "pydanja",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "pydantic, jsonapi, json:api, openapi, fastapi",
"author": null,
"author_email": "Chris Read <centurix@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/a8/dd/269d981ecc74ce631e66b0968f6d0c495fa5bb833171920c5d37b9eb63bd/pydanja-0.1.18.tar.gz",
"platform": null,
"description": "![build workflow](https://github.com/Centurix/pydanja/actions/workflows/python-app.yml/badge.svg)\n![pypi](https://img.shields.io/pypi/v/pydanja)\n![licence](https://img.shields.io/github/license/Centurix/pydanja.svg)\n![status](https://img.shields.io/pypi/status/pydanja)\n![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)\n\n# PyDANJA\n\n**PyDAN**<sub>tic</sub> **J**<sub>SON</sub>**A**<sub>PI</sub>\n\n\n[JSON:API (or JSONAPI)](https://jsonapi.org/format/) Suport for [Pydantic](https://docs.pydantic.dev/latest/)\n\nOutput [JSONAPI](https://jsonapi.org/format/) from your [FastAPI](https://fastapi.tiangolo.com/) or [PyDantic](https://docs.pydantic.dev/latest/) based application with very little code.\n\nThis is a series of classes that can be included into your [Pydantic](https://docs.pydantic.dev/latest/) project that act as a container format for outputting and verifying [JSON:API](https://jsonapi.org/format/) compliant content.\n\nThis library makes use of BaseModel generics to contain either a single resource or a list of resources as further BaseModels.\n\n## Installation\n\n`pip install pydanja`\n\n## Requirements\n\nThis will support the oldest non-EOL Python (3.8 as of the writing of this document)\n\n## Usage\n\nWith pydantic\n\n```\nfrom pydanja import DANJAResource\n\n\nclass TestType(BaseModel):\n \"\"\"A simple Pydantic BaseModel\"\"\"\n # We use an extra resource_id to indicate the ID for JSON:API\n testtype_id: Optional[int] = Field(\n alias=\"id\",\n default=None,\n json_schema_extra={\n \"resource_id\": True\n }\n )\n name: str\n description: str\n\n\nresource_container = DANJAResource.from_basemodel(TestType(\n id=1,\n name=\"Stuff!\",\n description=\"This is desc!\"\n))\nprint(resource_container.model_dump_json(indent=2))\n\n# The BaseModel contained resource can be acquired by\nresource = resource_container.resource\n```\n\nThis basic example shows a [Pydantic](https://docs.pydantic.dev/latest/) BaseModel being contained within a `DANJAResource` object. The `model_dump_json` will output [JSON:API](https://jsonapi.org/format/):\n\n```\n{\n \"data\": {\n \"id\": \"1\",\n \"type\": \"testtype\",\n \"lid\": null,\n \"attributes\": {\n \"testtype_id\": 1,\n \"name\": \"Stuff!\",\n \"description\": \"This is desc!\"\n },\n \"relationships\": null,\n \"links\": null,\n \"meta\": null\n },\n \"links\": null,\n \"meta\": null,\n \"included\": null\n}\n```\n\nNote that all [JSON:API](https://jsonapi.org/format/) fields are included in the output of the model dump. If you are using an API framework like [FastAPI](https://fastapi.tiangolo.com/), you use the `response_model_exclude_none` to suppress fields with no values.\n\n### FastAPI example\n\n```\nfrom typing import Optional, Union\nfrom pydantic import BaseModel, Field, ConfigDict\nfrom fastapi import FastAPI\nfrom pydanja import DANJAResource, DANJAResourceList, DANJAError, danja_openapi\nfrom fastapi.openapi.utils import get_openapi\n\n\napp = FastAPI()\n\n\n# Optional: Clear up the OpenAPI documentation by de-cluttering schema\ndef custom_openapi():\n if app.openapi_schema:\n return app.openapi_schema\n\n openapi_schema = get_openapi(\n title=\"FastAPI\",\n version=\"2.5.0\",\n summary=\"FastAPI\",\n description=\"FastAPI\",\n routes=app.routes,\n )\n\n app.openapi_schema = danja_openapi(openapi_schema)\n\n return app.openapi_schema\n\napp.openapi = custom_openapi\n\n\n\n# Example BaseModel\nclass TestType(BaseModel):\n # If we use ID, then we must alias it to avoid clashes with Python\n testtype_id: Optional[int] = Field(\n alias=\"id\",\n default=None,\n json_schema_extra={\n \"resource_id\": True\n }\n )\n name: str\n description: str\n\n\n@app.post(\"/\", response_model_exclude_none=True)\nasync def test_func(payload: DANJAResource[TestType]) -> Union[DANJAResource[TestType], DANJAError]:\n \"\"\"\n payload will be verified correctly for inbound JSON:API content\n The Union includes a reference to the JSON:API error object that this could throw\n \"\"\"\n res = TestType(\n id=1,\n name=\"Stuff!\",\n description=\"This is description!\"\n )\n return DANJAResource.from_basemodel(res)\n\n@app.get(\"/\", response_model_exclude_none=True)\nasync def test_get() -> Union[DANJAResourceList[TestType], DANJAError]:\n values = [\n TestType(id=1, name=\"One\", description=\"Desc One\"),\n TestType(id=2, name=\"Two\", description=\"Desc Two\"),\n TestType(id=3, name=\"Three\", description=\"Desc Three\"),\n TestType(id=4, name=\"Four\", description=\"Desc Four\"),\n ]\n return DANJAResourceList.from_basemodel_list(values)\n```\n\nThis library supports:\n\n* Single resources (`DANJAResource`)\n* Lists of resources (`DANJAResourceList`)\n* Error objects (`DANJAErrorList`/`DANJAError`)\n* Link objects (`DANJALink`)\n\nThere are more examples, including [FastAPI](https://fastapi.tiangolo.com/) code in the `src/examples` directory.\n\n\n### Contributing\n\nThis project uses [PDM](https://pdm.fming.dev/latest/) for dependency and virtual environment management.\n\nIt aims to use the lowest supported Python version (3.8 as of the writing of this document)\n\nThere are currently three build steps in the actions workflow:\n\n* Unit test\n* Linting\n* Type checking\n\nThese can be run through PDM by using:\n\n* `pdm run lint`\n* `pdm run test`\n* `pdm run typecheck`\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "JSON:API Support for Pydantic",
"version": "0.1.18",
"project_urls": {
"Documentation": "https://pydanja.readthedocs.io/en/latest/",
"Homepage": "https://github.com/Centurix/pydanja",
"Repository": "https://github.com/Centurix/pydanja"
},
"split_keywords": [
"pydantic",
" jsonapi",
" json:api",
" openapi",
" fastapi"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "4b9bd47ec88c46b405195c240ae0f812454f769fd089ecd6238289209e082b31",
"md5": "c879374761dd8f388d307040eac67d9b",
"sha256": "21db34cfc12e60f3a211b23c1a7053574b9860d25b9663e69076d4e6df9aa126"
},
"downloads": -1,
"filename": "pydanja-0.1.18-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c879374761dd8f388d307040eac67d9b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 6608,
"upload_time": "2024-04-30T07:43:54",
"upload_time_iso_8601": "2024-04-30T07:43:54.934640Z",
"url": "https://files.pythonhosted.org/packages/4b/9b/d47ec88c46b405195c240ae0f812454f769fd089ecd6238289209e082b31/pydanja-0.1.18-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a8dd269d981ecc74ce631e66b0968f6d0c495fa5bb833171920c5d37b9eb63bd",
"md5": "dce21d88bf541db978ff3a737dc9ca6e",
"sha256": "d4505325adc86a748d910231fd2a903a12f3155996a40f495443dcc8ab7c0372"
},
"downloads": -1,
"filename": "pydanja-0.1.18.tar.gz",
"has_sig": false,
"md5_digest": "dce21d88bf541db978ff3a737dc9ca6e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 9894,
"upload_time": "2024-04-30T07:43:56",
"upload_time_iso_8601": "2024-04-30T07:43:56.542933Z",
"url": "https://files.pythonhosted.org/packages/a8/dd/269d981ecc74ce631e66b0968f6d0c495fa5bb833171920c5d37b9eb63bd/pydanja-0.1.18.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-30 07:43:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Centurix",
"github_project": "pydanja",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pydanja"
}