apiaryio / api-elements

API Elements is a structure for describing APIs and the complex data structures used within them.
http://apielements.org/
MIT License
28 stars 10 forks source link

Exposing Deployment Information #53

Open kylef opened 5 years ago

kylef commented 5 years ago

This is an issue to propose / discuss how we should expose information on where a particular API is deployed.

Current Support

API Blueprint

The API Blueprint does not include any support for describing the deployment information. API Blueprint does allow metadata at the top of an API Blueprint. Many tools use the metadata HOST which can be a URL to where the API may be deployed.

HOST: https://example.com/v2/

This is translated to metadata attribute for an API Category in API Elements:

{
  "element": "member",
  "meta": {
    "classes": {
      "element": "array",
      "content": [
        {
          "element": "string",
          "content": "user"
        }
      ]
    }
  },
  "content": {
    "key": {
      "element": "string",
      "content": "HOST"
    },
    "value": {
      "element": "string",
      "content": "https://example.com/v2/"
    }
  }
}

Swagger 2

Swagger 2 provides support for deployment information with schemes (array) host and basePath. Our adapter takes the first schema and host and places that in the same metadata section as API Blueprint so that the value is in a format that is already used by tooling and didn't require tooling updates.

schemes: [https]
host: example.com
basePath: /v2/

The above Swagger 2 structure would result in a HOST metadata of https://example.com and basePath would be prepended into every href found in the parse result which perhaps isn't the most ideal way to handle it. The problem is that the basePath may be supplied without a host and thus couldn't be exposed as HOST metadata.

{
  "element": "member",
  "meta": {
    "classes": {
      "element": "array",
      "content": [
        {
          "element": "string",
          "content": "user"
        }
      ]
    }
  },
  "content": {
    "key": {
      "element": "string",
      "content": "HOST"
    },
    "value": {
      "element": "string",
      "content": "https://example.com"
    }
  }
}
basePath: /v2/
paths:
  /user
{
  "element": "resource",
  "attributes": {
    "href": {
      "element": "string",
      "content": "/v2/user"
    }
  },
  "content": [...]
}

OpenAPI 3

In OpenAPI 3 a lot of server information including server variables may be described. See https://github.com/OAI/OpenAPI-Specification/blob/50c152549263cda0f05608d514ba78546b390d0e/versions/3.0.0.md#server-object or more details.

kylef commented 5 years ago

I was thinking we could introduce a concept of "Server" into API Elements which is similiar to OpenAPI 3. A server could contain a href, and optionally hrefVariables. The href is a URI template (template href). For example a simple OAS3 server would map to a server element:

element: server
meta:
  description: Production
attributes:
  href: https://example.com/

Templated variables may look as follows:

element: server
attributes:
  href: {scheme}://example.com/
  hrefVariables:
    element: object
    content:
      - element: member
        content:
          key: scheme
          value:
            element: enum
            attributes:
              enumerations:
                - http
                - https

A server MAY be inside a resource, or inside an API Category. The API Category may contain a "servers" category to group all available servers.

Tools such as API Documentation, API Consoles SHOULD make use of this information. Tools like API Gateways MAY utilise this information.

It should be possible to supply the server information at run-time to tooling, for example a console or documentation renderer should allow me to inject certain server information. The use-case is that it can inject mock-servers, or other tooling for example a configured API Gateway can populate server information to documentation renderer.

Mapping to other formats

API Blueprint

API Blueprint doesn't contain deployment information and thus does not emit any server elements.

NOTE, some have defined semantics for HOST as a metadata in API Blueprint. This will stay as-is, this is NOT a feature of API Blueprint and we want to keep the seperation of deployment information out of the API Blueprint language. It will not be mapped to servers object. HOST is NOT a feature of API Blueprint.

Swagger 2

The schemes, host, basePath is mapped into a server object similiar to the following:

element: server
attributes:
  href: {scheme}://{host}/{basePath}
  hrefVariables:
    element: object
    content:
      - element: member
        content:
          key: scheme
      - element: member
        content:
          key: host
      - element: member
        content:
          key: basePath

As some of these fields are optional in Swagger 2, they may not have a value. schemes will be mapped to either a fixed value or a enumeration of values. Similiary host and basePath will be mapped to variables in the server object.

OpenAPI 3

There is direct mapping between OAS 'Server Object' and server API Element.

kylef commented 5 years ago

Following some discussions in OpenAPI, there is some consensus that servers is perhaps a poor name (https://open-api.slack.com/archives/C1137F8HF/p1559929905003800), and hosts, backends or similiar may be a better fit.

klokane commented 5 years ago

What about ability set uri templates part in depencies on type of enviroment eg.

kylef commented 5 years ago

@klokane I think this can be solved with 'One Of', and enum, for example the MSON-pseudo code, the hrefVariables can be represented using selection:

I think you can imagine how that could be reproduced in the above element structure (didn't want to write extend/select API Elements by hand).

There can also simpler variant with enum, providing it is only one value that is changed:

element: server
attributes:
  href: https://{environment}/
  hrefVariables:
    element: object
    content:
      - element: member
        content:
          key: environment
          value:
            type: enum
            attributes:
              enumerations:
                - element: string
                  meta:
                    title:
                      element: string
                      content: Development
                  content: dev.example.com
                - element: string
                  meta:
                    title:
                      element: string
                      content: Production
                  content: example.com
klokane commented 5 years ago

Nice idea, maybe we should introduce standardized way howto place this into Blueprint to allow tooling work with. In relation to enviroment variables, it can be good idea for dredd (cc @honzajavorek)

kylef commented 5 years ago

There's a proof of concept implementation for OpenAPI 2 parser at https://github.com/apiaryio/api-elements.js/commit/50dc4947c1e51a60108f4deef94e3dfd442236da.

kylef commented 4 years ago

I had some discussions with @tjanc who proposed we should re-use the "resource" element because it already contains href and hrefVariables. Semantically, a server IS a resource. Therefore we can use the existing Resource Element instead of introducing a new element. To be able to differentiate the resource element from other resources, we can add an additional classifier of host to represent it is a host.

element: resource
meta:
  classes:
    - host
attributes:
  href: {scheme}://example.com/
  hrefVariables:
    element: hrefVariables
    content:
      - element: member
        content:
          key: scheme
          value:
            element: enum
            attributes:
              enumerations:
                - http
                - https

In terms of a category of these types of resources, we can have a hosts category which looks as follows:

element: category
meta:
  classes:
    - hosts
content:
  - element: resource
    meta:
      classes:
        - host
    attributes:
      href: {scheme}://example.com/
      hrefVariables:
        element: hrefVariables
        content:
          - element: member
            content:
              key: scheme
              value:
                element: enum
                attributes:
                  enumerations:
                    - http
                    - https

OpenAPI 3 also supports attaching a set of "Server Object"s to a resource (Path Item Object) or a transition (Operation Object). As such, in this case we can introduce a hosts attribute to "Resource Element" and "Transition Element" as follows:

element: resource
attributes:
  href: /foo
  hosts:
    element: category
    content:
      - element: resource
        meta:
          classes:
            - host
        attributes:
          href: {scheme}://example.com/
          hrefVariables:
            element: hrefVariables
            content:
              - element: member
                content:
                  key: scheme
                  value:
                    element: enum
                    attributes:
                      enumerations:
                        - http
                        - https

The existing API Elements referencing is also possible, thus:

element: resource
meta:
  id:
    element: string
    content: productionServer

can be referenced:

element: productionServer

To summarise, API Element may offer the following: