Skip to content

Commit a3535a3

Browse files
sphuberagoscinski
authored andcommitted
Config: Add the read_only setting
This setting, which is set to `True` by default, will determine whether the instance is to be read-only. The `protected_methods_middleware` function is added as middleware to the application. If the `read_only` setting is `True` and the request method is `DELETE`, `PATCH`, `POST` or `PUT`, a `405 Method Not Allowed` response is returned.
1 parent d92009c commit a3535a3

File tree

4 files changed

+54
-0
lines changed

4 files changed

+54
-0
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ uvicorn aiida_restapi:app
3434
uvicorn aiida_restapi:app --reload
3535
```
3636

37+
By default all endpoints of the REST API are available.
38+
The API can be made *read-only* by setting the `read_only` configuration settings to `True`.
39+
This can either be done by setting the environment variable:
40+
```bash
41+
export READ_ONLY=True
42+
```
43+
or by adding the following to the `.env` file:
44+
```ini
45+
read_only=true
46+
```
47+
When the API is read-only, all `DELETE`, `PATCH`, `POST` and `PUT` requests will result in a `405 - Method Not Allowed` response.
48+
3749
## Examples
3850

3951
See the [examples](https://github.com/aiidateam/aiida-restapi/tree/master/examples) directory.

aiida_restapi/config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
class Settings(BaseSettings):
1515
"""Configuration settings for the application."""
1616

17+
# pylint: disable=too-few-public-methods
18+
19+
class Config:
20+
"""Config settings."""
21+
22+
env_file = '.env'
23+
env_file_encoding = 'utf-8'
24+
1725
secret_key: str = '09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7'
1826
"""The secret key used to create access tokens."""
1927

@@ -23,6 +31,9 @@ class Settings(BaseSettings):
2331
access_token_expire_minutes: int = 30
2432
"""The number of minutes an access token remains valid."""
2533

34+
read_only: bool = False
35+
"""Whether the instance is read-only. If set to ``True`` all DELETE, PATCH, POST and PUT methods will raise 405."""
36+
2637

2738
@lru_cache()
2839
def get_settings() -> Settings:

aiida_restapi/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
from aiida_restapi.graphql import main
66
from aiida_restapi.routers import auth, computers, daemon, groups, nodes, process, users
77

8+
from .middleware import protected_methods_middleware
9+
810
app = FastAPI()
11+
12+
app.middleware('http')(protected_methods_middleware)
13+
914
app.include_router(auth.router)
1015
app.include_router(computers.router)
1116
app.include_router(daemon.router)

aiida_restapi/middleware.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Module with middleware."""
2+
3+
from typing import Callable
4+
5+
from fastapi import Request, Response
6+
from fastapi.encoders import jsonable_encoder
7+
from fastapi.responses import JSONResponse
8+
9+
from .config import Settings, get_settings
10+
11+
12+
async def protected_methods_middleware(request: Request, call_next: Callable[[Request], Response]) -> Response:
13+
"""Middleware that will return a 405 if the instance is read only and the request method is mutating.
14+
15+
Mutating request methods are `DELETE`, `PATCH`, `POST`, `PUT`.
16+
"""
17+
settings: Settings = get_settings()
18+
19+
if settings.read_only and request.method in {'DELETE', 'PATCH', 'POST', 'PUT'}:
20+
return JSONResponse(
21+
status_code=405,
22+
content=jsonable_encoder({'reason': 'This instance is read-only.'}),
23+
media_type='application/json',
24+
)
25+
26+
return await call_next(request)

0 commit comments

Comments
 (0)