openapi: 3.0.1
info:
  title: Metadata API
  description: RESTful API to create/read/update/delete metadata.
  version: 3.0.0-SNAPSHOT
  license:
    name: "GNU LGPLv3"
    url: "https://www.gnu.org/licenses/lgpl-3.0.en.html"
tags:
  - name: "Batch"
    description: Combines multiple API calls in one HTTP request. (seperate API)
  - name: "Package"
    description: Create, read, update and delete packages. (seperate API)
  - name: "Tag"
    description: Create, read, update and delete tags. (seperate API)
  - name: "Metadata"
    description: Create, read, update and delete metadata.
servers:
  - url: http://localhost:8080/api
paths:
  /metadata:
    get:
      tags:
        - "Metadata"
      summary: Retrieves the metadata in the system. (paged, queryable)
      parameters:
        - $ref: '#/components/parameters/number'
        - $ref: '#/components/parameters/size'
        - $ref: '#/components/parameters/query'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          $ref: '#/components/responses/OkAttributeCollectionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      tags:
        - "Metadata"
      summary: Creates a new entitytype.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EntityTypeCreate'
      responses:
        '201':
          $ref: '#/components/responses/Created'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
        - "Metadata"
      summary: Deletes metadata in the system based on a query.
      parameters:
        - $ref: '#/components/parameters/query'
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /metadata/{entityTypeId}:
    get:
      tags:
        - "Metadata"
      summary: Retrieves the metadata of an entitytype.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/flattenAttributes'
        - $ref: '#/components/parameters/i18n'
      responses:
        '200':
          $ref: '#/components/responses/OkEntityTypeResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    put:
      tags:
        - "Metadata"
      summary: replaces entitytype metadata.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EntityTypeCreate'
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    patch:
      tags:
        - "Metadata"
      summary: updates entitytype metadata.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EntityTypePatch'
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
        - "Metadata"
      summary: Delete an entitytype.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /metadata/{entityTypeId}/attributes:
    get:
      tags:
        - "Metadata"
      summary: Retrieves the attributes in the system for an entity type. (paged, queryable)
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/number'
        - $ref: '#/components/parameters/size'
        - $ref: '#/components/parameters/query'
        - $ref: '#/components/parameters/sort'
      responses:
        '200':
          $ref: '#/components/responses/OkAttributeCollectionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
        - "Metadata"
      summary: Deletes attributes in the system based on a query
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/query'
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      tags:
        - "Metadata"
      summary: Create an attribute.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttributeCreate'
      responses:
        '204':
          $ref: '#/components/responses/NoContent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /metadata/{entityTypeId}/attributes/{attributeId}:
    get:
      tags:
        - "Metadata"
      summary: Retrieves an attribute from the system.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/attributeId'
      responses:
        '200':
          $ref: '#/components/responses/OkAttributeCollectionResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    put:
      tags:
        - "Metadata"
      summary: Replace an attribute.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/attributeId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttributeCreate'
      responses:
        '204':
          $ref: '#/components/responses/NoContent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    patch:
      tags:
        - "Metadata"
      summary: Update an attribute.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/attributeId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AttributeCreate'
      responses:
        '204':
          $ref: '#/components/responses/NoContent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      tags:
        - "Metadata"
      summary: Delete an attribute.
      parameters:
        - $ref: '#/components/parameters/entityTypeId'
        - $ref: '#/components/parameters/attributeId'
      responses:
        '204':
          $ref: '#/components/responses/NoContent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-molgenis-token
  parameters:
    entityTypeId:
      name: entityTypeId
      description: Entity type identifier
      in: path
      required: true
      schema:
        type: string
      example: my_table
    attributeId:
      name: attributeId
      description: Attribute identifier
      in: path
      required: true
      schema:
        type: string
      example: my_column
    number:
      name: page
      description: Page number
      in: query
      required: false
      schema:
        type: integer
        minimum: 0
        default: 0
    size:
      name: size
      description: Page size
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    sort:
      name: sort
      description: Sort order
      in: query
      required: false
      style: form
      explode: false
      schema:
        type: string
      example: id,+label,-description
    query:
      name: q
      description: Query. [RSQL expression](https://github.com/jirutka/rsql-parser) where operator is '==' (equal to), '!=' (not equal to), '=lt=' or '<' (less than), '=le=' or '<=' (less than or equal to), '=gt=' or '>' (greater than), '=ge=' or '>=' (greater than or equal to), '=like=' (contains) or '=q=' (matches).
      in: query
      required: false
      schema:
        type: string
      example: label=q=node
    flattenAttributes:
      name: flattenAttributes
      description: Include attributes of parent entity types
      in: query
      required: false
      schema:
        type: boolean
    i18n:
      name: i18n
      description: Include translations e.g. label/description
      in: query
      required: false
      schema:
        type: boolean
  schemas:
    Links:
      type: object
      properties:
        previous:
          type: string
          format: uri
        self:
          type: string
          format: uri
        next:
          type: string
          format: uri
      required:
        - self
      example:
        previous: https://my.molgenis.org/api/metadata?number=0
        self: https://my.molgenis.org/api/metadata?number=1
        next: https://my.molgenis.org/api/metadata?number=2
    Page:
      type: object
      properties:
        size:
          type: number
          minimum: 0
        totalElements:
          type: number
          minimum: 0
        totalPages:
          type: number
          minimum: 0
        number:
          type: number
          minimum: 0
      required:
        - size
        - totalElements
        - totalPages
        - number
      example:
        size: 20
        totalElements: 100
        totalPages: 5
        number: 1
    EntityType:
      type: object
      properties:
        href:
          $ref: "#/components/schemas/Links"
        data:
          $ref: "#/components/schemas/EntityTypeData"
    EntityTypeData:
      type: object
      properties:
        id:
          type: string
        package:
          $ref: "#/components/schemas/Package"
        extends:
          $ref: "#/components/schemas/EntityType"
        description:
          type: string
        description_i18n:
          $ref: "#/components/schemas/I18nValue"
        label:
          type: string
        label_i18n:
          $ref: "#/components/schemas/I18nValue"
        abstract:
          type: boolean
        indexingDepth:
          type: integer
        attributes:
          type: object
          $ref: "#/components/schemas/Attributes"
      example:
        id: 0
        parent: https://my.molgenis.org/api/data/Node/1
        children: https://my.molgenis.org/api/data/Node/0/children
    Attributes:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/Attribute"
        links:
          $ref: "#/components/schemas/Links"
    Attribute:
      type: object
      properties:
        links:
          $ref: "#/components/schemas/Links"
        data:
          $ref: "#/components/schemas/AttributeData"
    AttributeData:
      properties:
        id:
          type: string
        name:
          type: string
        sequenceNr:
          type: integer
          nullable: true
        type:
          type: string
          enum: [bool, categorical, categorical_mref, compound, date, date_time, decimal, email, enum, file, html, hyperlink, int, long, mref, one_to_many, script, string, text, xref]
        mappedBy:
          $ref: "#/components/schemas/Attribute"
          # or nullable
        orderBy:
          type: array
          items:
            $ref: "#/components/schemas/AttributeSort"
          nullable: true
        idAttribute:
          type: boolean
        labelAttribute:
          type: boolean
        lookupAttributeIndex:
          type: integer
          nullable: true
        refEntityType:
          $ref: "#/components/schemas/Links"
          # or nullable
        description:
          type: string
          nullable: true
        description_i18n:
          $ref: "#/components/schemas/I18nValue"
          # or nullable
        label:
          type: string
          nullable: true
        label_i18n:
          $ref: "#/components/schemas/I18nValue"
          # or nullable
        nullable:
          type: boolean
        auto:
          type: boolean
        visible:
          type: boolean
        unique:
          type: boolean
        readOnly:
          type: boolean
        aggregatable:
          type: boolean
        enumOptions:
          type: array
          items:
            type: string
          nullable: true
        categoricalOptions:
          type: array
          items:
            $ref: "#/components/schemas/CategoricalOption"
          nullable: true
        defaultValue:
          type: string
          nullable: true
        cascadeDelete:
          type: boolean
          nullable: true
        parentAttribute:
          $ref: "#/components/schemas/Attribute"
        expression:
          type: string
          nullable: true
        nullableExpression:
          type: string
          nullable: true
        visibleExpression:
          type: string
          nullable: true
        validationExpression:
          type: string
          nullable: true
    Package:
      type: object
      properties:
        href:
          $ref: "#/components/schemas/Links"
    EntityTypeCreate:
      type: object
      required: [id, attributes]
      properties:
        id:
          type: string
        package:
          type: string
        label:
          $ref: "#/components/schemas/I18nValue"
        description:
          $ref: "#/components/schemas/I18nValue"
        abstract:
          type: string
        extends:
          type: string
        attributes:
          type: array
          items:
            $ref: "#/components/schemas/AttributeCreate"
    EntityTypePatch:
      type: object
      properties:
        package:
          type: string
        label:
          $ref: "#/components/schemas/I18nValue"
        description:
          $ref: "#/components/schemas/I18nValue"
        extends:
          type: string
        attributes:
          type: array
          items:
            $ref: "#/components/schemas/AttributeCreate"
    AttributeCreate:
      type: object
      required: [name, type]
      properties:
        id:
          type: string
        name:
          type: string
        type:
          type: string
          enum: [bool, categorical, categorical_mref, compound, date, date_time, decimal, email, enum, file, html, hyperlink, int, long, mref, one_to_many, script, string, text, xref]
        parent:
          description: the id of the parent attribute
          type: string
        refEntityType:
          type: string
        cascadeDelete:
          type: boolean
        mappedByAttribute:
          description: the id of the 'mapped by' attribute
          type: string
        orderBy:
          type: array
          items:
            $ref: "#/components/schemas/AttributeSort"
        expression:
          type: string
        nullable:
          type: boolean
        auto:
          type: boolean
        visible:
          type: boolean
        label:
          $ref: "#/components/schemas/I18nValue"
        description:
          $ref: "#/components/schemas/I18nValue"
        aggregatable:
          type: boolean
        enumOptions:
          type: array
          items:
            type: string
        range:
          $ref: "#/components/schemas/Range"
        readonly:
          type: boolean
        unique:
          type: boolean
        nullableExpression:
          type: string
        visibleExpression:
          type: string
        validationExpression:
          type: string
        defaultValue:
          type: string
        sequenceNumber:
          type: integer
        idAttribute:
          type: boolean
        labelAttribute:
          type: boolean
        lookupAttributeIndex:
          type: integer
    EntityTypeCollection:
      type: object
      properties:
        links:
          $ref: "#/components/schemas/Links"
        items:
          type: array
          items:
            $ref: "#/components/schemas/EntityType"
        page:
          $ref: "#/components/schemas/Page"
    AttributeCollection:
      type: object
      properties:
        links:
          $ref: "#/components/schemas/Links"
        items:
          type: array
          items:
            $ref: "#/components/schemas/Attribute"
        page:
          $ref: "#/components/schemas/Page"
    AttributeSort:
      type: array
      properties:
        id:
          type: string
        order:
          type: string
          enum: [ASC,DESC]
    Range:
      type: object
      properties:
        min:
          type: integer
        max:
          type: integer
    I18nValue:
      type: object
      properties:
        defaultValue:
          type: string
        translations:
          type: object
    CategoricalOption:
      type: object
      properties:
        id:
          type: string
        label:
          type: string
    Problem:
      type: object
      properties:
        type:
          type: string
          format: uri
          description:
            An absolute URI that identifies the problem type.  When dereferenced,
            it SHOULD provide human-readable documentation for the problem type
            (e.g., using HTML).
          default: 'about:blank'
          example: 'https://zalando.github.io/problem/constraint-violation'
        title:
          type: string
          description:
            A short, summary of the problem type. Written in english and readable for engineers
            (usually not suited for non technical stakeholders and not localized).
          example: Service Unavailable
        status:
          type: integer
          format: int32
          description:
            The HTTP status code generated by the origin server for this occurrence
            of the problem.
          minimum: 100
          maximum: 600
          exclusiveMaximum: true
          example: 503
        detail:
          type: string
          description:
            A human readable explanation specific to this occurrence of the
            problem.
          example: Connection to database timed out
        instance:
          type: string
          format: uri
          description: |
            An absolute URI that identifies the specific occurrence of the problem.
            It may or may not yield further information if dereferenced.
        errorCode:
          type: string
          description:
            The MOLGENIS error code for the thrown exception.

  responses:
    OkEntityTypeResponse:
      description: OK
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntityType'
    OkEntityTypeCollectionResponse:
      description: OK
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntityTypeCollection'
    OkAttributeResponse:
      description: OK
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Attribute'
    OkAttributeCollectionResponse:
      description: OK
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AttributeCollection'
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    Accepted:
      description: Accepted
      headers:
        Location:
          schema:
            type: string
          description: The URI of the created job
    Created:
      description: Created
    NoContent:
      description: No Content
    NotFound:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Problem'
security:
  - ApiKeyAuth: []
