Skip to content

Commit 18d4994

Browse files
Merge pull request #4 from OpenDataServices/1-get-datasets
Implement GET /datasets endpoint
2 parents b5364b2 + 8088d96 commit 18d4994

File tree

13 files changed

+430
-1
lines changed

13 files changed

+430
-1
lines changed

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: CI
2+
on: [push]
3+
4+
jobs:
5+
ci:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v4
9+
- uses: actions/setup-python@v5
10+
with:
11+
python-version: "3.12"
12+
- name: Install dev requirements
13+
run: pip install -r requirements_dev.txt
14+
- name: Install local package
15+
run: pip install .
16+
- name: Check black
17+
run: black --check oc4ids_datastore_api/ tests/
18+
- name: Check isort
19+
run: isort --check-only oc4ids_datastore_api/ tests/
20+
- name: Check flake8
21+
run: flake8 oc4ids_datastore_api/ tests/
22+
- name: Check mypy
23+
run: mypy oc4ids_datastore_api/ tests/
24+
- name: Run tests
25+
run: pytest

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.venv
2+
__pycache__

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.12

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,42 @@
1-
# oc4ids-datastore-api
1+
# OC4IDS Datastore API
2+
3+
## Local Development
4+
5+
### Prerequisites
6+
7+
- Python 3.12
8+
9+
### Install Python requirements
10+
11+
```
12+
python -m venv .venv
13+
source .venv/bin/activate
14+
pip install -r requirements_dev.txt
15+
```
16+
17+
### Set database enrivonment variable
18+
19+
With a read-only user, set the path to the already existing database, which is created by [oc4ids-datastore-pipeline](https://github.com/OpenDataServices/oc4ids-datastore-pipeline).
20+
21+
```
22+
export DATABASE_URL="postgresql://oc4ids_datastore_read_only@localhost/oc4ids_datastore"
23+
```
24+
25+
### Run app
26+
27+
```
28+
fastapi dev oc4ids_datastore_api/main.py
29+
```
30+
31+
### View the OpenAPI schema
32+
33+
While the app is running, go to `http://127.0.0.1:8000/docs/`
34+
35+
### Run linting and type checking
36+
37+
```
38+
black oc4ids_datastore_api/ tests/
39+
isort oc4ids_datastore_api/ tests/
40+
flake8 oc4ids_datastore_api/ tests/
41+
mypy oc4ids_datastore_api/ tests/
42+
```

oc4ids_datastore_api/__init__.py

Whitespace-only changes.

oc4ids_datastore_api/database.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import os
2+
from typing import Sequence
3+
4+
from sqlalchemy import Engine
5+
from sqlmodel import Session, create_engine, select
6+
7+
from oc4ids_datastore_api.models import DatasetSQLModel
8+
9+
_engine = None
10+
11+
12+
def get_engine() -> Engine:
13+
global _engine
14+
if _engine is None:
15+
_engine = create_engine(os.environ["DATABASE_URL"])
16+
return _engine
17+
18+
19+
def fetch_all_datasets() -> Sequence[DatasetSQLModel]:
20+
with Session(get_engine()) as session:
21+
return session.exec(select(DatasetSQLModel)).all()

oc4ids_datastore_api/main.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from fastapi import FastAPI
2+
3+
from oc4ids_datastore_api.schemas import Dataset
4+
from oc4ids_datastore_api.services import get_all_datasets
5+
6+
app = FastAPI()
7+
8+
9+
@app.get("/datasets")
10+
def get_datasets() -> list[Dataset]:
11+
return get_all_datasets()

oc4ids_datastore_api/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import datetime
2+
3+
from sqlmodel import Field, SQLModel
4+
5+
6+
class DatasetSQLModel(SQLModel, table=True):
7+
__tablename__ = "dataset"
8+
9+
dataset_id: str = Field(primary_key=True)
10+
source_url: str
11+
publisher_name: str
12+
license_url: str | None
13+
license_name: str | None
14+
json_url: str | None
15+
csv_url: str | None
16+
xlsx_url: str | None
17+
updated_at: datetime.datetime

oc4ids_datastore_api/schemas.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import datetime
2+
3+
from pydantic import BaseModel
4+
5+
6+
class Publisher(BaseModel):
7+
name: str
8+
9+
10+
class License(BaseModel):
11+
url: str | None
12+
name: str | None
13+
14+
15+
class Download(BaseModel):
16+
format: str
17+
url: str
18+
19+
20+
class Dataset(BaseModel):
21+
loaded_at: datetime.datetime
22+
source_url: str
23+
publisher: Publisher
24+
license: License
25+
downloads: list[Download]

oc4ids_datastore_api/services.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from oc4ids_datastore_api.database import fetch_all_datasets
2+
from oc4ids_datastore_api.models import DatasetSQLModel
3+
from oc4ids_datastore_api.schemas import Dataset, Download, License, Publisher
4+
5+
6+
def _transform_dataset(dataset: DatasetSQLModel) -> Dataset:
7+
download_urls = {
8+
"json": dataset.json_url,
9+
"csv": dataset.csv_url,
10+
"xlsx": dataset.xlsx_url,
11+
}
12+
downloads = [
13+
Download(format=format, url=url) for format, url in download_urls.items() if url
14+
]
15+
return Dataset(
16+
loaded_at=dataset.updated_at,
17+
source_url=dataset.source_url,
18+
publisher=Publisher(name=dataset.publisher_name),
19+
license=License(url=dataset.license_url, name=dataset.license_name),
20+
downloads=downloads,
21+
)
22+
23+
24+
def get_all_datasets() -> list[Dataset]:
25+
datasets = fetch_all_datasets()
26+
return [_transform_dataset(dataset) for dataset in datasets]

0 commit comments

Comments
 (0)