pydanja


Namepydanja JSON
Version 0.1.18 PyPI version JSON
download
home_pagehttps://github.com/Centurix/pydanja
SummaryJSON:API Support for Pydantic
upload_time2024-04-30 07:43:56
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords pydantic jsonapi json:api openapi fastapi
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![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"
}
        
Elapsed time: 0.27754s