diff --git a/openapi/index_openapi.json b/openapi/index_openapi.json index 38b883057..264f294e3 100644 --- a/openapi/index_openapi.json +++ b/openapi/index_openapi.json @@ -1710,6 +1710,12 @@ "type": "string", "description": "response string from the server" }, + "request_delay": { + "title": "Request Delay", + "minimum": 0.0, + "type": "number", + "description": "A non-negative float giving time in seconds that the client is suggested to wait before issuing a subsequent request." + }, "implementation": { "title": "Implementation", "allOf": [ diff --git a/openapi/openapi.json b/openapi/openapi.json index 918a2965c..d3498d34e 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -3280,6 +3280,12 @@ "type": "string", "description": "response string from the server" }, + "request_delay": { + "title": "Request Delay", + "minimum": 0.0, + "type": "number", + "description": "A non-negative float giving time in seconds that the client is suggested to wait before issuing a subsequent request." + }, "implementation": { "title": "Implementation", "allOf": [ diff --git a/optimade/models/optimade_json.py b/optimade/models/optimade_json.py index bad738057..f611e18b6 100644 --- a/optimade/models/optimade_json.py +++ b/optimade/models/optimade_json.py @@ -4,7 +4,14 @@ from enum import Enum from typing import Any, Dict, List, Optional, Type, Union -from pydantic import AnyHttpUrl, AnyUrl, BaseModel, EmailStr, root_validator +from pydantic import ( + AnyHttpUrl, + AnyUrl, + BaseModel, + EmailStr, + NonNegativeFloat, + root_validator, +) from optimade.models import jsonapi from optimade.models.utils import SemanticVersion, StrictField @@ -313,6 +320,11 @@ class ResponseMeta(jsonapi.Meta): None, description="response string from the server" ) + request_delay: Optional[NonNegativeFloat] = StrictField( + None, + description="A non-negative float giving time in seconds that the client is suggested to wait before issuing a subsequent request.", + ) + implementation: Optional[Implementation] = StrictField( None, description="a dictionary describing the server implementation" ) diff --git a/optimade/server/config.py b/optimade/server/config.py index f763c336d..a5d820a58 100644 --- a/optimade/server/config.py +++ b/optimade/server/config.py @@ -292,6 +292,13 @@ class ServerConfig(BaseSettings): description="If True, the server will check whether the query parameters given in the request are correct.", ) + request_delay: Optional[float] = Field( + None, + description=( + "The value to use for the `meta->request_delay` field, which indicates to clients how long they should leave between success queries." + ), + ) + @validator("implementation", pre=True) def set_implementation_version(cls, v): """Set defaults and modify bypassed value(s)""" @@ -299,6 +306,13 @@ def set_implementation_version(cls, v): res.update(v) return res + @validator("request_delay", pre=True) + def check_request_delay(cls, v): + """Check `request_delay` is non-negative.""" + if v is not None and v < 0: + raise ValueError("`request_delay` must be non-negative") + return v + @root_validator(pre=True) def use_real_mongo_override(cls, values): """Overrides the `database_backend` setting with MongoDB and diff --git a/optimade/server/routers/utils.py b/optimade/server/routers/utils.py index ac19df72f..152f98370 100644 --- a/optimade/server/routers/utils.py +++ b/optimade/server/routers/utils.py @@ -76,6 +76,10 @@ def meta_values( if schema is None: schema = CONFIG.schema_url if not CONFIG.is_index else CONFIG.index_schema_url + if CONFIG.request_delay is not None: + # Add request delay via **kwargs only so that it is not set to null by default + kwargs["request_delay"] = CONFIG.request_delay + return ResponseMeta( query=ResponseMetaQuery(representation=f"{url_path}?{url.query}"), api_version=__api_version__,