Skip to content

API Schemas and Auth.md

Kelsey Smuczynski edited this page Mar 24, 2026 · 1 revision

API Schemas and Auth

API Organization

REST routes are grouped by resource module under api/. The currently registered routers are:

  • /asset
  • /author
  • /contact
  • /geospatial
  • /group
  • /lexicon
  • /location
  • /observation
  • /publication
  • /sample
  • /sensor
  • /search
  • /thing
  • /ngwmn

Additional API modules exist in the repo (geothermal, form, collabnet, series, well-inventory) that are currently commented out or not registered.


Schema Organization

Pydantic schemas live under schemas/ and follow this pattern:

Schema Type Purpose
Create* Create payloads
Update* Patch/update payloads
*Response Response serialization

Common patterns:

  • Validation is handled with field and model validators
  • Spatial responses often convert geometry into WKT or GeoJSON-like structures
  • Observation schemas normalize timestamps to UTC
  • Response schemas frequently compose related data for API convenience

Schema Field Conventions

  • Create schemas: Required fields as <type>, optional fields as <type> | None = None
  • Update schemas: All fields optional with None default
  • Response schemas: Explicitly define all return types

Database Model Conventions

  • Models inherit from Base and include AutoBaseMixin
  • Use ReleaseMixin for entities that require visibility control
  • Use DataProvenanceMixin for tracking data source methods

Validation Strategy

Two layers of validation protect the API:

Layer Error Code Description
Pydantic 422 Format, type, and range validation on incoming JSON
Service / DB 409 Logical constraints (e.g., duplicate location names) checked within the service layer

Never use standard HTTPException directly. Use PydanticStyleException for consistency:

from services.exceptions_helper import PydanticStyleException

raise PydanticStyleException(
    status_code=409,
    detail=[{
        "loc": ["body", "location_name"],
        "msg": "Location already exists.",
        "type": "duplicate_value"
    }]
)

Auth Model

core.dependencies defines role-based dependencies:

Role Access
Viewer / AMPViewer Read
Editor / AMPEditor Update
Admin / AMPAdmin Create + Delete
LexiconEditor Lexicon write
LexiconAdmin Lexicon admin

This pattern is visible in router implementations such as location, group, and observation.


Auth Provider

  • OAuth/OIDC configuration points at Authentik
  • JWT verification is handled in core.permissions
  • The admin UI uses its own auth provider in admin/auth.py, but reuses the same JWT verification logic
  • In non-production mode, AUTHENTIK_DISABLE_AUTHENTICATION=1 allows bypass behavior

OpenAPI Surfaces

Surface URL Notes
Public schema default /openapi.json Filtered to routes marked public_route
Authenticated schema /openapi-auth.json Full schema
Authenticated Swagger /docs-auth Configures OAuth PKCE

Important Caveat About "Public" Routes

The "public" OpenAPI filter is documentation-driven, not a runtime access guarantee. Routes explicitly marked public_route in api/thing.py still depend on viewer_dependency, meaning:

  • They appear in the public schema
  • They may still require authentication at runtime unless auth is disabled

If truly anonymous access is intended, verify and update the code accordingly.


Notable API Workflows

  • Bulk groundwater upload: POST /observation/groundwater-level/bulk-upload
  • Search: GET /search — aggregates contacts, things, and assets
  • OGC API: pygeoapi provides a parallel geospatial read surface at /ogcapi, separate from the REST routers
  • Geospatial standards: Primary SRID 4326 (WGS84); geometry stored as Geometry(POINT, 4326); spatial queries use ST_Distance, ST_Within, ST_GeomFromText

Clone this wiki locally