Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
bc4894b
Implement node links endpoint
edan-bainglass Dec 22, 2025
969b2d7
Switch from pk to uuid for entity identifier
edan-bainglass Dec 22, 2025
49ab0a4
Add prefixes at the router layer
edan-bainglass Dec 22, 2025
ff7006e
Reorder routes in server endpoints endpoint
edan-bainglass Dec 28, 2025
6ae0738
Rename repository module as services
edan-bainglass Dec 28, 2025
f02d573
Discard docstrings
edan-bainglass Dec 29, 2025
3377748
Centralize error handling
edan-bainglass Dec 29, 2025
03baa47
Consolidate models
edan-bainglass Jan 1, 2026
bac7cb1
Rename `PaginatedResults.results` to `data`
edan-bainglass Jan 1, 2026
5422103
Peripheral cleanup
edan-bainglass Jan 1, 2026
28a73df
Fix docs
edan-bainglass Jan 1, 2026
d07fa71
Fix entrypoints
edan-bainglass Jan 2, 2026
90964b1
Add missing tests
edan-bainglass Jan 2, 2026
48d2eaf
Organize node endpoints
edan-bainglass Jan 2, 2026
4257379
Fix tests
edan-bainglass Jan 2, 2026
09a047f
Fix field name with an alias
edan-bainglass Jan 17, 2026
fc290f4
Implement related entity endpoints
edan-bainglass Jan 1, 2026
75298f0
Implement group-node endpoints
edan-bainglass Jan 2, 2026
a7a2983
Fix tests
edan-bainglass Jan 2, 2026
db68f7d
Flatten `get_related_many` results
edan-bainglass Jan 2, 2026
16a32e5
Change `download_format` query parameter to just `format`
edan-bainglass Jan 3, 2026
0fad0f9
Add missing docstring types
edan-bainglass Jan 17, 2026
a9e6537
Minimize use of `to_model`, especially when fetching many
edan-bainglass Jan 17, 2026
60aa98d
Implement JSON:API adapter layer
edan-bainglass Dec 30, 2025
d9c18b5
Fix implementation w.r.t changes in Aiida core Pydantic system
edan-bainglass May 16, 2026
5a4719a
Pin to aiida-core `main` branch
edan-bainglass May 15, 2026
077fd46
Drop Python 3.9 support
edan-bainglass May 16, 2026
242b52d
Fix mypy
edan-bainglass May 16, 2026
23777b1
Update pre-commit hooks
edan-bainglass May 16, 2026
44fbcce
Fix mypy
edan-bainglass May 16, 2026
7cf9046
Fix import
edan-bainglass May 16, 2026
0c31154
Fix tests
edan-bainglass May 15, 2026
da905cb
Add missing JSON:API treatment for `submit_process` endpoint
edan-bainglass May 16, 2026
b60b3d8
Pin RabbitMQ version in CI
edan-bainglass May 16, 2026
cdf0c4e
Refactor test endpoints
edan-bainglass Apr 3, 2026
8452207
Split attributes/constructor node creation endpoints
edan-bainglass Apr 3, 2026
cb24a70
Disallow constructor creation feature for nodes that do not support it
edan-bainglass Apr 3, 2026
b1f361b
Exclude legacy/abstract codes from POST creation
edan-bainglass Apr 3, 2026
105a4d3
Update docstrings and imports
edan-bainglass Apr 3, 2026
46ac347
Restore auth
edan-bainglass Apr 9, 2026
d1d0152
Fix mypy
edan-bainglass May 16, 2026
795b342
Fix test
edan-bainglass May 16, 2026
6d63800
Add proper authentication
edan-bainglass Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
- name: Checkout source
uses: actions/checkout@v2

- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: '3.9'
python-version: '3.10'

- name: Validate the tag version against the package version
run: python .github/workflows/validate_release_tag.py $GITHUB_REF
Expand All @@ -31,10 +31,10 @@ jobs:
- name: Checkout source
uses: actions/checkout@v2

- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: '3.9'
python-version: '3.10'

- name: Install flit
run: pip install flit~=3.4
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Set up Python 3.9
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: '3.9'
python-version: '3.10'

- uses: pre-commit/action@v3.0.1

Expand All @@ -27,7 +27,7 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11']
python-version: ['3.10', '3.11', '3.12']

services:
postgres:
Expand All @@ -44,9 +44,10 @@ jobs:
ports:
- 5432:5432
rabbitmq:
image: rabbitmq:latest
image: rabbitmq:3.8.14-management
ports:
- 5672:5672
- 15672:15672

steps:
- uses: actions/checkout@v2
Expand All @@ -69,7 +70,7 @@ jobs:
run: pytest --cov aiida_restapi --cov-report=xml

- name: Upload to Codecov
if: matrix.python-version == 3.8
if: matrix.python-version == 3.10
uses: codecov/codecov-action@v4
with:
name: pytests
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ repos:
exclude: *exclude_pre_commit_hooks

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
rev: v2.1.0
hooks:
- id: mypy
additional_dependencies:
Expand All @@ -36,18 +36,18 @@ repos:
)$

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.6
rev: 0.37.2
hooks:
- id: check-github-workflows

- repo: https://github.com/ikamensh/flynt/
rev: 1.0.1
rev: 1.0.6
hooks:
- id: flynt
args: [--line-length=120, --fail-on-change]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
rev: v0.15.13
hooks:
- id: ruff-format
exclude: &exclude_ruff >
Expand All @@ -60,7 +60,7 @@ repos:
args: [--fix, --exit-non-zero-on-fix, --show-fixes]

- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.13.0
rev: v2.16.0
hooks:
- id: pretty-format-toml
args: [--autofix, --trailing-commas]
Expand Down
52 changes: 47 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ Serve e.g. using [`uvicorn`](https://www.uvicorn.org/).

## Features

* `/users` (GET/POST) and `/users/<id>` (GET) endpoints
* Authentication via [JSON web tokens](https://jwt.io/introduction) (see `test_auth.py` for the flow; also works via interactive docs)
* `User` `pydantic` model for validation
* Automatic documentation at `http://127.0.0.1:8000/docs`
* Full specification at `http://127.0.0.1:8000/openapi.json`
- `/users` (GET/POST) and `/users/<id>` (GET) endpoints
- Authentication via [JSON web tokens](https://jwt.io/introduction) (see `test_auth.py` for the flow; also works via interactive docs)
- `User` `pydantic` model for validation
- Automatic documentation at `http://127.0.0.1:8000/docs`
- Full specification at `http://127.0.0.1:8000/openapi.json`

## Installation

Expand All @@ -34,6 +34,42 @@ uvicorn aiida_restapi:app
uvicorn aiida_restapi:app --reload
```

### Authentication setup

Password authentication now validates against:

1. An existing AiiDA user in the configured profile storage.
2. A credential mapping supplied through one of these environment variables:

```shell
# option 1: inline JSON
export AIIDA_RESTAPI_AUTH_CREDENTIALS_JSON='{"user@example.com": {"hashed_password": "$argon2id$...", "disabled": false}}'

# option 2: JSON file path
export AIIDA_RESTAPI_AUTH_CREDENTIALS_FILE=/path/to/auth-credentials.json
```

Only one source should be set at a time. The mapping is keyed by user email and accepts either:

```json
{
"user@example.com": "$argon2id$..."
}
```

or:

```json
{
"user@example.com": {
"hashed_password": "$argon2id$...",
"disabled": false
}
}
```

The `/auth/token` endpoint expects the email as username.

## Examples

See the [examples](https://github.com/aiidateam/aiida-restapi/tree/master/examples) directory.
Expand All @@ -48,13 +84,16 @@ cd aiida-restapi
### Setting up pre-commit

We use pre-commit to take care for the formatting, type checking and linting.

```shell
pip install -e .[pre-commit] # install extra dependencies
pre-commit run # running pre-commit on changes
pre-commit run --all-files # running pre-commit on every file
pre-commit run pylint --all-files # run only the linter on every file
```

One can also set up pre-commit to be run on every commit

```shell
pre-commit install
# pre-commit uninstall # to disable it again
Expand All @@ -63,13 +102,16 @@ pre-commit install
### Running tests

With tox the tests can be run

```shell
pip install tox
tox -e py311 # run all tests for Python 3.11
tox -av # see all supported environments
```

tox will creat a custom environment to run the tests in. If you want to run the
tests inside your current environment

```shell
pip install -e .[testing] # install extra dependencies
pytest -v
Expand Down
12 changes: 11 additions & 1 deletion aiida_restapi/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ def cli() -> None:
@click.option('--read-only', is_flag=True)
@click.option('--watch', is_flag=True)
def start(read_only: bool, watch: bool, host: str, port: int) -> None:
"""Start the AiiDA REST API service."""
"""Start the AiiDA REST API service.

:param read_only: If set, the API will be started in read-only mode.
:type read_only: bool
:param watch: If set, the API will watch for code changes and reload automatically.
:type watch: bool
:param host: The host address to bind the API service to.
:type host: str
:param port: The port number to bind the API service to.
:type port: int
"""

os.environ['AIIDA_RESTAPI_READ_ONLY'] = '1' if read_only else '0'

Expand Down
13 changes: 13 additions & 0 deletions aiida_restapi/common/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Common exception classes."""


class QueryBuilderException(Exception):
"""Exception raised for errors during QueryBuilder execution."""


class JsonApiException(Exception):
"""Base exception for JSON:API related errors."""


class SchemaNotSupported(Exception):
"""Exception raised when a node type does not support a particular schema type."""
7 changes: 2 additions & 5 deletions aiida_restapi/common/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
import typing as t

import pydantic as pdt
from aiida.orm import Entity

ResultType = t.TypeVar('ResultType', bound=Entity.Model)

__all__ = ('PaginatedResults',)
ResultType = t.TypeVar('ResultType')


class PaginatedResults(pdt.BaseModel, t.Generic[ResultType]):
total: int
page: int
page_size: int
results: list[ResultType]
data: list[ResultType]
Loading
Loading