Skip to content

structures

/gateways/{id}/structures/*

This file describes the router for:

/gateways/{id}/{version}/structures/{id}

where version and the last id may be left out.

get_single_structure(request, gateway_id, structure_id, params=Depends(NoneType)) async

GET /gateways/{gateway_id}/structures/{structure_id}

Return a regular /structures/{id} response for an OPTIMADE implementation. The structure_id must be of the type {database ID}/{id}.

Source code in optimade_gateway/routers/gateway/structures.py
@ROUTER.get(
    "/gateways/{gateway_id}/structures/{structure_id:path}",
    response_model=Union[StructureResponseOne, ErrorResponse],
    response_model_exclude_defaults=False,
    response_model_exclude_none=False,
    response_model_exclude_unset=True,
    tags=["Structures"],
)
async def get_single_structure(
    request: Request,
    gateway_id: str,
    structure_id: str,
    params: SingleEntryQueryParams = Depends(),
) -> StructureResponseOne:
    """`GET /gateways/{gateway_id}/structures/{structure_id}`

    Return a regular `/structures/{id}` response for an OPTIMADE implementation.
    The `structure_id` must be of the type `{database ID}/{id}`.
    """
    from optimade_gateway.models import GatewayResource
    from optimade_gateway.queries import db_find
    from optimade_gateway.routers.utils import get_valid_resource

    gateway: GatewayResource = await get_valid_resource(GATEWAYS_COLLECTION, gateway_id)

    local_structure_id = None
    for database in gateway.attributes.databases:
        if structure_id.startswith(f"{database.id}/"):
            # Database found
            local_structure_id = structure_id[len(f"{database.id}/") :]
            break
    else:
        raise BadRequest(
            detail=(
                f"Structures entry <id={structure_id}> not found. To get a specific structures entry "
                "one needs to prepend the ID with a database ID belonging to the gateway, e.g., "
                f"'{gateway.attributes.databases[0].id}/<local_database_ID>'. Available databases for "
                f"gateway {gateway_id!r}: {[_.id for _ in gateway.attributes.databases]}"
            )
        )

    errors = []
    result = None
    parsed_params = urllib.parse.urlencode(
        {param: value for param, value in params.__dict__.items() if value}
    )

    (response, _) = await asyncio.get_running_loop().run_in_executor(
        executor=None,  # Run in thread with the event loop
        func=functools.partial(
            db_find,
            database=database,
            endpoint=f"structures/{local_structure_id}",
            response_model=StructureResponseOne,
            query_params=parsed_params,
        ),
    )

    if isinstance(response, ErrorResponse):
        for error in response.errors:
            if isinstance(error.id, str) and error.id.startswith("OPTIMADE_GATEWAY"):
                warnings.warn(error.detail, OptimadeGatewayWarning)
            else:
                meta = {}
                if error.meta:
                    meta = error.meta.dict()
                meta.update(
                    {
                        "optimade_gateway": {
                            "gateway": gateway,
                            "source_database_id": database.id,
                        }
                    }
                )
                error.meta = Meta(**meta)
                errors.append(error)
    else:
        result = response.data
        if isinstance(result, dict) and result.get("id") is not None:
            result["id"] = f"{database.id}/{result['id']}"
        elif result is None:
            pass
        else:
            result.id = f"{database.id}/{result.id}"

    meta = meta_values(
        url=request.url,
        data_returned=response.meta.data_returned,
        data_available=None,  # Don't set this, as we'd have to request ALL gateway databases
        more_data_available=response.meta.more_data_available,
    )
    del meta.data_available

    if errors:
        return ErrorResponse(errors=errors, meta=meta)

    return StructureResponseOne(links=ToplevelLinks(next=None), data=result, meta=meta)

get_structures(request, gateway_id, params=Depends(NoneType)) async

GET /gateways/{gateway_id}/structures

Return a regular /structures response for an OPTIMADE implementation, including responses from all the gateway's databases.

Source code in optimade_gateway/routers/gateway/structures.py
@ROUTER.get(
    "/gateways/{gateway_id}/structures",
    response_model=Union[StructureResponseMany, ErrorResponse],
    response_model_exclude_defaults=False,
    response_model_exclude_none=False,
    response_model_exclude_unset=True,
    tags=["Structures"],
)
async def get_structures(
    request: Request,
    gateway_id: str,
    params: EntryListingQueryParams = Depends(),
) -> StructureResponseMany:
    """`GET /gateways/{gateway_id}/structures`

    Return a regular `/structures` response for an OPTIMADE implementation,
    including responses from all the gateway's databases.
    """
    from optimade_gateway.queries import perform_query
    from optimade_gateway.routers.utils import validate_resource

    await validate_resource(GATEWAYS_COLLECTION, gateway_id)

    if getattr(params, "sort", False):
        warnings.warn(SortNotSupported())
        params.sort = ""

    return await perform_query(
        url=request.url,
        query=QueryResource(
            **{
                "id": "temp",
                "type": "queries",
                "attributes": {
                    "last_modified": datetime.utcnow(),
                    "gateway_id": gateway_id,
                    "state": "created",
                    "query_parameters": {
                        key: value for key, value in params.__dict__.items() if value
                    },
                    "endpoint": "structures",
                    "endpoint_model": (
                        StructureResponseMany.__module__,
                        StructureResponseMany.__name__,
                    ),
                },
            }
        ),
        use_query_resource=False,
    )

get_versioned_single_structure(request, gateway_id, version, structure_id, params=Depends(NoneType)) async

GET /gateways/{gateway_id}/{version}/structures/{structure_id}

Same as GET /gateways/{gateway_id}/structures/{structure_id}.

Source code in optimade_gateway/routers/gateway/structures.py
@ROUTER.get(
    "/gateways/{gateway_id}/{version}/structures/{structure_id:path}",
    response_model=Union[StructureResponseOne, ErrorResponse],
    response_model_exclude_defaults=False,
    response_model_exclude_none=False,
    response_model_exclude_unset=True,
    tags=["Structures"],
    include_in_schema=False,
)
async def get_versioned_single_structure(
    request: Request,
    gateway_id: str,
    version: str,
    structure_id: str,
    params: SingleEntryQueryParams = Depends(),
) -> StructureResponseOne:
    """`GET /gateways/{gateway_id}/{version}/structures/{structure_id}`

    Same as `GET /gateways/{gateway_id}/structures/{structure_id}`.
    """
    await validate_version(version)
    return await get_single_structure(request, gateway_id, structure_id, params)

get_versioned_structures(request, gateway_id, version, params=Depends(NoneType)) async

GET /gateways/{gateway_id}/{version}/structures

Same as GET /gateways/{gateway_id}/structures.

Source code in optimade_gateway/routers/gateway/structures.py
@ROUTER.get(
    "/gateways/{gateway_id}/{version}/structures",
    response_model=Union[StructureResponseMany, ErrorResponse],
    response_model_exclude_defaults=False,
    response_model_exclude_none=False,
    response_model_exclude_unset=True,
    tags=["Structures"],
    include_in_schema=False,
)
async def get_versioned_structures(
    request: Request,
    gateway_id: str,
    version: str,
    params: EntryListingQueryParams = Depends(),
) -> StructureResponseMany:
    """`GET /gateways/{gateway_id}/{version}/structures`

    Same as `GET /gateways/{gateway_id}/structures`.
    """
    await validate_version(version)
    return await get_structures(request, gateway_id, params)
Back to top