Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiments with templated hosts #779

Closed
darrelmiller opened this issue Sep 2, 2016 · 13 comments
Closed

Experiments with templated hosts #779

darrelmiller opened this issue Sep 2, 2016 · 13 comments

Comments

@darrelmiller
Copy link
Member

On the TDC call today, we experimented with a few different options for enabling parameterized host, schema and basePath. Community feedback would be much appreciated.

Option 1: Global parameters are back

{
    "openapi" : "3.0.0",

    "parameters" : {
        "version" : {
            "in" : "basepath",
            "default" : "v1.0", 
            "schema" : {
                "type" : "string"
            }
        },

        "environment" : {
            "in" : "host",
            "required" : true, 
            "schema" : {
                "type" : "string"
            }
        }
    },

    "hosts" : [
        { 
          "host" : "{environment}.example.org",
          "basePath" : "/{version}/api",
           "scheme" : "https"
         }
    ]

}

This is a minimally intrusive option but it brings the parameters back at the global scope which we are not particularly keen to do.

The next option trades the current array of hosts into a server object so that it can contain the host related parameters. It also means that there is only one baseUrl, but it can be parameterized and in fact the entire thing could be a parameter, which could allow for multiple static values using an enum parameter.

{
    "openapi" : "3.0.0",

    "server" : {
       "baseUrl" : "{scheme}://{environment}.example.org/{version}/api",

        "parameters" : [
             {
                "name" : "scheme", 
                "in" : "host",
                "default" : "https", 
                "schema" : {
                    "type" : "string"
                }
            },
             {
                "name" : "version", 
                "in" : "host",
                "required" : false, 
                "default" : "v1.0", 
                "schema" : {
                    "type" : "string"
                }
            },

            {
                "name" : "environment",
                "in" : "host",
                "required" : true, 
                "schema" : {
                    "type" : "string"
                }
            }

        ]
    }

}

There are concerns about how default values work in these parameters and the "in" : "host" is redundant but there just for consistency with the parameter object definition.

@ePaul
Copy link
Contributor

ePaul commented Sep 3, 2016

Hmm, the in: host parameter would work for a operation-specific parameter just as well, I think. No need for global parameters here.

@darrelmiller
Copy link
Member Author

@ePaul I suppose it would. Do we really want to have to specify the parameter in every operation though? Even if we $ref it, it is still a pain.

@ePaul
Copy link
Contributor

ePaul commented Sep 6, 2016

Hmm, good point. But didn't we have global (or at least path-level) parameters too?

@darrelmiller
Copy link
Member Author

Open 3.0 does have path item parameters, which is a bit less redundant than operation parameters, but still a little annoying. How do you feel about defining a parameters object inside a hosts/server object?

@DavidBiesack
Copy link

In option 2, should "in" : "host", be "in" : "baseUrl" ? I think the name host is misleading here.

Also, I think the "server" element name is also a bit misleading since it is a URL not just a server. I suggest using "baseUrl" for the outer container (a natural progression from "basePath" in 2.0) and it have "value" and "parameters" members:

{
    "openapi" : "3.0.0",
    "baseUrl" : {
       "value" : "{scheme}://{environment}.example.org/{version}/api",
        "parameters" : [ ... ]
}

@DavidBiesack
Copy link

Is there some additional background material on this proposal -what is the motivation/use case and what is the problem this solves? For example, how are the default values overridden? Can I open an Open API spec in the UI and set baseUrl parameters when I want to 'Try it out' ?

I suggest considering profiles , where a profile is a collection of parameter names/values. associated with values for these parameters (i.e. version 1.0, version 1.1, version 2.0) or for example dev/test/prod profiles to referencing the same API on dev, test, and prod servers. A specific profile may need to set more than just one variable such as environment; it may want to set {port} and {version} or some other baseUrl path parameter.

@darrelmiller
Copy link
Member Author

@david Yes, using in:host is misleading, however, it was a continuation of the current state of OpenApi 3.0 where "hosts" is a top level element that contains "hosts", "basePath" and "scheme".
'server' was an attempt to fix that, but I agree it's not ideal. Hoisting `baseUrl' to the root is an interesting alternative that is pretty clear.

The issues we are trying to address are mainly those brought up in issue #169. If I were to try and distill the intent to a single sentence, I would say: That by allowing parameters in the baseUrl we can use a single OpenAPI specification to access multiple implementations of the HTTP interface it describes.

The idea of parameter profiles is an interesting idea. I need to think about that some more.

@fehguy
Copy link
Contributor

fehguy commented Sep 30, 2016

@darrelmiller I've thought through this, here is my take.

  • I'm guess host parameterization will be something that will not be used by a majority of users. We shouldn't complicate the baseline case for the parameterization
  • Parameters will always be strings
  • The location will always be in the URL
  • There is no value in reusing them throughout the specification

With that, I'm suggesting we not try to reuse the parameter object, as it is never interchangeable with host parameters. We should create a new type, with the following properties:

  • type: string is implied
  • required: true is implied
  • default is required
  • enum is optional

That would produce something like this:

server:
  url: {scheme}://{environment}.gigantic-server.com/{base}
  templateParameters:  # <== let's choose a different name?
    scheme:
      enum:
      - http
      - https
      default: https
    environment: # no enum, so accept anything
      default: development
    base:
      enum:
      - /v1
      - /v2
      default: /v2

This ends up being nice an concise. In the degenerate case:

server:
  url: http://petstore.gigantic-server.com/v2

@jharmn
Copy link
Contributor

jharmn commented Sep 30, 2016

+1 to @fehguy's assertion that the parameter object is not a great fit here.

The problem being solved here is that any given environment should be able to change the server URL. As such, environment should be a top-level key with template params under it.
Then, environment specific URLs could be automagically built without any guessing.

Refining @fehguy 's example, with what I think is more realistic usage:

server: 
  url: "{scheme}://{host}:{port}/{base}"
  defaultTemplate: development
  templates:  // effectively 'environments' in practice 
    development: 
      scheme: 
        default: http
      host: 
        default: development.gigantic-server.com
      port:
        enum:
          - 8080
          - 8088
        default: 8080
      base: 
        default: v2
    production: 
      scheme: 
        default: http
        enum: 
          - http
          - https
      host: 
        default: api.gigantic-server.com
      port:
        default: 80
      base: 
        default: v2
        enum: 
          - v1
          - v2

Default (aka degenerate) case:

server:
  url: http://development.gigantic-server.com:8080/v2

@darrelmiller
Copy link
Member Author

Goofy comment up front: We could punt on all of this if we told people to put their OpenAPI document at the root of their API. Then we could make discovery a problem for APIs.json

Now back to sad reality. I don't think environments should be the primary use case of this feature. I think things like language, tenant and version are uses.

Should we really be encouraging people to be advertising the location of their development environment in their publicly facing OpenAPI document?

@ePaul
Copy link
Contributor

ePaul commented Oct 5, 2016

@darrelmiller In many cases I've seen the OpenAPI document being copied into the source code of a client, and then code generation (swagger-codegen or similar) being run on it. Now we either need to do a separate build for the development environment (and copy two files, which can easily go out of sync), override the URL for the dev version (or ignore the URL in the API definition and just take it from some configuration), or do some other hack.

@fehguy
Copy link
Contributor

fehguy commented Oct 7, 2016

Thanks @jharmn, @ePaul and @darrelmiller. I'm going to combine these thoughts into #812

@fehguy
Copy link
Contributor

fehguy commented Feb 1, 2017

Since #812 was merged, I'm closing this out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants