Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document API with OpenAPI #26

Open
ximex opened this issue Jan 5, 2024 · 1 comment
Open

Document API with OpenAPI #26

ximex opened this issue Jan 5, 2024 · 1 comment

Comments

@ximex
Copy link

ximex commented Jan 5, 2024

It would be great if you could document the API in the OpenAPI spec
https://www.openapis.org/

@ximex
Copy link
Author

ximex commented Oct 26, 2024

i created a first version of OpenAPI spec. I created it only from the docs here without comparing with the real data.
You could test it here: https://editor-next.swagger.io/

openapi: 3.1.1
info:
  title: blaulichtSMS
  description: All APIs for the blaulichtSMS service
  contact:
    name: SOLARYS Software GmbH
    url: https://blaulichtsms.net/support/#kontaktformular
  license:
    name: Creative Commons Attribution Share Alike 4.0 International
    identifier: CC-BY-SA-4.0
  version: 0.0.1
servers:
  - url: https://api-staging.blaulichtsms.net/blaulicht
    description: Test server
  - url: https://api.blaulichtsms.net/blaulicht
    description: Live server
paths:
  /api/alarm/v1/trigger:
    post:
      tags: ['Alarm']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AlarmTriggerRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlarmTriggerResponse'
  /api/alarm/v1/query:
    post:
      tags: ['Alarm']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AlarmQueryRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlarmQueryResponse'
  /api/alarm/v1/list:
    post:
      tags: ['Alarm']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AlarmListRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlarmListResponse'

  /api/alarm/v1/dashboard/login:
    post:
      tags: ['Dashboard']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DashboardLoginRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DashboardLoginResponse'
  /api/alarm/v1/dashboard/{sessionId}:
    get:
      tags: ['Dashboard']
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DashboardDataResponse'
        '401':
          description: Unauthorized

  /api/portal/v1/import/participants/json:
    post:
      tags: ['Import']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportParticipantsJsonRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /api/portal/v1/import/participants/csv/{customerId}:
    post:
      tags: ['Import']
      parameters:
        - $ref: '#/components/parameters/CustomerIdPath'
        - $ref: '#/components/parameters/UsernameHeader'
        - $ref: '#/components/parameters/PasswordHeader'
      requestBody:
        content:
          text/csv:
            schema:
              $ref: '#/components/schemas/ImportParticipantsCsvRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /api/portal/v1/import/trigger/json:
    post:
      tags: ['Import']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportTriggerJsonRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /api/portal/v1/import/trigger/csv/{customerId}:
    post:
      tags: ['Import']
      parameters:
        - $ref: '#/components/parameters/CustomerIdPath'
        - $ref: '#/components/parameters/UsernameHeader'
        - $ref: '#/components/parameters/PasswordHeader'
      requestBody:
        content:
          text/csv:
            schema:
              $ref: '#/components/schemas/ImportTriggerCsvRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /api/portal/v1/import/groups/json:
    post:
      tags: ['Import']
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportGroupsJsonRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /api/portal/v1/import/groups/csv/{customerId}:
    post:
      tags: ['Import']
      headers:
      parameters:
        - $ref: '#/components/parameters/CustomerIdPath'
        - $ref: '#/components/parameters/UsernameHeader'
        - $ref: '#/components/parameters/PasswordHeader'
      requestBody:
        content:
          text/csv:
            schema:
              $ref: '#/components/schemas/ImportGroupsCsvRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '403':
          description: Forbidden

components:
  schemas:
    SessionId:
      type: string
    CustomerId:
      description: CustomerId as string
      type: string
      pattern: '^\d+$'
    Username:
      type: string
    Password:
      type: string
    Email:
      type: string
      format: email
    GroupId:
      type: string
      pattern: '^G\d{1,9}$'
    TemplateId:
      type: string
      pattern: '^A\d+$'
    AlarmId:
      type: string
    AlarmType:
      type: string
      enum:
        - 'alarm'
        - 'info'
    IntegrationType:
      type: string
      enum:
        - 'wasserkarte.info' # TODO
    ParticipationType:
      type: string
      enum:
        - 'yes'
        - 'no'
        - 'uknown' # TODO: typo?
        - 'pending'
    DateTime:
      type: string
      format: date-time
      pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$'
    HexColor:
      type: string
      pattern: '^#[0-9a-f]{6}$'
    Msisdn:
      type: string
      pattern: '^\+\d+$'
    Coordinates:
      type: object
      required: ['lat', 'lon']
      properties:
        lat:
          type: number
        lon:
          type: number
    Geolocation:
      type: object
      required: ['coordinates', 'positionSetByAuthor', 'radius', 'distance', 'address']
      properties:
        coordinates:
          $ref: '#/components/schemas/Coordinates'
        positionSetByAuthor:
          type: boolean
        radius:
          type: number
          nullable: true
        distance:
          type: number
          nullable: true
        address:
          type: string
          nullable: true
    Integration:
      type: object
      required: ['type', 'fields']
      properties:
        type:
          $ref: '#/components/schemas/IntegrationType'
        fields:
          type: object
          required: ['apiKey']
          properties: # TODO
            apiKey:
              type: string
    AlarmData:
      type: object
      required: ['alarmId', 'alarmGroups', 'alarmDate', 'endDate', 'authorName', 'alarmText', 'needsAcknowledgement', 'usersAlertedCount', 'geolocation', 'recipients', 'audioUrl']
      properties:
        alarmId:
          $ref: '#/components/schemas/AlarmId'
        alarmGroups:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmGroup'
        alarmDate:
          $ref: '#/components/schemas/DateTime'
        endDate:
          $ref: '#/components/schemas/DateTime'
        authorName:
          type: string
        alarmText:
          type: string
        needsAcknowledgement:
          type: boolean
        usersAlertedCount:
          type: integer
        geolocation:
          $ref: '#/components/schemas/Geolocation'
        recipients:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmRecipient'
        audioUrl:
          type: string
          nullable: true
    AlarmGroup:
      type: object
      required: ['groupId', 'groupName']
      properties:
        groupId:
          $ref: '#/components/schemas/GroupId'
        groupName:
          type: string
    AlarmRecipient:
      type: object
      required: ['id', 'name', 'msisdn', 'participation', 'participationMessage', 'functions']
      properties:
        id:
          type: string
        name:
          type: string
        msisdn:
          $ref: '#/components/schemas/Msisdn'
        participation:
          $ref: '#/components/schemas/ParticipationType'
        participationMessage:
          type: string
        functions:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmFunction'
    AlarmFunction:
      type: object
      required: ['functionId', 'name', 'order', 'shortForm', 'backgroundHexColorCode', 'foregroundHexColorCode']
      properties:
        functionId:
          type: string
          pattern: '^\d+$'
        name:
          type: string
        shortForm:
          type: string
        order:
          type: integer
        backgroundHexColorCode:
          $ref: '#/components/schemas/HexColor'
        foregroundHexColorCode:
          $ref: '#/components/schemas/HexColor'

    AlarmResultCode:
      type: string
      enum:
        - 'OK'
        - 'MISSING_INPUT_DATA'
        - 'MISSING_CUSTOMER_ID'
        - 'MISSING_USERNAME'
        - 'INVALID_CUSTOMER_ID'
        - 'NOT_CONFIGURED_FOR_CUSTOMER'
        - 'UNKNOWN_USER'
        - 'NOT_AUTHORIZED'
        - 'UNAUTHORIZED_SENDER_ID'
        - 'DEACTIVATED'
        - 'INVALID_GROUP'
        - 'INVALID_TEMPLATE'
        - 'NOT FOUND'
        - 'UNKNOWN_ERROR'
    AlarmDataExtended:
      allOf:
        - $ref: '#/components/schemas/AlarmData'
        - type: object
          required: ['customerId', 'indexNumber']
          properties:
            customerId:
              $ref: '#/components/schemas/CustomerId'
            indexNumber:
              type: integer
              nullable: true

    AlarmTriggerRequest:
      type: object
      required: ['username', 'password', 'customerId', 'type', 'needsAcknowledgement']
      properties:
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        customerId:
          $ref: '#/components/schemas/CustomerId'
        type:
          $ref: '#/components/schemas/AlarmType'
        hideTriggerDetails:
          type: boolean
        alarmText:
          type: string
        indexNumber:
          type: integer
        needsAcknowledgement:
          type: boolean
        startDate:
          $ref: '#/components/schemas/DateTime'
        duration:
          type: integer
        recipientConfirmation:
          type: boolean
        recipientConfirmationTarget:
          $ref: '#/components/schemas/Msisdn'
        template:
          $ref: '#/components/schemas/TemplateId'
        groupCodes:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/GroupId'
        additionalMsisdns:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/Msisdn'
        coordinates:
          $ref: '#/components/schemas/Coordinates'
        geolocation:
          $ref: '#/components/schemas/Geolocation'
    AlarmTriggerResponse:
      type: object
      required: ['result', 'alarmId', 'customerId', 'description', 'alarmData']
      properties:
        result:
          $ref: '#/components/schemas/AlarmResultCode'
        alarmId:
          $ref: '#/components/schemas/AlarmId'
        customerId:
          $ref: '#/components/schemas/CustomerId'
        description:
          type: 'null'
        alarmData:
          $ref: '#/components/schemas/AlarmDataExtended'
    AlarmQueryRequest:
      type: object
      required: ['username', 'password', 'customerId', 'alarmId']
      properties:
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        customerId:
          $ref: '#/components/schemas/CustomerId'
        alarmId:
          $ref: '#/components/schemas/AlarmId'
    AlarmQueryResponse:
      type: object
      required: ['result', 'alarmId', 'customerId', 'description', 'alarmData']
      properties:
        result:
          $ref: '#/components/schemas/AlarmResultCode'
        alarmId:
          $ref: '#/components/schemas/AlarmId'
        customerId:
          $ref: '#/components/schemas/CustomerId'
        description:
          type: string
        alarmData:
          $ref: '#/components/schemas/AlarmDataExtended'
    AlarmListRequest:
      type: object
      required: ['username', 'password', 'customerIds']
      properties:
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        customerIds:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/CustomerId'
        startDate:
          $ref: '#/components/schemas/DateTime'
        endDate:
          $ref: '#/components/schemas/DateTime'
    AlarmListResponse:
      type: object
      required: ['result', 'description', 'alarms']
      properties:
        result:
          $ref: '#/components/schemas/AlarmResultCode'
        description:
          type: string
        alarms:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmDataExtended'
        scenariosEnabled: # TODO not in docu
          type: boolean

    LoginResultCode:
      type: string
      nullable: true
      enum:
        - 'MISSING_INPUT_DATA'
        - 'MISSING_PASSWORD'
        - 'MISSING_CUSTOMERID'
        - 'MISSING_USERNAME'
        - 'INVALID_CREDENTIALS'

    DashboardLoginRequest:
      type: object
      required: ['customerId', 'username', 'password']
      properties:
        customerId:
          $ref: '#/components/schemas/CustomerId'
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
    DashboardLoginResponse:
      type: object
      required: ['success', 'sessionId', 'error']
      properties:
        success:
          type: boolean
        sessionId:
          allOf:
            - $ref: '#/components/schemas/SessionId'
            - description: Is `null` if `success` is `false`
              nullable: true
        error:
          allOf:
            - $ref: '#/components/schemas/LoginResultCode'
            - description: Is `null` if `success` is `true`
    DashboardDataResponse:
      type: object
      properties:
        customerId:
          $ref: '#/components/schemas/CustomerId'
        customerName:
          type: string
        username:
          $ref: '#/components/schemas/Username'
        integrations:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/Integration'
        alarms:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmData'
        infos:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmData'

    ParticipantData:
      type: object
      required: ['msisdn', 'givenname', 'surname', 'groups']
      properties:
        msisdn:
          $ref: '#/components/schemas/Msisdn'
        givenname:
          type: string
        surname:
          type: string
        email:
          $ref: '#/components/schemas/Email'
        groups:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/GroupId'
    AlarmGroupExtended:
      allOf:
        - $ref: '#/components/schemas/AlarmGroup'
        - type: object
          properties:
            redo:
              type: integer
              enum: [0, 1]
            redoInterval:
              description: If `redo` is `1`
              type: integer

    ImportParticipantsJsonRequest:
      type: object
      required: ['customerId', 'username', 'password', 'participants']
      properties:
        customerId:
          $ref: '#/components/schemas/CustomerId'
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        participants:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/ParticipantData'
    ImportParticipantsCsvRequest:
      type: string
      example: |-
        givenname;surname;msisdn;email;groups
        John;Doe;+4366412345678;;G1
        Joanne;Doe;+4367612345678;joane@doe.com;G1,G2
    ImportTriggerJsonRequest:
      type: object
      required: ['customerId', 'username', 'password', 'trigger']
      properties:
        customerId:
          $ref: '#/components/schemas/CustomerId'
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        trigger:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/ParticipantData'
    ImportTriggerCsvRequest:
      type: string
      example: |-
        givenname;surname;msisdn;email;groups
        Max;Mustermann;+4366412345678;;G1
        Martina;Musterfrau;+4367612345678;martina.musterfrau@example.com;G1,G2
    ImportGroupsJsonRequest:
      type: object
      required: ['customerId', 'username', 'password', 'groups']
      properties:
        customerId:
          $ref: '#/components/schemas/CustomerId'
        username:
          $ref: '#/components/schemas/Username'
        password:
          $ref: '#/components/schemas/Password'
        groups:
          type: array
          uniqueItems: true
          items:
            $ref: '#/components/schemas/AlarmGroupExtended'
    ImportGroupsCsvRequest:
      type: string
      example: |-
        groupId;name;redo;redoInterval
        G1;siren;;
        G2;silent alert;;
        G3;whole brigade;;

  parameters:
    SessionIdPath:
      name: sessionId
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/SessionId'
    CustomerIdPath:
      name: customerId
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/CustomerId'
    UsernameHeader:
      name: X-Username
      in: header
      required: true
      schema:
        $ref: '#/components/schemas/Username'
    PasswordHeader:
      name: X-Password
      in: header
      required: true
      schema:
        $ref: '#/components/schemas/Password'

tags:
  - name: Alarm
#    description: Alarm
#  - name: SMS
#    description: SMS
  - name: Dashboard
#    description: Dashboard
  - name: Import
#    description: Import

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant