University of Helsinki · API Governance Rules

University of Helsinki API Rules

Spectral linting rules defining API design standards and conventions for University of Helsinki.

13 Rules error 5 warn 8
View Rules File View on GitHub

Rule Categories

api info no oauth2 operation path security server

Rules

error
server-url-absolute
Every server URL must be absolute. All thirteen University of Helsinki specs already do this, which is why none of them fell into the audit's `hostless` class — a relative or missing servers block is exactly how a vendor's contract passes as an institution's.
$.servers[*].url
error
server-on-institution-host
Server URLs must resolve to a host the University of Helsinki operates — gw.api.helsinki.fi for the gateway estate, api.laji.fi for the Finnish Museum of Natural History. A spec whose server points anywhere else does not belong in this repository.
$.servers[*].url
warn
operation-summary
Every operation should carry a summary. Met at 93%.
$.paths[*][get,put,post,delete,patch]
warn
operation-tags
Every operation should be tagged. Met at 91%.
$.paths[*][get,put,post,delete,patch]
warn
operation-operation-id
Every operation should carry an operationId. Met at 73%; the gap is concentrated in the older gateway APIs.
$.paths[*][get,put,post,delete,patch]
warn
operation-description
Every operation should carry a description as well as a summary. Met at only 25% — the largest single documentation gap in the estate, and the cheapest to close.
$.paths[*][get,put,post,delete,patch]
warn
info-description
Every spec should describe itself. Met by 5 of 13.
$.info
warn
info-contact
Every spec should name a contact. Met by 4 of 13, and where it is present the convention is a functional group address at helsinki.fi (tike-integraatiopalvelu@, grp-nxstage-devs@) rather than a named individual — that is the right convention and should be the rule.
$.info
error
security-scheme-declared
Every spec must declare at least one security scheme. The gateway has keyless access disabled, so a spec with no scheme cannot be called as written — two currently are in that state (Dawa Sync, Sovellussalkku).
$.components
warn
api-key-header-canonical
The gateway's own configuration names `X-Api-Key` as the credential header. Specs should use that exact spelling; one currently declares `X-API-Key`.
$.components.securitySchemes[?(@.type=='apiKey' && @.in=='header')].name
error
oauth2-flows-declared
An oauth2 security scheme must declare its flows. The one oauth2 scheme in the estate declares none and links a third-party CRM vendor's documentation, which is boilerplate that escaped into a published contract.
$.components.securitySchemes[?(@.type=='oauth2')]
warn
path-segment-lowercase
Path segments should be lowercase or kebab-case, the estate's dominant convention (466 of 541 segments).
$.paths
error
no-server-variables-unset
Server variables must carry a default so the URL is resolvable without out-of-band knowledge.
$.servers[*].variables[*]

Spectral Ruleset

Raw ↑
# authorship: generated by API Evangelist from the University of Helsinki's own
# published OpenAPI conventions, 2026-08-30. Nothing here is a house style
# imported from elsewhere -- every threshold below is a measurement of the
# thirteen institution-operated specs in openapi/_original/.
x-method: derived
x-source: openapi/_original/
x-operator: institution
#
# Measured across 13 specs / 320 operations / 316 component schemas:
#   servers absolute .............. 13/13  (100%)
#   operation summary ............. 297/320 (93%)
#   operation tags ................ 291/320 (91%)
#   security declared per op ...... 251/320 (78%)
#   operationId ................... 233/320 (73%)
#   operation description ......... 79/320  (25%)   <- the weak spot
#   info.description .............. 5/13    (38%)
#   info.contact .................. 4/13    (31%)
#   path segment casing ........... lower/kebab 466, snake 45, camel 20, other 10
#   property casing ............... camel 2045, lower 1372, snake 28, other 64
#
# Two rules below (operation-description, info-contact) are deliberately set at
# `warn` on conventions this estate does NOT currently meet. They are the
# remediation list, not a description of the status quo.
rules:
  server-url-absolute:
    description: >-
      Every server URL must be absolute. All thirteen University of Helsinki specs already do
      this, which is why none of them fell into the audit's `hostless` class — a relative or
      missing servers block is exactly how a vendor's contract passes as an institution's.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: '^https://'
  server-on-institution-host:
    description: >-
      Server URLs must resolve to a host the University of Helsinki operates —
      gw.api.helsinki.fi for the gateway estate, api.laji.fi for the Finnish Museum of Natural
      History. A spec whose server points anywhere else does not belong in this repository.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: '^https://(gw\.api\.helsinki\.fi|api\.laji\.fi)'
  operation-summary:
    description: Every operation should carry a summary. Met at 93%.
    severity: warn
    given: $.paths[*][get,put,post,delete,patch]
    then:
      field: summary
      function: truthy
  operation-tags:
    description: Every operation should be tagged. Met at 91%.
    severity: warn
    given: $.paths[*][get,put,post,delete,patch]
    then:
      field: tags
      function: truthy
  operation-operation-id:
    description: Every operation should carry an operationId. Met at 73%; the gap is concentrated in the older gateway APIs.
    severity: warn
    given: $.paths[*][get,put,post,delete,patch]
    then:
      field: operationId
      function: truthy
  operation-description:
    description: >-
      Every operation should carry a description as well as a summary. Met at only 25% — the
      largest single documentation gap in the estate, and the cheapest to close.
    severity: warn
    given: $.paths[*][get,put,post,delete,patch]
    then:
      field: description
      function: truthy
  info-description:
    description: Every spec should describe itself. Met by 5 of 13.
    severity: warn
    given: $.info
    then:
      field: description
      function: truthy
  info-contact:
    description: >-
      Every spec should name a contact. Met by 4 of 13, and where it is present the convention is
      a functional group address at helsinki.fi (tike-integraatiopalvelu@, grp-nxstage-devs@)
      rather than a named individual — that is the right convention and should be the rule.
    severity: warn
    given: $.info
    then:
      field: contact
      function: truthy
  security-scheme-declared:
    description: >-
      Every spec must declare at least one security scheme. The gateway has keyless access
      disabled, so a spec with no scheme cannot be called as written — two currently are in that
      state (Dawa Sync, Sovellussalkku).
    severity: error
    given: $.components
    then:
      field: securitySchemes
      function: truthy
  api-key-header-canonical:
    description: >-
      The gateway's own configuration names `X-Api-Key` as the credential header. Specs should use
      that exact spelling; one currently declares `X-API-Key`.
    severity: warn
    given: $.components.securitySchemes[?(@.type=='apiKey' && @.in=='header')].name
    then:
      function: pattern
      functionOptions:
        match: '^X-Api-Key$'
  oauth2-flows-declared:
    description: >-
      An oauth2 security scheme must declare its flows. The one oauth2 scheme in the estate
      declares none and links a third-party CRM vendor's documentation, which is boilerplate that
      escaped into a published contract.
    severity: error
    given: $.components.securitySchemes[?(@.type=='oauth2')]
    then:
      field: flows
      function: truthy
  path-segment-lowercase:
    description: Path segments should be lowercase or kebab-case, the estate's dominant convention (466 of 541 segments).
    severity: warn
    given: $.paths
    then:
      field: '@key'
      function: pattern
      functionOptions:
        match: '^\/([a-z0-9\-._~]+|\{[^}]+\})(\/([a-z0-9\-._~]+|\{[^}]+\}))*\/?$'
  no-server-variables-unset:
    description: Server variables must carry a default so the URL is resolvable without out-of-band knowledge.
    severity: error
    given: $.servers[*].variables[*]
    then:
      field: default
      function: truthy

Work with this as data

Every ruleset here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for spectral rules

4 MCP tools reach this
  • find_rulesBrowse and filter every ruleset in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This ruleset
curl "https://apis.io/api/v1/rules/university-of-helsinki-openapi-spectral-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.