openapi: "3.0.0"

info:
  version: 1.1.0-beta.4
  title: DraCor API
  contact:
    email: "fr.fischer@fu-berlin.de"
  termsOfService: "https://dracor.org"
  license:
    name: "MIT"
    url: "https://github.com/dracor-org/dracor-api/blob/main/LICENSE"

servers:
  - url: https://staging.dracor.org/api/v1

paths:
  /info:
    get:
      summary: API info
      description: >-
        Shows version numbers of the dracor-api app and the underlying
        eXist-db.
      operationId: api-info
      tags: [public]
      responses:
        '200':
          description: Returns JSON object
          content:
            application/json:
              example:
                {
                  "name": "DraCor",
                  "version": "1.0.0",
                  "status": "stable",
                  "existdb": "6.2.0",
                  "base": "https://staging.dracor.org/api/v1",
                  "openapi": "https://staging.dracor.org/api/v1/openapi.yaml"
                }
              schema:
                $ref: '#/components/schemas/Info'

  /corpora:
    get:
      summary: List available corpora
      operationId: list-corpora
      tags: [public]
      parameters:
        - name: include
          in: query
          description: Include metrics for each corpus
          required: false
          schema:
            type: string
            enum: [metrics]
      responses:
        '200':
          description: Returns list of available corpora
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CorpusInCorpora'

              example:
                [
                  {
                    "name": "ger",
                    "title": "German Drama Corpus",
                    "repository": "https://github.com/dracor-org/gerdracor",
                    "uri": "https://staging.dracor.org/api/v1/corpora/ger",
                    "description": "Edited by Frank Fischer and Peer Trilcke. Features 501 German-language plays from the 1730s to the 1940s.",
                    "licence": "CC0",
                    "licenceUrl": "https://creativecommons.org/share-your-work/public-domain/cc0/",
                    "metrics": {
                      "characters": 10001,
                      "female": 1308,
                      "male": 3953,
                      "plays": 471,
                      "sp": 327696,
                      "stage": 139169,
                      "text": 471,
                      "updated": "2019-01-12T00:55:59.145+01:00",
                      "wordcount": {
                        "sp": 7909927.0,
                        "stage": 880356,
                        "text": 8275863.0
                      }
                    },
                  },
                  {
                    "name": "rus",
                    "title": "Russian Drama Corpus",
                    "repository": "https://github.com/dracor-org/rusdracor",
                    "uri": "https://staging.dracor.org/api/v1/corpora/rus",
                    "metrics": {
                      "characters": 2440,
                      "female": 564,
                      "male": 1789,
                      "plays": 141,
                      "sp": 73485,
                      "stage": 31949,
                      "text": 141,
                      "updated": "2019-01-11T22:48:53.865+01:00",
                      "wordcount": {
                        "sp": 1388515.0,
                        "stage": 140415,
                        "text": 1468669.0
                      }
                    }
                  },
                  {
                    "name": "shake",
                    "title": "Shakespeare Drama Corpus",
                    "repository": "https://github.com/dracor-org/shakedracor",
                    "uri": "https://staging.dracor.org/api/v1/corpora/shake",
                    "metrics": {
                      "characters": 1433,
                      "female": 0,
                      "male": 0,
                      "plays": 37,
                      "sp": 31066,
                      "stage": 10450,
                      "text": 37,
                      "updated": "2019-01-11T22:53:29.419+01:00",
                      "wordcount": {
                        "sp": 876744,
                        "stage": 41230,
                        "text": 908286
                      }
                    }
                  }
                ]
    post:
      summary: Add new corpus
      operationId: post-corpora
      tags: [admin]
      requestBody:
        description: |
          The meta data for the new corpus can be provided in either JSON or XML
          format. The JSON structure is a straightforward object providing
          corpus name, title and (optionally) a repository URL. The XML format
          needs to be a TEI document with `teiCorpus` as its root element. The
          corpus title needs to be provided in the `titleStmt` while the name
          and repo URL are encoded in particular `idno` elements in the
          `publicationStmt` (see example).

          NB: Contrary to the TEI schema our teiCorpus document must not contain
          the `TEI` elements for individual plays.
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - title
              properties:
                name:
                  type: string
                  description: corpus name
                title:
                  type: string
                  description: corpus title
                repository:
                  type: string
                  description: repository URL
                archive:
                  type: string
                  description: >
                    URL of ZIP archive containing TEI files of the corpus

                    The TEI files are expected to be placed in a `tei`
                    subdirectory. Other files will be ignored when loading the
                    archive.
            example: |
              {
                "name": "rus",
                "title": "Russian Drama Corpus",
                "repository": "https://github.com/dracor-org/rusdracor"
              }
          application/xml:
            schema:
              type: string
            example: |
              <?xml version="1.0" encoding="UTF-8"?>
              <teiCorpus xmlns="http://www.tei-c.org/ns/1.0">
                <teiHeader>
                  <fileDesc>
                    <titleStmt>
                      <title>Test Drama Corpus</title>
                    </titleStmt>
                    <publicationStmt>
                      <publisher>DraCor</publisher>
                      <idno type="URI" xml:base="https://dracor.org/">test</idno>
                      <idno type="repo">https://github.com/dracor-org/testdracor</idno>
                    </publicationStmt>
                  </fileDesc>
                </teiHeader>
              </teiCorpus>
      responses:
        '200':
          description: Returns corpus metadata
          content:
            application/json:
              schema:
                type: object
        '409':
          description: Corpus already exists
        '400':
          description: Posted data lacks required properties or is malformed

  /corpora/{corpusname}:
    get:
      summary: List corpus content
      description: >-
        Lists all plays available in the corpus including the id, title,
        author(s) and other meta data.
      operationId: list-corpus-content
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
      responses:
        '200':
          description: Returns object representing corpus contents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Corpus'
        '404':
          description: Unknown corpus
    post:
      summary: Load corpus data from its repository
      description: >-
        This endpoint requires authorization.

        Posting `{"load": true}` to the corpus URI reloads the data for this
        corpus from its repository (if defined).
      operationId: load-corpus
      tags: [admin]
      parameters:
        - $ref: "#/components/parameters/corpusname"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - load
              properties:
                load:
                  type: boolean
            example: |
              {"load": true}
      responses:
        '202':
          description: Corpus update has been scheduled
          content:
            application/json:
              schema:
                type: object
              example: |
                {
                  "message": "corpus update scheduled"
                }
        '404':
          description: Unknown corpus
        '409':
          description: >-
            Corpus update could not be scheduled.

            This is the response when another update has not yet finished.
    delete:
      summary: Remove corpus from database
      operationId: delete-corpus
      tags: [admin]
      parameters:
        - $ref: "#/components/parameters/corpusname"
      responses:
        '200':
          description: Corpus deleted
        '404':
          description: Unknown corpus


  /corpora/{corpusname}/metadata:
    get:
      summary: List of metadata for all plays in a corpus
      operationId: corpus-metadata
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
      responses:
        '200':
          description: Returns a list of metadata for all plays
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PlayMetadata'
            text/csv:
              schema:
                type: string
        '404':
          description: Unknown corpus

  /corpora/{corpusname}/metadata/csv:
    get:
      summary: List of metadata for all plays in a corpus
      operationId: corpus-metadata-csv-endpoint
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
      responses:
        '200':
          description: Returns a comma separated list of metadata for all plays
          content:
            text/csv:
              example: |
                name,id,wikidataId,firstAuthor,numOfCoAuthors,title,subtitle,normalizedGenre,digitalSource,originalSourcePublisher,originalSourcePubPlace,originalSourceYear,originalSourceNumberOfPages,yearNormalized,size,libretto,averageClustering,density,averagePathLength,maxDegreeIds,averageDegree,diameter,yearPremiered,yearPrinted,maxDegree,numOfSpeakers,numOfSpeakersFemale,numOfSpeakersMale,numOfSpeakersUnknown,numOfPersonGroups,numConnectedComponents,numEdges,yearWritten,numOfSegments,wikipediaLinkCount,numOfActs,wordCountText,wordCountSp,wordCountStage,numOfP,numOfL
                "achat-ein-april-scherz","ger000637","Q121463020","Achat","0","Ein April-Scherz","Original-Lustspiel in einem Akt","Comedy","https://books.google.com/books?id=qHNIAQAAMAAJ&pg=PA45","Vereins-Buchhandlung","Berlin","1842","30","1842","6","false","0.8444444444444444","0.8","1.2","fraeulein|rittmeister","4","2","","1842","5","6","3","3","0","0","1","12","","22","0","0","6888","6681","411","518","0"
              schema:
                type: string
        '404':
          description: Unknown corpus

  /corpora/{corpusname}/plays/{playname}:
    get:
      summary: Get metadata and network metrics for a single play
      operationId: play-info
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns an object with play meta data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Play'
        '404':
          description: Unknown play (or corpus)
    delete:
      summary: Remove a single play from the corpus
      operationId: play-delete
      tags: [admin]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Play has been removed
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/metrics:
    get:
      summary: Get network metrics for a single play
      operationId: play-metrics
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns an object with metrics data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayMetrics'
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/tei:
    get:
      summary: Get TEI document of a single play
      operationId: play-tei
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns TEI document. See [Encoding Guidelines](https://github.com/dracor-org/dracor-schema/tree/main/odd).
          content:
            application/xml:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)
    put:
      summary: Add new or update existing TEI document
      description: |
        When sending a PUT request to a new play URI, the request body is stored
        in the database as a new document accessible under that URI. If the URI
        already exists the corresponding TEI document is updated with the
        request body.

        The `playname` parameter of a new URI must consist of lower case ASCII
        characters, digits and/or dashes only.
      operationId: play-tei-put
      tags: [admin]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - name: playname
          in: path
          required: true
          schema:
            type: string
            pattern: "[a-z0-9]+([-a-z0-9]?[a-z0-9])?"
      requestBody:
        description: TEI document
        content:
          application/xml:
            schema:
              type: string
      responses:
        '200':
          description: TEI document has been stored
          content:
            application/xml:
              schema:
                type: string
        '400':
          description: >-
            The request body is not a valid TEI document or the `playname` is
            invalid.
        '404':
          description: >-
            There is no corpus with the given `corpusname`.

  /corpora/{corpusname}/plays/{playname}/characters:
    get:
      summary: Get a list of characters of a play
      operationId: get-characters
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns list of characters
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Character'
              example: |
                [
                  {
                    "numOfSpeechActs": 171,
                    "gender": "MALE",
                    "numOfScenes": 21,
                    "name": "Городничий",
                    "numOfWords": 4985,
                    "isGroup": false,
                    "id": "gorodnichij"
                  },
                  {
                    "numOfSpeechActs": 49,
                    "gender": "MALE",
                    "numOfScenes": 8,
                    "name": "Аммос Федорович",
                    "numOfWords": 748,
                    "isGroup": false,
                    "id": "ammos_fedorovich_ljapkin_tjapkin"
                  },
                  {
                    "numOfSpeechActs": 50,
                    "gender": "MALE",
                    "numOfScenes": 9,
                    "name": "Артемий Филиппович Земляника",
                    "numOfWords": 735,
                    "isGroup": false,
                    "id": "artemij_filippovich_zemljanika"
                  },
                  {
                    "numOfSpeechActs": 24,
                    "gender": "MALE",
                    "numOfScenes": 8,
                    "name": "Лука Лукич",
                    "numOfWords": 291,
                    "isGroup": false,
                    "id": "luka_lukich"
                  }
                ]
            text/csv:
              schema:
                type: string
              example: |
                id,name,gender,isGroup,numOfScenes,numOfSpeechActs,numOfWords
                "gorodnichij","Городничий","MALE","false","21","171","4985"
                "ammos_fedorovich_ljapkin_tjapkin","Аммос Федорович","MALE","false","8","49","748"
                "artemij_filippovich_zemljanika","Артемий Филиппович Земляника","MALE","false","9","50","735"
                "luka_lukich","Лука Лукич","MALE","false","8","24","291"
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/characters/csv:
    get:
      summary: Get a list of characters of a play (CSV)
      operationId: get-characters-csv
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns list of characters as CSV
          content:
            text/csv:
              schema:
                type: string
              example: |
                id,name,gender,isGroup,numOfScenes,numOfSpeechActs,numOfWords
                "gorodnichij","Городничий","MALE","false","21","171","4985"
                "ammos_fedorovich_ljapkin_tjapkin","Аммос Федорович","MALE","false","8","49","748"
                "artemij_filippovich_zemljanika","Артемий Филиппович Земляника","MALE","false","9","50","735"
                "luka_lukich","Лука Лукич","MALE","false","8","24","291"
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/networkdata/csv:
    get:
      summary: Get network data of a play as CSV
      operationId: network-csv
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns CSV file
          content:
            text/csv:
              schema:
                type: string
              example: |
                Source,Type,Target,Weight
                choros,Undirected,atossa,4
                choros,Undirected,angelos,3
                choros,Undirected,dareios,2
                choros,Undirected,xerxes,2
                atossa,Undirected,angelos,2
                atossa,Undirected,dareios,1
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/networkdata/gexf:
    get:
      summary: Get network data of a play as GEXF
      operationId: network-gexf
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns GEXF file. See [Specification](https://gexf.net).
          content:
            application/xml:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/networkdata/graphml:
    get:
      summary: Get network data of a play as GraphML
      operationId: network-graphml
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns GraphML file
          content:
            application/xml:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/relations/csv:
    get:
      summary: Get relation data of a play as CSV
      operationId: relations-csv
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns CSV file
          content:
            text/csv:
              schema:
                type: string
              example: |
                Source,Type,Target,Label
                amaryllis,Undirected,atalanta,siblings
                amaryllis,Undirected,menalkas,siblings
                atalanta,Undirected,menalkas,siblings
                myrtillus,Undirected,doris,siblings
                amaryllis,Directed,corydon,lover_of
                damoetas,Directed,atalanta,parent_of
                damoetas,Directed,amaryllis,parent_of
                damoetas,Directed,menalkas,parent_of
                nisus,Directed,doris,lover_of
                corydon,Directed,atalanta,lover_of
        '404':
          description: Unknown play or play does not provide relation data

  /corpora/{corpusname}/plays/{playname}/relations/gexf:
    get:
      summary: Get relation data of a play as GEXF
      operationId: relations-gexf
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns GEXF file. See [Specification](https://gexf.net).
          content:
            application/xml:
              schema:
                type: string
              example: |
                <?xml version="1.0" encoding="UTF-8"?>
                <gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
                  <meta>
                    <creator>dracor.org</creator>
                    <description>Relations for Gottsched, Johann Christoph: Atalanta oder die bezwungene Sprödigkeit</description>
                  </meta>
                  <graph mode="static">
                    <attributes class="node" mode="static">
                      <attribute id="gender" title="Gender" type="string"/>
                      <attribute id="person-group" title="Person group" type="boolean"/>
                      <attribute id="number-of-words" title="Number of spoken words" type="integer"/>
                    </attributes>
                    <attributes class="edge" mode="static">
                      <attribute id="label" title="Label" type="string"/>
                    </attributes>
                    <nodes>
                      <node id="doris" label="Doris">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="1037"/>
                          <attvalue for="gender" value="FEMALE"/>
                        </attvalues>
                      </node>
                      <node id="menalkas" label="Menalkas">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="1509"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                      <node id="nisus" label="Nisus">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="2203"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                      <node id="atalanta" label="Atalanta">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="2307"/>
                          <attvalue for="gender" value="FEMALE"/>
                        </attvalues>
                      </node>
                      <node id="corydon" label="Corydon">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="1373"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                      <node id="damon" label="Damon">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="2674"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                      <node id="amaryllis" label="Amaryllis">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="823"/>
                          <attvalue for="gender" value="FEMALE"/>
                        </attvalues>
                      </node>
                      <node id="myrtillus" label="Myrtillus">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="1720"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                      <node id="damoetas" label="Damötas">
                        <attvalues>
                          <attvalue for="person-group" value="0"/>
                          <attvalue for="number-of-words" value="679"/>
                          <attvalue for="gender" value="MALE"/>
                        </attvalues>
                      </node>
                    </nodes>
                    <edges>
                      <edge id="1" source="amaryllis" target="atalanta" type="undirected" label="siblings"/>
                      <edge id="2" source="amaryllis" target="menalkas" type="undirected" label="siblings"/>
                      <edge id="3" source="atalanta" target="menalkas" type="undirected" label="siblings"/>
                      <edge id="4" source="myrtillus" target="doris" type="undirected" label="siblings"/>
                      <edge id="5" source="amaryllis" target="corydon" type="directed" label="lover_of"/>
                      <edge id="6" source="damoetas" target="atalanta" type="directed" label="parent_of"/>
                      <edge id="7" source="damoetas" target="amaryllis" type="directed" label="parent_of"/>
                      <edge id="8" source="damoetas" target="menalkas" type="directed" label="parent_of"/>
                      <edge id="9" source="nisus" target="doris" type="directed" label="lover_of"/>
                      <edge id="10" source="corydon" target="atalanta" type="directed" label="lover_of"/>
                    </edges>
                  </graph>
                </gexf>
        '404':
          description: Unknown play or play does not provide relation data

  /corpora/{corpusname}/plays/{playname}/relations/graphml:
    get:
      summary: Get relation data of a play as GraphML
      operationId: relations-graphml
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns GraphML file
          content:
            application/xml:
              schema:
                type: string
              example: |
                <?xml version="1.0" encoding="UTF-8"?>
                <graphml xmlns="http://graphml.graphdrawing.org/xmlns">
                  <key attr.name="label" attr.type="string" for="node" id="label"/>
                  <key attr.name="Relation" attr.type="string" for="edge" id="relation"/>
                  <key attr.name="Gender" attr.type="string" for="node" id="gender"/>
                  <key attr.name="Person group" attr.type="boolean" for="node" id="person-group"/>
                  <graph edgedefault="undirected">
                    <node id="doris">
                      <data key="label">Doris</data>
                      <data key="gender">FEMALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="menalkas">
                      <data key="label">Menalkas</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="nisus">
                      <data key="label">Nisus</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="atalanta">
                      <data key="label">Atalanta</data>
                      <data key="gender">FEMALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="corydon">
                      <data key="label">Corydon</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="damon">
                      <data key="label">Damon</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="amaryllis">
                      <data key="label">Amaryllis</data>
                      <data key="gender">FEMALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="myrtillus">
                      <data key="label">Myrtillus</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <node id="damoetas">
                      <data key="label">Damötas</data>
                      <data key="gender">MALE</data>
                      <data key="person-group">false</data>
                    </node>
                    <edge id="1" directed="false" source="amaryllis" target="atalanta">
                      <data key="relation">siblings</data>
                    </edge>
                    <edge id="2" directed="false" source="amaryllis" target="menalkas">
                      <data key="relation">siblings</data>
                    </edge>
                    <edge id="3" directed="false" source="atalanta" target="menalkas">
                      <data key="relation">siblings</data>
                    </edge>
                    <edge id="4" directed="false" source="myrtillus" target="doris">
                      <data key="relation">siblings</data>
                    </edge>
                    <edge id="5" directed="true" source="amaryllis" target="corydon">
                      <data key="relation">lover_of</data>
                    </edge>
                    <edge id="6" directed="true" source="damoetas" target="atalanta">
                      <data key="relation">parent_of</data>
                    </edge>
                    <edge id="7" directed="true" source="damoetas" target="amaryllis">
                      <data key="relation">parent_of</data>
                    </edge>
                    <edge id="8" directed="true" source="damoetas" target="menalkas">
                      <data key="relation">parent_of</data>
                    </edge>
                    <edge id="9" directed="true" source="nisus" target="doris">
                      <data key="relation">lover_of</data>
                    </edge>
                    <edge id="10" directed="true" source="corydon" target="atalanta">
                      <data key="relation">lover_of</data>
                    </edge>
                  </graph>
                </graphml>
        '404':
          description: Unknown play or play does not provide relation data

  /corpora/{corpusname}/plays/{playname}/spoken-text:
    get:
      summary: Get spoken text of a play (excluding stage directions)
      operationId: play-spoken-text
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
        - name: gender
          in: query
          required: false
          schema:
            type: string
            enum: [FEMALE, MALE, UNKNOWN]
        - name: relation
          in: query
          required: false
          schema:
            type: string
            enum:
              - siblings
              - friends
              - spouses
              - parent_of_active
              - parent_of_passive
              - lover_of_active
              - lover_of_passive
              - related_with_active
              - related_with_passive
              - associated_with_active
              - associated_with_passive
        - name: role
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Returns plain text document
          content:
            text/plain:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/spoken-text-by-character:
    get:
      summary: Get spoken text for each character of a play
      operationId: play-spoken-text-by-character
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns texts per character
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SpokenTextByCharacter'
            text/csv:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/stage-directions:
    get:
      summary: Get all stage directions of a play
      operationId: play-stage-directions
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns plain text document
          content:
            text/plain:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /corpora/{corpusname}/plays/{playname}/stage-directions-with-speakers:
    get:
      summary: Get all stage directions of a play including speakers
      operationId: play-stage-directions-with-speakers
      tags: [public]
      parameters:
        - $ref: "#/components/parameters/corpusname"
        - $ref: "#/components/parameters/playname"
      responses:
        '200':
          description: Returns plain text document
          content:
            text/plain:
              schema:
                type: string
        '404':
          description: Unknown play (or corpus)

  /id/{id}:
    get:
      summary: Resolve DraCor play ID
      description: |
        Depending on the `Accept` header this endpoint redirects to either the
        RDF representation [play-rdf], the JSON meta data [play-info] or the
        dracor.org URL of the play identified by the `id` parameter.
      operationId: resolve-id
      tags: [public]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          example: ger000023
      responses:
        '303':
          description: Redirect to RDF or JSON resource or dracor.org URL.
        '404':
          description: No play found by this ID

  /character/{id}:
    get:
      summary: List plays having a character identified by Wikidata ID
      operationId: plays-with-character
      tags: [public]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          example: Q131412
      responses:
        '200':
          description: List of plays.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PlayWithWikidataCharacter'
        '400':
          description: Invalid character ID.
        '404':
          description: Unknown character

  /dts:
    get:
      summary: Distributed Text Services API Entrypoint
      description: >-
        Entrypoint of the DraCor DTS implementation (see specification – https://distributed-text-services.github.io/specifications/versions/1-alpha/#entry-endpoint).
      operationId: dts-entrypoint
      tags: [DTS]
      responses:
        '200':
          description: information about the DTS implementation containing URI templates of the "collection", "navigation" and "document" endpoints.
          content:
            application/ld+json:
              schema:
                $ref: '#/components/schemas/DtsEntrypoint'
              example: |
                {
                  "@context" : "https://distributed-text-services.github.io/specifications/context/1-alpha1.json",
                  "@id" : "https://staging.dracor.org/api/v1/dts",
                  "@type" : "EntryPoint",
                  "dtsVersion" : "1-alpha",
                  "collection" : "https://staging.dracor.org/api/v1/dts/collection{?id}",
                  "document" : "https://staging.dracor.org/api/v1/dts/document{?resource,ref,start,end}",
                  "navigation" : "https://staging.dracor.org/api/v1/dts/navigation{?resource,ref}"
                }

  /dts/collection:
    get:
      summary: DTS Collection
      description: >-
        Collection endpoint: Lists the collections available. Documentation see https://distributed-text-services.github.io/specifications/versions/1-alpha/#collection-endpoint.
      operationId: get-dts-collection
      tags: [DTS]
      parameters:
        - name: id
          in: query
          required: false
          description: Identifier for a collection or document. Preferably the full URI of a corpus or a play, but shorter DraCor IDs are also supported.
          schema:
            type: string
          examples:
              corpus_via_dts_collection_uri:
                value: https://dracor.org/id/ger
                summary: German Drama Corpus (URI)
              corpus_via_dts_collection_corpusname:
                value: rus
                summary: Russian Drama Corpus (DraCor ID)
              single_play_via_dts_collection_uri:
                value: https://dracor.org/id/ger000088
                summary: G.E. Lessing – Emilia Galotti (URI)
              single_play_via_dts_collection_playname:
                value: ger000088
                summary: G.E. Lessing – Emilia Galotti (DraCor ID)
        - name: nav
          in: query
          required: false
          description: Determines whether the content of the member property represents parent or child items.
          schema:
            type: string
            enum:
              - parents
      responses:
        '200':
          description: Collections available.
          content:
            application/ld+json:
              schema:
                type: object
              example: |
                {
                  "@context" : "https://distributed-text-services.github.io/specifications/context/1-alpha1.json",
                  "@id" : "http://localhost:8088/id/test",
                  "@type" : "Collection",
                  "dtsVersion" : "1-alpha",
                  "totalItems" : 1,
                  "totalParents" : 1,
                  "totalChildren" : 1,
                  "title" : "Test Drama Corpus",
                  "description" : "This corpus is for testing purposes only. It features a handful of plays in different languages.",
                  "members" : [
                  {
                    "@id" : "http://localhost:8088/id/test000001",
                    "@type" : "Resource",
                    "title" : "Ревизор",
                    "totalItems" : 0,
                    "totalParents" : 1,
                    "totalChildren" : 0,
                    "dublinCore" :
                      {
                        "language" : "rus",
                        "creator" : "Гоголь, Николай Васильевич"
                      },
                      "document" : "http://localhost:8088/api/v1/dts/document?resource=http://localhost:8088/id/test000001",
                      "navigation" : "http://localhost:8088/api/v1/dts/navigation?resource=http://localhost:8088/id/test000001",
                      "download" : "http://localhost:8088/api/v1/dts/corpora/test/plays/gogol-revizor/tei"
                  }
                  ]
                }
        '400':
          description: Bad request. Using the parameter `page` with a document is not possible. (Paging functionality has not been implemented yet.)
        '404':
          description: The requested resource is not available.
        '501':
          description: Not implemented. Using the undocumented parameter `page` will result in this status code. The paging functionality has not been implemented yet.

  /dts/navigation:
    get:
      summary: Navigation
      description: >-
        Navigation endpoint: Documentation see https://distributed-text-services.github.io/specifications/versions/1-alpha/#navigation-endpoint.
      operationId: get-dts-navigation
      tags: [DTS]
      parameters:
        - name: resource
          in: query
          required: true
          description: The unique identifier for the Resource whose tree or subtree must be returned. Should be the full URI of a play (recommended) or the DraCor ID.
          schema:
            type: string
          example: https://dracor.org/id/ger000088
        - name: ref
          in: query
          required: false
          description: The identifier of a single node in the CitationTree for the Resource, used as the root for the sub-tree to be reconstructed.
          examples:
              first_act:
                value: body/div[1]
                summary: first act
              second_scene_thrid_act:
                value: body/div[3]/div[2]
                summary: 2nd scene of the 3rd act
          schema:
            type: string
        - name: start
          in: query
          required: false
          description: The string identifier of a node in the CitationTree for the Resource, used as the starting point for a range that serves as the reference point for the query. This parameter is inclusive, so the starting point is considered part of the sub-tree to be returned.
          schema:
            type: string
            example: body/div[2]/div[1]
        - name: end
          in: query
          required: false
          description: The string identifier of a node in the CitationTree for the Resource, used as the ending point for a range that serves as the reference point for the query. This parameter is inclusive, so the supplied ending point is considered part of the specified range.
          schema:
            type: string
            example: body/div[2]/div[3]
        - name: down
          in: query
          required: false
          schema:
            type: string
            enum:
            - "-1"
            - "0"
            - "1"
            - "2"
            - "3"
            - "4"
      responses:
        '200':
          description: Successful.
          content:
            application/ld+json:
              schema:
                type: object
        '400':
          description: Bad request. Check error message in the response.
        '404':
          description: There are no Citeable Unit(s) identified by the provided identifier(s) in `ref`, `start` or `end`.
        '501':
          description: Not implemented. Not all of the functionality foreseen by the specification is fully implemented, e.g. requesting sub-structures of non-body elements.

  /dts/document:
    get:
      summary: DTS Document endpoint
      description: >-
        DTS Document endpoint: Documentation see https://distributed-text-services.github.io/specifications/versions/1-alpha/#document-endpoint.
      operationId: get-dts-document
      tags: [DTS]
      parameters:
        - name: resource
          in: query
          required: true
          description: The unique identifier for the Resource whose tree or subtree must be returned. Should be the full URI of a play (recommended) or the DraCor ID.
          schema:
            type: string
          example: https://dracor.org/id/ger000088
        - name: ref
          in: query
          required: false
          description: The identifier of a single node in the CitationTree for the Resource, used as the root for the sub-tree to be reconstructed.
          examples:
              first_act:
                value: body/div[1]
                summary: first act
              second_scene_thrid_act:
                value: body/div[3]/div[2]
                summary: 2nd scene of the 3rd act
          schema:
            type: string
        - name: start
          in: query
          required: false
          description: The string identifier of a node in the CitationTree for the Resource, used as the starting point for a range that serves as the reference point for the query. This parameter is inclusive, so the starting point is considered part of the sub-tree to be returned.
          schema:
            type: string
            example: body/div[2]/div[1]
        - name: end
          in: query
          required: false
          description: The string identifier of a node in the CitationTree for the Resource, used as the ending point for a range that serves as the reference point for the query. This parameter is inclusive, so the supplied ending point is considered part of the specified range.
          schema:
            type: string
            example: body/div[2]/div[3]
      responses:
        '200':
          description: Returns either a whole TEI-XML document of a play or a fragment thereof. In case a fragment was requested it is contained in the element <dts:wrapper> inside the root <TEI> element.
          content:
            application/xml:
              schema:
                type: string
                example: |
                  <?xml version="1.0" encoding="UTF-8"?>
                  <TEI xmlns="http://www.tei-c.org/ns/1.0">
                    <dts:wrapper xmlns:dts="https://w3id.org/dts/api#">
                      <!-- requested document fragment -->
                    </dts:wrapper>
                  </TEI>
        '400':
          description: Bad request – (1) The combination of the parameter 'ref' together with 'start' and 'end' is not allowed. (2) Only one parameter of the pair 'start' and 'end' is provided.
        '404':
          description: The resource requested is not found.
        '501':
          description: This functionality has not been implemented yet. If the parameters documented above are used correctly this status code should never be returned.

  /wikidata/author/{id}:
    get:
      summary: List author information from Wikidata
      operationId: wikidata-author-info
      tags: [wikidata]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          example: Q34628
      responses:
        '200':
          description: Author information
          content:
            application/json:
              schema:
                type: object
        '404':
          description: Invalid or unknown author ID
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    description: an error message
              example: |
                {
                  "error": "invalid author ID"
                }

  /wikidata/mixnmatch:
    get:
      summary: Endpoint for Wikidata Mix'n'match
      description: See https://meta.wikimedia.org/wiki/Mix'n'match/Import.
      operationId: wikidata-mixnmatch
      tags: [wikidata]
      responses:
        '200':
          description: List of plays (id, name, q [wikidata ID]).
          content:
            text/csv:
              schema:
                type: string

  /webhook/github:
    post:
      summary: GitHub Webhook
      description: >-
        Endpoint accepting POST requests from Github (see
        https://developer.github.com/webhooks/). We currently only handle push
        events on the main branch.
      operationId: github-webhook
      tags: [webhook]
      parameters:
        - in: header
          name: User-Agent
          required: true
          schema:
            type: string
            pattern: "GitHub-Hookshot/.*"
        - in: header
          name: X-GitHub-Delivery
          required: true
          schema:
            type: string
          example: "4e16d4dc-1d87-11e9-830d-68e2a0832130"
        - in: header
          name: X-GitHub-Event
          required: true
          schema:
            type: string
            enum: ["push"]
        - in: header
          name: X-Hub-Signature
          required: true
          schema:
            type: string
          example: "sha1=6da21762fada5c1d0205c6e42xxxxxxxxxx357c0"
      requestBody:
        description: >-
          Webhook payload (see https://developer.github.com/webhooks/#payloads)
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: >-
            Webhook delivery has been received, a status message is being
            returned.
          content:
            application/json:
              schema:
                type: object
              example: |
                {
                  "message": "Delivery accepted.",
                  "result": "/db/dracor/webhook/20190121213010-xxx.xml",
                  "scheduled": true
                }

components:
  parameters:
    corpusname:
      name: corpusname
      in: path
      required: true
      description: >
        Short name of the corpus as provided in the `name` property of the result
        objects from the [/corpora](#/public/list-corpora) endpoint
      schema:
        type: string
      examples:
        GerDraCor:
          value: ger
          summary: German Drama Corpus
        GreekDraCor:
          value: greek
          summary: Greek Drama Corpus
        ItaDraCor:
          value: ita
          summary: Italian Drama Corpus
        RomDraCor:
          value: rom
          summary: Roman Drama Corpus
        RusDraCor:
          value: rus
          summary: Russian Drama Corpus
        ShakeDraCor:
          value: shake
          summary: Shakespeare Drama Corpus
        SpanDraCor:
          value: span
          summary: Spanish Drama Corpus
    playname:
      name: playname
      in: path
      required: true
      description: >
        Name parameter (or "slug") of the play as provided in the `name`
        property of the result objects of the
        [/corpora/{corpusname}](#/public/list-corpus-content) endpoint.
      schema:
        type: string
      examples:
        lessing_galotti:
          value: lessing-emilia-galotti
          summary: "G.E. Lessing: Emilia Galotti (GerDraCor)"
        aeschylus_persians:
          value: aeschylus-persians
          summary: "Aeschylus: Persians (GreekDraCor)"
        goldoni_servitore:
          value: goldoni-il-servitore-di-due-padroni
          summary: "C. Goldoni: Il servitore di due padroni (ItaDraCor)"
        seneca_medea:
          value: seneca-medea
          summary: "Seneca: Medea (RomDraCor)"
        gogol_revizor:
          value: gogol-revizor
          summary: "N. Gogol: Revizor (RusDraCor)"
        shakespeare_hamlet:
          value: hamlet
          summary: "W. Shakespeare: Hamlet (ShakeDraCor)"
        munoz_refugio:
          value: munoz-refugio
          summary: "P. Muñoz Seca: El Refugio (SpanDraCor)"
  schemas:
    Info:
      type: object
      properties:
        name:
          # ontology: #service_name
          type: string
        version:
          # ontology: #service_version
          type: string
        status:
          # ontology: #service_development_stage
          type: string
        existdb:
          # ontology: #service_dependency_is_existdb_version
          type: string
        base:
          type: string
          format: url
        openapi:
          type: string
          format: url
      required:
        - name
        - version
        - status
        - existdb
        - base
        - openapi
    WordCounts:
      type: object
      properties:
        text:
          # ontology: #corpus_num_of_word_tokens_in_text_elements
          type: integer
        stage:
          # ontology: #corpus_num_of_word_tokens_in_stage
          type: integer
        sp:
          # ontology: #corpus_num_of_word_tokens_in_sp
          type: integer
      required:
        - text
        - stage
        - sp
    CorpusMetrics:
      type: object
      properties:
        characters:
          # ontology: #corpus_num_of_characters
          type: integer
        male:
          # ontology: #corpus_num_of_characters_male
          type: integer
        female:
          # ontology: #corpus_num_of_characters_female
          type: integer
        stage:
          # ontology: #corpus_num_of_stage
          type: integer
        sp:
          # ontology: #corpus_num_of_sp
          type: integer
        text:
          # ontology: #corpus_num_of_tei_text_elements
          type: integer
        plays:
          # ontology: #corpus_num_of_plays
          type: integer
        wordcount:
          # ontology: #contains_corpus_wordcount_data
          $ref: '#/components/schemas/WordCounts'
        updated:
          # ontology: #corpus_metrics_date_updated
          type: string
      required:
        - characters
        - male
        - female
        - stage
        - sp
        - text
        - plays
        - wordcount
        - updated
    CorpusInCorpora:
      type: object
      properties:
        uri:
          # ontology: #corpus_uri
          type: string
          format: url
        name:
          # ontology: #corpus_name
          type: string
        title:
          # ontology: #corpus_title
          type: string
        acronym:
          # ontology: #corpus_acronym
          type: string
        commit:
          type: string
        description:
          # ontology: #corpus_description
          type: string
        licence:
          # ontology: #corpus_licence
          type: string
        licenceUrl:
          # ontology: #corpus_licence_url
          type: string
          format: url
        repository:
          # ontology: #corpus_repository
          type: string
          format: url
        metrics:
          # ontology: contains_corpus_metrics_data
          $ref: '#/components/schemas/CorpusMetrics'
      required:
        - uri
        - name
        - title
        - acronym
    SourceInPlayMetadata:
      # see dutil:get-source
      type: object
      properties:
        name:
          # ontology: #play_digital_source_name
          type: string
          nullable: true
        url:
          # ontology: #play_digital_source_url
          type: string
          format: url
          nullable: true
      # currently neither name nor url is required, but we omit the source
      # object if none of the properties is available
      required: []
    ExternalReferenceResourceId:
      # see dutil:get-authors
      type: object
      properties:
        type:
          # ontology: #play_author_ref_external_id
          type: string
        ref:
          # ontology: #play_author_ref_type
          type: string
      required:
        - type
        - ref
    AuthorInPlayInCorpus:
      # see dutil:get-authors
      type: object
      properties:
        name:
          # ontology: #play_author_name
          type: string
        fullname:
          # ontology: #play_author_fullname
          type: string
        shortname:
          # ontology: #play_author_shortname
          type: string
        refs:
          # ontology: #contains_external_ref_id_data
          type: array
          items:
            $ref: '#/components/schemas/ExternalReferenceResourceId'
        alsoKnownAs:
          # ontology: #play_author_also_known_as
          type: array
          items:
            type: string
        nameEn:
          # ontology: #play_author_name_en
          type: string
        fullnameEn:
          # ontology: #play_author_fullname_en
          type: string
        shortnameEn:
          # ontology: #play_author_shortname_en
          type: string
      required:
        - name
        - fullname
        - shortname
        - refs
    PlayInCorpus:
      # see api:corpus-index
      type: object
      properties:
        id:
          # ontology: #play_id
          type: string
        uri:
          type: string
          format: url
        name:
          # ontology: #play_name
          type: string
        title:
          # ontology: #play_title
          type: string
        subtitle:
          # ontology: #play_subtitle
          type: string
        titleEn:
          # ontology: #play_title_en
          type: string
        subtitleEn:
          # ontology: #play_subtitle_en
          type: string
        authors:
          # ontology: #contains_play_author_data
          type: array
          items:
            $ref: '#/components/schemas/AuthorInPlayInCorpus'
        yearNormalized:
          # ontology: #play_year_normalized
          type: integer
          nullable: true
        yearWritten:
          # ontology: #play_year_written
          type: string
          nullable: true
        yearPremiered:
          # ontology: #play_year_premiered
          type: string
          nullable: true
        yearPrinted:
          # ontology: #play_year_printed
          type: string
          nullable: true
        datePremiered:
          # ontology: #play_date_premiered
          type: string
        source:
          # ontology: #contains_digital_source_data
          $ref: '#/components/schemas/SourceInPlayMetadata'
        networkdataCsvUrl:
          # ontology: #play_network_data_csv_url
          type: string
          format: url
        networkSize:
          # ontology: #play_network_size
          type: integer
        wikidataId:
          # ontology: #play_wikidata_id
          type: string
          nullable: true
      required:
        - id
        - uri
        - name
        - title
        - authors
        - yearNormalized
        - yearWritten
        - yearPremiered
        - yearPrinted
        - networkSize
        - networkdataCsvUrl
        - wikidataId
    Corpus:
      # see dutil:get-corpus-info
      type: object
      properties:
        name:
          # ontology: #corpus_name
          type: string
        title:
          # ontology: #corpus_title
          type: string
        acronym:
          # ontology: #corpus_acronym
          type: string
        description:
          # ontology: #corpus_description
          type: string
        commit:
          type: string
        repository:
          # ontology: #corpus_repository
          type: string
          format: url
        licence:
          # ontology: #corpus_licence
          type: string
        licenceUrl:
          # ontology: #corpus_licence_url
          type: string
          format: url
        plays:
          # ontology: #contains_play_data
          type: array
          items:
            $ref: '#/components/schemas/PlayInCorpus'
      required:
        - name
        - title
        - acronym
    PlayMetadata:
      # see dutil:get-corpus-meta-data
      type: object
      properties:
        id:
          # ontology: #play_id
          type: string
        name:
          # ontology: #play_name
          type: string
        title:
          # ontology: #play_title
          type: string
        subtitle:
          # ontology: #play_subtitle
          type: string
          nullable: true
        wikidataId:
          # ontology: #play_wikidata_id
          type: string
          nullable: true
        firstAuthor:
          # ontology: #play_first_author_shortname
          type: string
        yearNormalized:
          # ontology: #play_year_normalized
          type: integer
          nullable: true
        yearWritten:
          # ontology: #play_year_written
          type: string
          nullable: true
        yearPremiered:
          # ontology: #play_year_premiered
          type: string
          nullable: true
        yearPrinted:
          # ontology: #play_year_printed
          type: string
          nullable: true
        datePremiered:
          # ontology: #play_date_premiered
          type: string
        normalizedGenre:
          # ontology: #play_genre_normalized
          type: string
          nullable: true
        libretto:
          # ontology: #play_is_libretto
          type: boolean
        density:
          # ontology: #play_network_density
          type: number
        digitalSource:
          nullable: true
        originalSourceNumberOfPages:
          # ontology: #play_original_source_num_of_pages
          type: integer
          nullable: true
        originalSourcePubPlace:
          # ontology: #play_original_source_publication_place
          type: string
          nullable: true
        originalSourcePublisher:
          # ontology: #play_original_source_publisher
          type: string
          nullable: true
        originalSourceYear:
          # ontology: #play_original_source_publication_year
          type: integer
          nullable: true
        averageClustering:
          # ontology: #play_network_average_clustering
          type: number
        averageDegree:
          # ontology: #play_network_average_degree
          type: number
        averagePathLength:
          # ontology: #play_network_average_path_length
          type: number
        diameter:
          # ontology: #play_network_diameter
          type: integer
        maxDegree:
          # ontology: #play_network_max_degree
          type: integer
        maxDegreeIds:
          # ontology: #play_network_max_degree_character_id
          type: string
        numOfL:
          # ontology: #play_num_of_verse_lines
          type: integer
        numConnectedComponents:
          # ontology: #play_network_num_connected_components
          type: integer
        numEdges:
          # ontology: #play_network_num_edges
          type: integer
        numOfActs:
          # ontology: #play_num_of_acts
          type: integer
        numOfCoAuthors:
          # ontology: #play_num_of_co_authors
          type: integer
        numOfP:
          # ontology: #play_num_of_paragraphs
          type: integer
        numOfPersonGroups:
          # ontology: #play_num_of_person_groups
          type: integer
        numOfSegments:
          # ontology: #play_num_of_segments
          type: integer
        numOfSpeakers:
          # ontology: #play_num_of_speakers
          type: integer
        numOfSpeakersMale:
          # ontology: #play_num_of_speakers_gender_male
          type: integer
        numOfSpeakersFemale:
          # ontology: #play_num_of_speakers_gender_female
          type: integer
        numOfSpeakersUnknown:
          # ontology: #play_num_of_speakers_gender_unknown
          type: integer
        size:
          # ontology: #play_network_size
          type: integer
        wikipediaLinkCount:
          # ontology: #play_num_of_wikipedia_links
          type: integer
          nullable: true
        wordCountSp:
          # ontology: #play_num_of_word_tokens_in_sp
          type: integer
        wordCountStage:
          # ontology: #pplay_num_of_word_tokens_in_stage
          type: integer
        wordCountText:
          # ontology: #play_num_of_word_tokens_in_text_elements
          type: integer
      required:
        - id
        - name
        - title
        - subtitle
        - wikidataId
        - firstAuthor
        - yearNormalized
        - yearWritten
        - yearPremiered
        - yearPrinted
        - datePremiered
        - normalizedGenre
        - libretto
        - digitalSource
        - originalSourceNumberOfPages
        - originalSourcePublisher
        - originalSourcePubPlace
        - originalSourceYear
        - averageClustering
        - averageDegree
        - averagePathLength
        - density
        - diameter
        - maxDegree
        - maxDegreeIds
        - numConnectedComponents
        - numEdges
        - numOfActs
        - numOfCoAuthors
        - numOfL
        - numOfP
        - numOfPersonGroups
        - numOfSegments
        - numOfSpeakers
        - numOfSpeakersFemale
        - numOfSpeakersMale
        - numOfSpeakersUnknown
        - size
        - wikipediaLinkCount
        - wordCountSp
        - wordCountStage
        - wordCountText
    SegmentItemInPlayMetadata:
      # see dutil:get-play-info
      type: object
      properties:
        type:
          # ontology: #segment_type
          type: string
          nullable: true
        number:
          # ontology: #segment_number
          type: integer
        title:
          # ontology: #segment_title
          type: string
        speakers:
          type: array
          items:
            type: string
      required:
        - type
        - number
    AuthorInPlayMetadata:
      # FIXME: this schema seems to be identical to AuthorInPlayInCorpus, can we
      # eliminate it?
      type: object
      properties:
        refs:
          type: array
          items:
            $ref: '#/components/schemas/ExternalReferenceResourceId'
        alsoKnownAs:
          # ontology: #play_author_also_known_as
          type: array
          items:
            type: string
        fullnameEn:
          # ontology: #play_author_fullname_en
          type: string
        name:
          # ontology: #play_author_name
          type: string
        shortnameEn:
          # ontology: #play_author_shortname_en
          type: string
        nameEn:
          # ontology: #play_author_name_en
          type: string
        fullname:
          # ontology: #play_author_fullname
          type: string
        shortname:
          # ontology: #play_author_shortname
          type: string
      required:
        - name
        - fullname
        - shortname
        - refs
    CharacterInPlayMetadata:
      # see dutil:get-play-info
      type: object
      properties:
        id:
          # ontology: #character_id
          type: string
        name:
          # ontology: #character_name
          type: string
          nullable: true
        isGroup:
          # ontology: #character_is_group
          type: boolean
        sex:
          # ontology: #character_gender
          type: string
          nullable: true
          enum:
            - MALE
            - FEMALE
            - UNKNOWN
        wikidataId:
          # ontology: #character_wikidata_id
          type: string
      required:
        - id
        - name
        - isGroup
        - sex
    RelationItemInPlayMetadata:
      # see dutil:get-relations
      type: object
      properties:
        directed:
          # ontology: #character_relation_is_directed
          type: boolean
        type:
          # ontology: #character_relation_type
          type: string
          enum:
          - parent_of
          - lover_of
          - related_with
          - associated_with
          - siblings
          - spouses
          - friends
        source:
          # ontology: #character_relation_from
          type: string
        target:
          # ontology: #character_relation_to
          type: string
      required:
        - directed
        - type
        - source
        - target
    Play:
      # see dutil:get-play-info
      type: object
      properties:
        id:
          # ontology: #play_id
          type: string
        uri:
          type: string
          format: url
        name:
          # ontology: #play_name
          type: string
        corpus:
          # ontology: #play_corpus_name
          type: string
        title:
          # ontology: #play_title
          type: string
        subtitle:
          # ontology: #play_subtitle
          type: string
          nullable: true
        titleEn:
          # ontology: #play_title_en
          type: string
        subtitleEn:
          # ontology: #play_subtitle_en
          type: string
        authors:
          # ontology: #contains_play_author_data
          type: array
          items:
            $ref: '#/components/schemas/AuthorInPlayMetadata'
        yearNormalized:
          # ontology: #play_year_normalized
          type: integer
          nullable: true
        yearWritten:
          # ontology: #play_year_written
          type: string
          nullable: true
        yearPremiered:
          # ontology: #play_year_premiered
          type: string
          nullable: true
        yearPrinted:
          # ontology: #play_year_printed
          type: string
          nullable: true
        datePremiered:
          # ontology: #play_date_premiered
          type: string
        normalizedGenre:
          # ontology: #play_genre_normalized
          type: string
          nullable: true
        libretto:
          # ontology: #play_is_libretto
          type: boolean
        allInIndex:
          # ontology: #play_all_in_index
          type: number
          nullable: true
          minimum: 0.0
          maximum: 1.0
        allInSegment:
          # ontology: #play_all_in_segment
          type: integer
          nullable: true
        characters:
          # ontology: #contains_play_character_data
          type: array
          items:
            $ref: '#/components/schemas/CharacterInPlayMetadata'
        segments:
          type: array
          items:
            $ref: '#/components/schemas/SegmentItemInPlayMetadata'
        relations:
          # ontology: #contains_character_relation_data
          type: array
          items:
            $ref: '#/components/schemas/RelationItemInPlayMetadata'
        source:
          # ontology: #ccontains_digital_source_data
          $ref: '#/components/schemas/SourceInPlayMetadata'
        originalSource:
          # ontology: #play_original_source_full_citation
          type: string
        wikidataId:
          # ontology: #play_wikidata_id
          type: string
          nullable: true
      required:
        - id
        - uri
        - name
        - corpus
        - title
        - authors
        - yearPremiered
        - yearPrinted
        - yearWritten
        - yearNormalized
        - normalizedGenre
        - libretto
        - allInSegment
        - allInIndex
        - characters
        - segments
    NodeInPlayMetrics:
      # see dutil:get-play-metrics
      type: object
      properties:
        id:
          # ontology: #character_id
          type: string
        betweenness:
          # ontology: #haracter_node_betweenness
          type: number
        closeness:
          # ontology: #character_node_closeness
          type: number
        degree:
          # ontology: #character_node_degree
          type: integer
        eigenvector:
          # ontology: #character_node_eigenvector
          type: number
          nullable: true
        weightedDegree:
          # ontology: #character_node_weighted_degree
          type: integer
      required:
        - id
        - betweenness
        - closeness
        - degree
        - eigenvector
        - weightedDegree
    PlayMetrics:
      # see dutil:get-play-metrics
      type: object
      properties:
        id:
          # ontology: #play_id
          type: string
        name:
          # ontology: #play_name
          type: string
        corpus:
          # ontology: #play_corpus_name
          type: string
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/NodeInPlayMetrics'
        averageClustering:
          # ontology: #play_network_average_clustering
          type: number
        averageDegree:
          # ontology: #play_network_average_degree
          type: number
        averagePathLength:
          # ontology: #play_network_average_path_length
          type: number
        density:
          # ontology: #play_network_density
          type: number
        diameter:
          # ontology: #play_network_diameter
          type: integer
        maxDegree:
          # ontology: #play_network_average_degree
          type: integer
        maxDegreeIds:
          # ontology: #play_network_max_degree_character_id
          type: array
          items:
            type: string
        numConnectedComponents:
          # ontology: #play_network_num_connected_components
          type: integer
        numEdges:
          # ontology: #play_network_num_edges
          type: integer
        size:
          # ontology: #play_network_size
          type: integer
        wikipediaLinkCount:
          # ontology: #play_num_of_wikipedia_links
          type: integer
          nullable: true
      required:
        - id
        - name
        - corpus
        - nodes
        - averageClustering
        - averageDegree
        - averagePathLength
        - density
        - diameter
        - maxDegree
        - maxDegreeIds
        - numConnectedComponents
        - numEdges
        - size
        - wikipediaLinkCount
    Character:
      type: object
      properties:
        id:
          # ontology: #character_id
          type: string
        name:
          # ontology: #character_name
          type: string
          nullable: true
        isGroup:
          # ontology: #character_is_group
          type: boolean
        gender:
          # ontology: #character_gender
          type: string
          enum:
          - MALE
          - FEMALE
          - UNKNOWN
          nullable: true
        betweenness:
          # ontology: #character_node_betweenness
          type: number
          nullable: true
        closeness:
          # ontology: #character_node_closeness
          type: number
          nullable: true
        degree:
          # ontology: #character_node_degree
          type: integer
          nullable: true
        eigenvector:
          # ontology: #character_node_eigenvector
          type: number
          nullable: true
        numOfScenes:
          # ontology: #character_num_of_segments
          type: integer
        numOfSpeechActs:
          # ontology: #character_num_of_sp
          type: integer
        numOfWords:
          # ontology: #character_num_of_word_tokens
          type: integer
        weightedDegree:
          # ontology: #character_node_weighted_degree
          type: integer
          nullable: true
        wikidataId:
          # ontology: #character_wikidata_id
          type: string
      required:
        - id
        - name
        - isGroup
        - gender
        - betweenness
        - closeness
        - degree
        - eigenvector
        - numOfScenes
        - numOfSpeechActs
        - numOfWords
        - weightedDegree
    SpokenTextByCharacter:
      # see api:get-spoken-text-by-character
      type: object
      properties:
        id:
          # ontology: #character_id
          type: string
        label:
          # ontology: #character_name
          type: string
        isGroup:
          # ontology: #character_is_group
          type: boolean
        gender:
          type: string
          enum:
          - MALE
          - FEMALE
          - UNKNOWN
          nullable: true
        roles:
          # ontology: #character_role
          type: array
          nullable: true
          items:
            type: string
        text:
          # ontology: #character_spoken_text
          type: array
          items:
            type: string
      required:
        - id
        - label
        - isGroup
        - gender
        - roles
        - text
    PlayWithWikidataCharacter:
      # see dutil:get-plays-with-character
      type: object
      properties:
        id:
          type: string
        uri:
          type: string
          format: url
        title:
          type: string
        authors:
          type: array
          items:
            type: string
        characterName:
          type: string
      required:
        - id
        - uri
        - title
        - authors
        - characterName
    DtsEntrypoint:
      # see ddts:entry-point
      type: object
      properties:
        "@context":
          type: string
        "@id":
          type: string
        "@type":
          type: string
        dtsVersion:
          type: string
        collection:
          type: string
        document:
          type: string
        navigation:
          type: string
      required:
        - "@context"
        - "@id"
        - "@type"
        - dtsVersion
        - collection
        - document
        - navigation
