Core API Design

Last Updated: 2025-11-02

Last updated: June 25, 2026 Reading time: 8 minutes File size: 12.8 KB

Last Updated: 2025-11-02 ADR Reference: ADR-003: Meaningful Identifiers in Public APIs

This document outlines the foundational API design patterns, external integrations, and common components shared across all BATbern Event Management Platform domain APIs.

OpenAPI Specification

yaml
openapi: 3.0.0
info:
  title: BATbern Event Management Platform API
  version: 1.0.0
  description: Comprehensive API for the BATbern Event Management Platform supporting organizers, speakers, partners, and attendees
servers:
  - url: https://api.batbern.ch
    description: Production API
  - url: https://api.staging.batbern.ch
    description: Staging API
  - url: http://localhost:8080
    description: Local Development API

security:
  - BearerAuth: []

Domain API Documentation

The BATbern API is organized by domain-driven design principles. Each domain has its own detailed API documentation:

External APIs

AWS Cognito API

Key Endpoints Used:

  • POST /oauth2/token - JWT token generation and refresh
  • POST /admin/createUser - Programmatic user creation for organizers
  • GET /oauth2/userInfo - User profile and role information

Integration Notes: Custom attributes store BATbern-specific roles (organizer, speaker, partner, attendee). Lambda triggers handle user registration workflows and role assignment validation.

AWS SES API

Key Endpoints Used:

  • POST /v2/email/outbound-emails - Send transactional emails
  • POST /v2/email/bulk-emails - Newsletter distribution
  • POST /v2/email/templates - Email template management

Integration Notes: Templates stored for speaker invitations, event notifications, and partner reports. Bounce and complaint handling integrated with user management.

AWS S3 API

Key Endpoints Used:

  • PUT /bucket/{key} - File upload with metadata
  • GET /bucket/{key} - File retrieval with access control
  • POST /bucket?delete - Batch file deletion for content management

Integration Notes: Presigned URLs for direct browser uploads. Lifecycle policies for archival content. CloudFront integration for global CDN distribution.

API Design Principles

Authentication & Authorization

  • JWT Bearer Tokens: AWS Cognito-issued tokens with custom claims
  • Role-Based Access Control: Fine-grained permissions per user type
  • Rate Limiting: Per-user and per-endpoint rate limits
  • API Key Management: Service-to-service authentication

Data Consistency

  • Eventual Consistency: Cross-service data synchronization via events
  • Optimistic Locking: Concurrent update conflict resolution
  • Idempotency: Safe retry mechanisms for critical operations
  • Data Validation: Schema validation at API gateway level

Performance Optimization

  • Response Caching: Caffeine in-memory caching for frequently accessed data
  • Pagination: Consistent pagination patterns across all list endpoints
  • Field Selection: GraphQL-style field selection for large objects
  • Bulk Operations: Batch endpoints for high-volume operations

Error Handling

  • Standard HTTP Status Codes: Consistent error response patterns
  • Detailed Error Messages: Structured error objects with context
  • Correlation IDs: Request tracing across service boundaries
  • Circuit Breakers: Fault tolerance for external service calls

Common Components & Schemas

Security Schemes

yaml
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Common Schemas

yaml
# Page-based pagination metadata (NOT offset/cursor). Source: shared-kernel api.PaginationMetadata.
PaginationMetadata:
  type: object
  required: [page, limit, totalItems, totalPages, hasNext, hasPrev]
  properties:
    page:
      type: integer
      description: Current page index
    limit:
      type: integer
      description: Page size (items per page)
    totalItems:
      type: integer
      format: int64
      description: Total number of items across all pages
    totalPages:
      type: integer
      description: Total number of pages
    hasNext:
      type: boolean
      description: Whether a next page exists
    hasPrev:
      type: boolean
      description: Whether a previous page exists

# Flat error envelope (NOT nested under `error`). Source: shared-kernel dto.ErrorResponse.
# @JsonInclude(NON_NULL): absent fields are omitted from the wire.
ErrorResponse:
  type: object
  properties:
    timestamp:
      type: string
      format: date-time
    path:
      type: string
      description: Request path that generated the error
    status:
      type: integer
      description: HTTP status code
    error:
      type: string
      description: Short HTTP reason phrase
    errorCode:
      type: string
      description: Stable machine-readable error code for typed client handling
    message:
      type: string
      description: Human-readable error message
    correlationId:
      type: string
      description: Correlation ID for tracing
    severity:
      type: string
      enum: [LOW, MEDIUM, HIGH, CRITICAL]
    details:
      type: object
      additionalProperties: true
      description: Additional structured context (e.g. per-field validation errors)
    stackTrace:
      type: string
      description: Dev/staging diagnostics only β€” never in production

Venue:
  type: object
  properties:
    name:
      type: string
    address:
      type: string
    city:
      type: string
    postalCode:
      type: string
    capacity:
      type: integer

Session:
  type: object
  properties:
    id:
      type: string

      description: Meaningful identifier (see ADR-003)
    title:
      type: string
    description:
      type: string
    startTime:
      type: string
      format: date-time
    endTime:
      type: string
      format: date-time
    speakers:
      type: array
      items:
        $ref: '#/components/schemas/SessionSpeaker'
    materials:
      type: array
      items:
        $ref: '#/components/schemas/ContentMetadata'

SessionSpeaker:
  type: object
  properties:
    username:
      type: string

      description: Meaningful identifier (see ADR-003)
    workflowState:
      $ref: '#/components/schemas/SpeakerWorkflowState'
    invitedAt:
      type: string
      format: date-time
    confirmedAt:
      type: string
      format: date-time
    declinedAt:
      type: string
      format: date-time

SpeakerProfile:
  type: object
  properties:
    bio:
      type: string
      maxLength: 500
    photoUrl:
      type: string
      format: uri
    expertiseAreas:
      type: array
      items:
        type: string
    socialLinks:
      type: object
      properties:
        linkedin:
          type: string
          format: uri
        twitter:
          type: string
          format: uri
        website:
          type: string
          format: uri

CompanyLogo:
  type: object
  properties:
    fileId:
      type: string

      description: Meaningful identifier (see ADR-003)
    url:
      type: string
      format: uri
    thumbnailUrl:
      type: string
      format: uri
    uploadedAt:
      type: string
      format: date-time

ContentMetadata:
  type: object
  properties:
    fileId:
      type: string

      description: Meaningful identifier (see ADR-003)
    filename:
      type: string
    contentType:
      type: string
      enum: [presentation, logo, speaker_photo, speaker_cv, event_photo, archive_material]
    mimeType:
      type: string
    fileSizeBytes:
      type: integer
      format: int64
    uploadedBy:
      type: string

      description: Meaningful identifier (see ADR-003)
    uploadedAt:
      type: string
      format: date-time
    cdnUrl:
      type: string
      format: uri
      description: CloudFront CDN URL for file access
    status:
      type: string
      enum: [pending, uploading, completed, failed, deleted]
    checksum:
      type: string
      description: SHA-256 checksum for integrity verification

API Versioning Strategy

All APIs use URL-based versioning with the format /api/v{version}/...:

  • Current version: v1
  • Version changes trigger new major version only for breaking changes
  • Backward-compatible additions made to existing version
  • Deprecated endpoints maintained for minimum 6 months with deprecation headers

Cross-Cutting Concerns

Request/Response Headers

Standard Request Headers:

  • Authorization: Bearer {token} - JWT authentication token
  • X-Correlation-ID: {uuid} - Request correlation ID (auto-generated if not provided)
  • Accept-Language: {locale} - Preferred response language (en, de)
  • Content-Type: application/json - Request content type

Standard Response Headers:

  • X-Correlation-ID: {uuid} - Request correlation ID for tracing
  • X-RateLimit-Limit: {number} - Rate limit threshold
  • X-RateLimit-Remaining: {number} - Remaining requests in window
  • X-RateLimit-Reset: {timestamp} - Rate limit window reset time

Rate Limiting

All endpoints enforce rate limiting based on user role:

  • Attendee: 100 requests per minute
  • Speaker: 200 requests per minute
  • Partner: 300 requests per minute
  • Organizer: 500 requests per minute

Rate limit exceeded returns 429 Too Many Requests with retry-after header.

Caching Strategy

  • GET endpoints: Support ETag and If-None-Match headers
  • Cache-Control headers: Set appropriately per endpoint
  • CDN caching: Static content (logos, archived materials) cached at edge
  • API caching: Caffeine-backed for frequently accessed data (15-minute TTL)

Pagination

All list endpoints use page-based pagination (NOT offset/cursor):

  • page - Page index (default: 0)
  • limit - Items per page (default: 20, max: 100)
  • sort - JSON:API-style sort expression (ADR-013 Β§3)
  • filter - JSON:API-style filter expression (ADR-013 Β§3)

Response wraps data in a PaginatedResponse with PaginationMetadata:

json
{
  "data": [...],
  "pagination": {
    "page": 0,
    "limit": 20,
    "totalItems": 150,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": false
  }
}

Field Selection

Large object endpoints support field selection via fields query parameter:

  • fields=id,title,status - Return only specified fields
  • Reduces payload size and improves performance
  • Nested field selection: fields=id,venue.name,venue.city

Internationalization

All text responses support English (en) and German (de) via Accept-Language header:

  • Error messages localized based on locale
  • Email templates use recipient’s preferred language
  • Date/time formatting follows locale conventions