Source code for aiida_restapi.jsonapi.utils
"""JSON:API utilities."""
from __future__ import annotations
import typing as t
from dataclasses import dataclass, field
from fastapi import Request
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from aiida_restapi.jsonapi.models.base import JsonApiErrorDocument
CacheBucket = dict[str, tuple[t.Union[str, int], str, dict[str, t.Any], dict[str, t.Any]]]
[docs]
@dataclass
class IncludedItemParamsCache:
"""Per-request cache for the parameter of an included resources.
The cache is used to avoid recomputing the parameters of shared included resources (user, computer, etc.).
The cache is organized in buckets per resource type and maps to id: (id, type, attributes, foreign fields).
"""
buckets: dict[str, CacheBucket] = field(default_factory=dict)
[docs]
def bucket(self, resource_type: str) -> CacheBucket:
"""Get the cache bucket for a given resource type.
:param resource_type: The resource type.
:type resource_type: str
:return: The cache bucket for the resource type.
:rtype: CacheBucket
"""
try:
return self.buckets[resource_type]
except KeyError:
bucket: CacheBucket = {}
self.buckets[resource_type] = bucket
return bucket
[docs]
def jsonapi_error(
request: Request,
exception: Exception,
status_code: int,
) -> JSONResponse:
"""Generate a JSON:API compliant error response.
:param request: The incoming request.
:type request: Request
:param exception: The exception that was raised.
:type exception: Exception
:param status_code: The HTTP status code for the response.
:type status_code: int
:return: A JSON response containing the error in JSON:API format.
:rtype: JSONResponse
"""
return JSONResponse(
status_code=status_code,
content=jsonable_encoder(
obj=JsonApiErrorDocument(
links={
'self': str(request.url),
},
errors=[
{
'title': exception.__class__.__name__,
'status': str(status_code),
'detail': str(exception),
},
],
),
exclude_none=True,
),
)