---
swagger: "2.0"
info:
  title: fatcat
  description: A scalable, versioned, API-oriented catalog of bibliographic entities
    and file metadata
  version: 0.1.0
schemes: [http]
basePath: /v0
#host: api.fatcat.wiki
consumes:
  - application/json
produces:
  - application/json

# don't want these to be rust types (at least for now)
x-fatcat-ident: &FATCATIDENT
  type: string
  example: "q3nouwy3nnbsvo3h5klxsx4a7y"
  pattern: "[a-zA-Z2-7]{26}"
  minLength: 26
  maxLength: 26
  description: "base32-encoded unique identifier"
x-fatcat-uuid: &FATCATUUID
  type: string
  example: "86daea5b-1b6b-432a-bb67-ea97795f80fe"
  pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
  minLength: 36
  maxLength: 36
  description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)"
x-issn: &FATCATISSN
  type: string
  example: "1234-5678"
  pattern: "\\d{4}-\\d{3}[0-9X]"
  minLength: 9
  maxLength: 9
x-orcid: &FATCATORCID
  type: string
  example: "0000-0002-1825-0097"
  pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]"
  minLength: 19
  maxLength: 19

# Common properties across entities
x-entity-props: &ENTITYPROPS
  state:
    type: string
    enum: ["wip", "active", "redirect", "deleted"]
  ident:
    <<: *FATCATIDENT
  revision:
    <<: *FATCATUUID
  redirect:
    <<: *FATCATIDENT
  editgroup_id:
    <<: *FATCATIDENT
  extra:
    type: object
    additionalProperties: {}
# TODO:
#  edit_extra:
#    type: object
#    additionalProperties: {}

definitions:
  error_response:
    type: object
    required:
      - message
    properties:
      message:
        type: string
        example: "A really confusing, totally unexpected thing happened"
  success:
    type: object
    required:
      - message
    properties:
      message:
        type: string
        example: "The computers did the thing successfully!"
  container_entity:
    type: object
    required:
      - name
    properties:
      <<: *ENTITYPROPS
      name:
        type: string
        example: "Journal of Important Results"
      publisher:
        type: string
        example: "Society of Curious Students"
      issnl:
        <<: *FATCATISSN
      wikidata_qid:
        type: string
      abbrev:
        type: string
      coden:
        type: string
  creator_entity:
    type: object
    required:
      - display_name
    properties:
      <<: *ENTITYPROPS
      display_name:
        type: string
        example: "Grace Hopper"
      given_name:
        type: string
      surname:
        type: string
      orcid:
        <<: *FATCATORCID
      wikidata_qid:
        type: string
  file_entity:
    type: object
    properties:
      <<: *ENTITYPROPS
      size:
        type: integer
        example: 1048576
        format: int64
      sha1:
        type: string
        #format: custom
        example: "f013d66c7f6817d08b7eb2a93e6d0440c1f3e7f8"
      md5:
        type: string
        #format: custom
        example: "d41efcc592d1e40ac13905377399eb9b"
      sha256:
        type: string
        #format: custom
        example: "a77e4c11a57f1d757fca5754a8f83b5d4ece49a2d28596889127c1a2f3f28832"
      urls:
        type: array
        items:
          type: object
          required:
            - url
            - rel
          properties:
            url:
              type: string
              format: url
              example: "https://example.edu/~frau/prcding.pdf"
            rel:
              type: string
              example: "webarchive"
      mimetype:
        type: string
        example: "application/pdf"
      releases:
        type: array
        items:
          type: string
          #format: uuid
  release_entity:
    type: object
    required:
      - title
    properties:
      <<: *ENTITYPROPS
      title:
        type: string
      work_id:
        type: string
        example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      container:
        $ref: "#/definitions/container_entity"
        description: "Optional; GET-only"
      files:
        description: "Optional; GET-only"
        type: array
        items:
          $ref: "#/definitions/file_entity"
      container_id:
        type: string
        example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      release_type:
        type: string
        example: "book"
      release_status:
        type: string
        example: "preprint"
      release_date:
        type: string
        format: date
      doi:
        type: string
        #format: custom
        example: "10.1234/abcde.789"
      isbn13:
        type: string
        #format: custom
      core_id:
        type: string
        #format: custom
      pmid:
        type: string
      pmcid:
        type: string
      wikidata_qid:
        type: string
      volume:
        type: string
      issue:
        type: string
        example: "12"
      pages:
        type: string
      publisher:
        type: string
      language:
        description: "Two-letter RFC1766/ISO639-1 language code, with extensions"
        type: string
      contribs:
        type: array
        items:
          $ref: "#/definitions/release_contrib"
      refs:
        type: array
        items:
          $ref: "#/definitions/release_ref"
      abstracts:
        type: array
        items:
          type: object
          properties:
            sha1:
              type: string
              example: "3f242a192acc258bdfdb151943419437f440c313"
            content:
              type: string
              example: "<jats:p>Some abstract thing goes here</jats:p>"
            mimetype:
              type: string
              example: "application/xml+jats"
            lang:
              type: string
              example: "en"
  work_entity:
    type: object
    properties:
      <<: *ENTITYPROPS
  entity_history_entry:
    type: object
    required:
      - edit
      - editgroup
      - changelog_entry
    properties:
      edit:
        $ref: "#/definitions/entity_edit"
      editgroup:
        $ref: "#/definitions/editgroup"
      changelog_entry:
        $ref: "#/definitions/changelog_entry"
  entity_edit:
    type: object
    required:
      - edit_id
      - ident
      - editgroup_id
    properties:
      edit_id:
          type: integer
          example: 847
          format: int64
      ident:
          type: string
          example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      revision:
          type: string
          #format: uuid
          example: "86daea5b-1b6b-432a-bb67-ea97795f80fe"
      prev_revision:
          type: string
          #format: uuid
          example: "86daea5b-1b6b-432a-bb67-ea97795f80fe"
      redirect_ident:
          type: string
          example: "q3nouwy3nnbsvo3h5klxsx4a7y"
          #format: ident
      editgroup_id:
          type: string
          example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      extra:
          type: object
          additionalProperties: {}
  editor:
    type: object
    required:
      - username
    properties:
      id:
        type: string
        example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      username:
        type: string
        example: "zerocool93"
  editgroup:
    type: object
    required:
      - editor_id
    properties:
      id:
        <<: *FATCATIDENT
      editor_id:
        <<: *FATCATIDENT
      description:
        type: string
      extra:
        type: object
        additionalProperties: {}
      edits:
        type: object
        properties:
          containers:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
          creators:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
          files:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
          releases:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
          works:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
  changelog_entry:
    type: object
    required:
      - index
      - editgroup_id
      - timestamp
    properties:
      index:
        type: integer
        format: int64
      editgroup_id:
        type: string
        example: "q3nouwy3nnbsvo3h5klxsx4a7y"
      timestamp:
        type: string
        format: date-time
      editgroup:
        $ref: "#/definitions/editgroup"
  release_ref:
    type: object
    properties:
      index:
        type: integer
        format: int64
      target_release_id:
        type: string
        #format: ident
      extra:
        type: object
        additionalProperties: {}
      key:
        type: string
      year:
        type: integer
        format: int64
      container_title:
        type: string
      title:
        type: string
      locator:
        type: string
        example: "p123"
  release_contrib:
    type: object
    properties:
      index:
        type: integer
        format: int64
      creator_id:
        type: string
        #format: ident
      creator:
        $ref: "#/definitions/creator_entity"
        description: "Optional; GET-only"
      raw_name:
        type: string
      extra:
        type: object
        additionalProperties: {}
      role:
        type: string
  stats_response:
    type: object
    properties:
      extra:
        type: object
        additionalProperties: {}

x-entity-responses: &ENTITYRESPONSES
  400:
    description: Bad Request
    schema:
      $ref: "#/definitions/error_response"
  404:
    description: Not Found
    schema:
      $ref: "#/definitions/error_response"
  500:
    description: Generic Error
    schema:
      $ref: "#/definitions/error_response"

paths:
  /container:
    post:
      operationId: "create_container"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/container_entity"
      responses:
        201:
          description: Created Entity
          schema:
            $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /container/batch:
    post:
      operationId: "create_container_batch"
      parameters:
        - name: autoaccept
          in: query
          type: boolean
          required: false
          description: "If true, and editor is authorized, batch is accepted all at once"
        - name: editgroup
          in: query
          type: string
          required: false
          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"
        - name: entity_list
          in: body
          required: true
          schema:
            type: array
            items:
              $ref: "#/definitions/container_entity"
      responses:
        201:
          description: Created Entities
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /container/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: expand
        in: query
        type: string
        required: false
        description: "List of sub-entities to expand in response. For now, only 'all' accepted."
    get:
      operationId: "get_container"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/container_entity"
        <<: *ENTITYRESPONSES
  /container/{id}/history:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_container_history"
      responses:
        200:
          description: Found Entity History
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_history_entry"
        <<: *ENTITYRESPONSES
  /container/lookup:
    get:
      operationId: "lookup_container"
      parameters:
        - name: issnl
          in: query
          required: true
          <<: *FATCATISSN
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/container_entity"
        <<: *ENTITYRESPONSES
  /creator:
    post:
      operationId: "create_creator"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/creator_entity"
      responses:
        201:
          description: Created Entity
          schema:
            $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /creator/batch:
    post:
      operationId: "create_creator_batch"
      parameters:
        - name: autoaccept
          in: query
          type: boolean
          required: false
          description: "If true, and editor is authorized, batch is accepted all at once"
        - name: editgroup
          in: query
          type: string
          required: false
          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"
        - name: entity_list
          in: body
          required: true
          schema:
            type: array
            items:
              $ref: "#/definitions/creator_entity"
      responses:
        201:
          description: Created Entities
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /creator/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: expand
        in: query
        type: string
        required: false
        description: "List of sub-entities to expand in response. For now, only 'all' accepted."
    get:
      operationId: "get_creator"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/creator_entity"
        <<: *ENTITYRESPONSES
  /creator/{id}/history:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_creator_history"
      responses:
        200:
          description: Found Entity History
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_history_entry"
        <<: *ENTITYRESPONSES
  /creator/{id}/releases:
    parameters:
      - name: id
        in: path
        type: string
        required: true
    get:
      operationId: "get_creator_releases"
      responses:
        200:
          description: Found Entity
          schema:
            type: array
            items:
              $ref: "#/definitions/release_entity"
        <<: *ENTITYRESPONSES
  /creator/lookup:
    get:
      operationId: "lookup_creator"
      parameters:
        - name: orcid
          in: query
          required: true
          <<: *FATCATORCID
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/creator_entity"
        <<: *ENTITYRESPONSES
  /file:
    post:
      operationId: "create_file"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/file_entity"
      responses:
        201:
          description: Created Entity
          schema:
            $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /file/batch:
    post:
      operationId: "create_file_batch"
      parameters:
        - name: autoaccept
          in: query
          type: boolean
          required: false
          description: "If true, and editor is authorized, batch is accepted all at once"
        - name: editgroup
          in: query
          type: string
          required: false
          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"
        - name: entity_list
          in: body
          required: true
          schema:
            type: array
            items:
              $ref: "#/definitions/file_entity"
      responses:
        201:
          description: Created Entities
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /file/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: expand
        in: query
        type: string
        required: false
        description: "List of sub-entities to expand in response. For now, only 'all' accepted."
    get:
      operationId: "get_file"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/file_entity"
        <<: *ENTITYRESPONSES
  /file/{id}/history:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_file_history"
      responses:
        200:
          description: Found Entity History
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_history_entry"
        <<: *ENTITYRESPONSES
  /file/lookup:
    get:
      operationId: "lookup_file"
      parameters:
        - name: sha1
          in: query
          type: string
          required: true
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/file_entity"
        <<: *ENTITYRESPONSES
  /release:
    post:
      operationId: "create_release"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/release_entity"
      responses:
        201:
          description: Created Entity
          schema:
            $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /release/batch:
    post:
      operationId: "create_release_batch"
      parameters:
        - name: autoaccept
          in: query
          type: boolean
          required: false
          description: "If true, and editor is authorized, batch is accepted all at once"
        - name: editgroup
          in: query
          type: string
          required: false
          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"
        - name: entity_list
          in: body
          required: true
          schema:
            type: array
            items:
              $ref: "#/definitions/release_entity"
      responses:
        201:
          description: Created Entities
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /release/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: expand
        in: query
        type: string
        required: false
        description: "List of sub-entities to expand in response. For now, only 'all' accepted."
    get:
      operationId: "get_release"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/release_entity"
        <<: *ENTITYRESPONSES
  /release/{id}/history:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_release_history"
      responses:
        200:
          description: Found Entity History
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_history_entry"
        <<: *ENTITYRESPONSES
  /release/{id}/files:
    parameters:
      - name: id
        in: path
        type: string
        required: true
    get:
      operationId: "get_release_files"
      responses:
        200:
          description: Found Entity
          schema:
            type: array
            items:
              $ref: "#/definitions/file_entity"
        <<: *ENTITYRESPONSES
  /release/lookup:
    get:
      operationId: "lookup_release"
      parameters:
        - name: doi
          in: query
          type: string
          required: true
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/release_entity"
        <<: *ENTITYRESPONSES
  /work:
    post:
      operationId: "create_work"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/work_entity"
      responses:
        201:
          description: Created Entity
          schema:
            $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /work/batch:
    post:
      operationId: "create_work_batch"
      parameters:
        - name: autoaccept
          in: query
          type: boolean
          required: false
          description: "If true, and editor is authorized, batch is accepted all at once"
        - name: editgroup
          in: query
          type: string
          required: false
          description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)"
        - name: entity_list
          in: body
          required: true
          schema:
            type: array
            items:
              $ref: "#/definitions/work_entity"
      responses:
        201:
          description: Created Entities
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_edit"
        <<: *ENTITYRESPONSES
  /work/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: expand
        in: query
        type: string
        required: false
        description: "List of sub-entities to expand in response. For now, only 'all' accepted."
    get:
      operationId: "get_work"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/work_entity"
        <<: *ENTITYRESPONSES
  /work/{id}/history:
    parameters:
      - name: id
        in: path
        type: string
        required: true
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_work_history"
      responses:
        200:
          description: Found Entity History
          schema:
            type: array
            items:
              $ref: "#/definitions/entity_history_entry"
        <<: *ENTITYRESPONSES
  /work/{id}/releases:
    parameters:
      - name: id
        in: path
        type: string
        required: true
    get:
      operationId: "get_work_releases"
      responses:
        200:
          description: Found Entity
          schema:
            type: array
            items:
              $ref: "#/definitions/release_entity"
        <<: *ENTITYRESPONSES
  /editor/{id}:
    parameters:
      - name: id
        in: path
        type: string
        required: true
    get:
      operationId: "get_editor"
      responses:
        200:
          description: Found Editor
          schema:
            $ref: "#/definitions/editor"
        404:
          description: Not Found
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /editor/{id}/changelog:
    parameters:
      - name: id
        in: path
        type: string
        required: true
    get:
      operationId: "get_editor_changelog"
      responses:
        200:
          description: Found Merged Changes
          schema:
            type: array
            items:
              $ref: "#/definitions/changelog_entry"
        404:
          description: Not Found
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /editgroup:
    post:
      operationId: "create_editgroup"
      parameters:
        - name: entity
          in: body
          required: true
          schema:
            $ref: "#/definitions/editgroup"
      responses:
        201:
          description: Successfully Created
          schema:
            $ref: "#/definitions/editgroup"
        400:
          description: Bad Request
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /editgroup/{id}:
    parameters:
      - name: id
        in: path
        required: true
        <<: *FATCATIDENT
    get:
      operationId: "get_editgroup"
      responses:
        200:
          description: Found Entity
          schema:
            $ref: "#/definitions/editgroup"
        400:
          description: Bad Request
          schema:
            $ref: "#/definitions/error_response"
        404:
          description: Not Found
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /editgroup/{id}/accept:
    parameters:
      - name: id
        in: path
        required: true
        <<: *FATCATIDENT
    post:
      operationId: "accept_editgroup"
      responses:
        200:
          description: Merged Successfully
          schema:
            $ref: "#/definitions/success"
        400:
          description: Unmergable
          schema:
            $ref: "#/definitions/error_response"
        404:
          description: Not Found
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /changelog:
    parameters:
      - name: limit
        in: query
        type: integer
        format: int64
        required: false
    get:
      operationId: "get_changelog"
      responses:
        200:
          description: Success
          schema:
            type: array
            items:
              $ref: "#/definitions/changelog_entry"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /changelog/{id}:
    parameters:
      - name: id
        in: path
        type: integer
        format: int64
        required: true
    get:
      operationId: "get_changelog_entry"
      responses:
        200:
          description: Found Changelog Entry
          schema:
            $ref: "#/definitions/changelog_entry"
        404:
          description: Not Found
          schema:
            $ref: "#/definitions/error_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"
  /stats:
    get:
      operationId: "get_stats"
      parameters:
        - name: more
          in: query
          type: string
          required: false
      responses:
        200:
          description: Success
          schema:
            $ref: "#/definitions/stats_response"
        500:
          description: Generic Error
          schema:
            $ref: "#/definitions/error_response"