Skip to content

index_info

CONFIG: ServerConfig = ServerConfig() module-attribute

This singleton loads the config from a hierarchy of sources (see customise_sources) and makes it importable in the server code.

ERROR_RESPONSES: Optional[dict[int, dict[str, Any]]] = {err.status_code: {'model': ErrorResponse, 'description': err.title}for err in POSSIBLE_ERRORS} module-attribute

__api_version__ = '1.1.0' module-attribute

router = APIRouter(redirect_slashes=True) module-attribute

IndexInfoAttributes

Bases: BaseInfoAttributes

Attributes for Base URL Info endpoint for an Index Meta-Database

Source code in optimade/models/index_metadb.py
17
18
19
20
21
22
23
24
25
class IndexInfoAttributes(BaseInfoAttributes):
    """Attributes for Base URL Info endpoint for an Index Meta-Database"""

    is_index: Annotated[
        bool,
        StrictField(
            description="This must be `true` since this is an index meta-database (see section Index Meta-Database).",
        ),
    ] = True

IndexInfoResource

Bases: BaseInfoResource

Index Meta-Database Base URL Info endpoint resource

Source code in optimade/models/index_metadb.py
46
47
48
49
50
51
52
53
54
55
56
57
class IndexInfoResource(BaseInfoResource):
    """Index Meta-Database Base URL Info endpoint resource"""

    attributes: IndexInfoAttributes
    relationships: Annotated[  # type: ignore[assignment]
        Optional[dict[Literal["default"], IndexRelationship]],
        StrictField(
            title="Relationships",
            description="""Reference to the Links identifier object under the `links` endpoint that the provider has chosen as their 'default' OPTIMADE API database.
A client SHOULD present this database as the first choice when an end-user chooses this provider.""",
        ),
    ]

IndexInfoResponse

Bases: Success

Source code in optimade/models/responses.py
53
54
55
56
class IndexInfoResponse(Success):
    data: Annotated[
        IndexInfoResource, StrictField(description="Index meta-database /info data.")
    ]

model_config = ConfigDict(json_encoders={datetime: lambda : v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
387
388
389
390
391
392
393
394
395
396
397
398
399
400
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

IndexRelationship

Bases: BaseModel

Index Meta-Database relationship

Source code in optimade/models/index_metadb.py
34
35
36
37
38
39
40
41
42
43
class IndexRelationship(BaseModel):
    """Index Meta-Database relationship"""

    data: Annotated[
        Optional[RelatedLinksResource],
        StrictField(
            description="""[JSON API resource linkage](http://jsonapi.org/format/1.0/#document-links).
It MUST be either `null` or contain a single Links identifier object with the fields `id` and `type`""",
        ),
    ]

RelatedLinksResource

Bases: BaseResource

A related Links resource object

Source code in optimade/models/index_metadb.py
28
29
30
31
class RelatedLinksResource(BaseResource):
    """A related Links resource object"""

    type: Literal["links"] = "links"

get_base_url(parsed_url_request)

Get base URL for current server

Take the base URL from the config file, if it exists, otherwise use the request.

Source code in optimade/server/routers/utils.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def get_base_url(
    parsed_url_request: Union[
        urllib.parse.ParseResult, urllib.parse.SplitResult, StarletteURL, str
    ]
) -> str:
    """Get base URL for current server

    Take the base URL from the config file, if it exists, otherwise use the request.
    """
    parsed_url_request = (
        urllib.parse.urlparse(parsed_url_request)
        if isinstance(parsed_url_request, str)
        else parsed_url_request
    )
    return (
        CONFIG.base_url.rstrip("/")
        if CONFIG.base_url
        else f"{parsed_url_request.scheme}://{parsed_url_request.netloc}"
    )

get_info(request)

Source code in optimade/server/routers/index_info.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@router.get(
    "/info",
    response_model=IndexInfoResponse,
    response_model_exclude_unset=True,
    tags=["Info"],
    responses=ERROR_RESPONSES,
)
def get_info(request: Request) -> IndexInfoResponse:
    return IndexInfoResponse(
        meta=meta_values(
            request.url,
            1,
            1,
            more_data_available=False,
            schema=CONFIG.index_schema_url,
        ),
        data=IndexInfoResource(
            id=IndexInfoResource.model_fields["id"].default,
            type=IndexInfoResource.model_fields["type"].default,
            attributes=IndexInfoAttributes(
                api_version=f"{__api_version__}",
                available_api_versions=[
                    {
                        "url": f"{get_base_url(request.url)}/v{__api_version__.split('.')[0]}/",
                        "version": f"{__api_version__}",
                    }
                ],
                formats=["json"],
                available_endpoints=["info", "links"],
                entry_types_by_format={"json": []},
                is_index=True,
            ),
            relationships={
                "default": IndexRelationship(
                    data={
                        "type": RelatedLinksResource.model_fields["type"].default,
                        "id": CONFIG.default_db,
                    }
                )
            },
        ),
    )

meta_values(url, data_returned, data_available, more_data_available, schema=None, **kwargs)

Helper to initialize the meta values

Source code in optimade/server/routers/utils.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def meta_values(
    url: Union[urllib.parse.ParseResult, urllib.parse.SplitResult, StarletteURL, str],
    data_returned: Optional[int],
    data_available: int,
    more_data_available: bool,
    schema: Optional[str] = None,
    **kwargs,
) -> ResponseMeta:
    """Helper to initialize the meta values"""
    from optimade.models import ResponseMetaQuery

    if isinstance(url, str):
        url = urllib.parse.urlparse(url)

    # To catch all (valid) variations of the version part of the URL, a regex is used
    if re.match(r"/v[0-9]+(\.[0-9]+){,2}/.*", url.path) is not None:
        url_path = re.sub(r"/v[0-9]+(\.[0-9]+){,2}/", "/", url.path)
    else:
        url_path = url.path

    if schema is None:
        schema = CONFIG.schema_url if not CONFIG.is_index else CONFIG.index_schema_url

    return ResponseMeta(
        query=ResponseMetaQuery(representation=f"{url_path}?{url.query}"),
        api_version=__api_version__,
        time_stamp=datetime.now(),
        data_returned=data_returned,
        more_data_available=more_data_available,
        provider=CONFIG.provider,
        data_available=data_available,
        implementation=CONFIG.implementation,
        schema=schema,
        **kwargs,
    )