openapi: 3.0.3
info:
  title: Aperio API
  version: 1.0.0
  description: Public deck catalogue and authenticated deck synchronization API.
servers:
  - url: /
paths:
  /api/1.0/deck/count/:
    get:
      summary: Count public decks
      security:
        - ApplicationToken: []
      responses:
        '200':
          description: Public deck count
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Count'
  /api/1.0/deck/list/{page}/:
    get:
      summary: List public decks
      security:
        - ApplicationToken: []
      parameters:
        - name: page
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
      responses:
        '200':
          description: Page of public decks
          content:
            application/json:
              schema:
                type: object
                required: [decks]
                properties:
                  decks:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeckDescription'
  /api/1.0/deck:
    get:
      summary: Get a deck and its cards
      description: Accepts either the deck's public or private key.
      security:
        - ApplicationToken: []
          DeckKey: []
      responses:
        '200':
          description: Deck contents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deck'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: The key matches conflicting public and private records.
    put:
      summary: Rename a deck
      description: Requires the deck's private key.
      security:
        - ApplicationToken: []
          DeckKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeckMutation'
      responses:
        '200':
          description: Updated deck
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Deck'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/1.0/cards:
    post:
      summary: Create a card
      description: Requires the deck's private key.
      security:
        - ApplicationToken: []
          DeckKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardMutation'
      responses:
        '201':
          description: Card created
          headers:
            Location:
              schema:
                type: string
                format: uri-reference
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Card'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/1.0/cards/{cardId}:
    parameters:
      - $ref: '#/components/parameters/CardId'
    put:
      summary: Replace a card's content
      description: Requires the private key for the card's deck.
      security:
        - ApplicationToken: []
          DeckKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CardMutation'
      responses:
        '200':
          description: Updated card
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Card'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      summary: Delete a card
      description: Requires the private key for the card's deck.
      security:
        - ApplicationToken: []
          DeckKey: []
      responses:
        '204':
          description: Card deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    ApplicationToken:
      type: apiKey
      in: header
      name: Token
    DeckKey:
      type: apiKey
      in: header
      name: Authorization
      description: Use `Key <public-or-private-key>`. Mutating operations require a private key.
  parameters:
    CardId:
      name: cardId
      in: path
      required: true
      schema:
        type: integer
        format: int32
        minimum: 1
  responses:
    BadRequest:
      description: Invalid request content
    Unauthorized:
      description: Missing or invalid deck authorization
    NotFound:
      description: Requested deck or card not found
  schemas:
    Count:
      type: object
      required: [count]
      properties:
        count:
          type: integer
          minimum: 0
    DeckDescription:
      type: object
      required: [name, cards, updateDate, publicKey]
      properties:
        name:
          type: string
        cards:
          type: integer
          minimum: 0
        updateDate:
          type: integer
          format: int64
          description: Unix timestamp in seconds.
        publicKey:
          type: string
    Deck:
      type: object
      required: [publicKey, name, cards]
      properties:
        publicKey:
          type: string
        name:
          type: string
        cards:
          type: array
          items:
            $ref: '#/components/schemas/Card'
    Card:
      type: object
      required: [id, front, back, position]
      properties:
        id:
          type: integer
          format: int32
        front:
          type: string
        back:
          type: string
        hint:
          type: string
          nullable: true
        position:
          type: integer
          minimum: 0
    DeckMutation:
      type: object
      required: [name]
      properties:
        name:
          type: string
          minLength: 1
    CardMutation:
      type: object
      required: [front, back]
      properties:
        front:
          type: string
          minLength: 1
        back:
          type: string
          minLength: 1
        hint:
          type: string
          nullable: true
