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

feat: replace server url with server host and pathname #888

Merged
merged 13 commits into from
Feb 13, 2023
214 changes: 86 additions & 128 deletions spec/asyncapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,103 +353,42 @@ Field Pattern | Type | Description

##### Servers Object Example

```json
{
"production": {
"url": "development.gigantic-server.com",
"description": "Development server",
"protocol": "kafka",
"protocolVersion": "1.0.0"
}
}
```

```yaml
production:
url: development.gigantic-server.com
description: Development server
protocol: kafka
protocolVersion: '1.0.0'
```


#### <a name="serverObject"></a>Server Object

An object representing a message broker, a server or any other kind of computer program capable of sending and/or receiving data. This object is used to capture details such as URIs, protocols and security configuration. Variable substitution can be used so that some details, for example usernames and passwords, can be injected by code generation tools.

##### Fixed Fields

Field Name | Type | Description
---|:---:|---
<a name="serverObjectUrl"></a>url | `string` | **REQUIRED**. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the AsyncAPI document is being served. Variable substitutions will be made when a variable is named in `{`braces`}`.
<a name="serverObjectProtocol"></a>protocol | `string` | **REQUIRED**. The protocol this URL supports for connection. Supported protocol include, but are not limited to: `amqp`, `amqps`, `http`, `https`, `ibmmq`, `jms`, `kafka`, `kafka-secure`, `anypointmq`, `mqtt`, `secure-mqtt`, `solace`, `stomp`, `stomps`, `ws`, `wss`, `mercure`, `googlepubsub`.
<a name="serverObjectProtocolVersion"></a>protocolVersion | `string` | The version of the protocol used for connection. For instance: AMQP `0.9.1`, HTTP `2.0`, Kafka `1.0.0`, etc.
<a name="serverObjectDescription"></a>description | `string` | An optional string describing the host designated by the URL. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.
<a name="serverObjectVariables"></a>variables | Map[`string`, [Server Variable Object](#serverVariableObject) \| [Reference Object](#referenceObject)]] | A map between a variable name and its value. The value is used for substitution in the server's URL template.
<a name="serverObjectSecurity"></a>security | [[Security Requirement Object](#securityRequirementObject)] | A declaration of which security mechanisms can be used with this server. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a connection or operation.
<a name="serverObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of servers.
<a name="serverObjectBindings"></a>bindings | [Server Bindings Object](#serverBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the server.

This object MAY be extended with [Specification Extensions](#specificationExtensions).

##### Server Object Example

A single server would be described as:

```json
{
"url": "development.gigantic-server.com",
"description": "Development server",
"protocol": "kafka",
"protocolVersion": "1.0.0"
}
```

```yaml
url: development.gigantic-server.com
description: Development server
protocol: kafka
protocolVersion: '1.0.0'
```

The following shows how multiple servers can be described, for example, at the AsyncAPI Object's [`servers`](#A2SServers):

```json
{
"servers": {
"development": {
"url": "development.gigantic-server.com",
"description": "Development server",
"host": "localhost:5672",
"description": "Development AMQP broker.",
"protocol": "amqp",
"protocolVersion": "0.9.1",
"protocolVersion": "0-9-1",
"tags": [
{
"name": "env:development",
"description": "This environment is meant for developers to run their own tests"
"description": "This environment is meant for developers to run their own tests."
}
]
},
"staging": {
"url": "staging.gigantic-server.com",
"description": "Staging server",
"host": "rabbitmq-staging.in.mycompany.com:5672",
"description": "RabbitMQ broker for the staging environment.",
"protocol": "amqp",
"protocolVersion": "0.9.1",
"protocolVersion": "0-9-1",
"tags": [
{
"name": "env:staging",
"description": "This environment is a replica of the production environment"
"description": "This environment is a replica of the production environment."
}
]
},
"production": {
"url": "api.gigantic-server.com",
"description": "Production server",
"host": "rabbitmq.in.mycompany.com:5672",
"description": "RabbitMQ broker for the production environment.",
"protocol": "amqp",
"protocolVersion": "0.9.1",
"protocolVersion": "0-9-1",
"tags": [
{
"name": "env:production",
"description": "This environment is the live environment available for final users"
"description": "This environment is the live environment available for final users."
}
]
}
Expand All @@ -460,83 +399,71 @@ The following shows how multiple servers can be described, for example, at the A
```yaml
servers:
development:
url: development.gigantic-server.com
description: Development server
host: localhost:5672
description: Development AMQP broker.
protocol: amqp
protocolVersion: 0.9.1
protocolVersion: 0-9-1
tags:
- name: "env:development"
description: "This environment is meant for developers to run their own tests"
description: "This environment is meant for developers to run their own tests."
staging:
url: staging.gigantic-server.com
description: Staging server
host: rabbitmq-staging.in.mycompany.com:5672
description: RabbitMQ broker for the staging environment.
protocol: amqp
protocolVersion: 0.9.1
protocolVersion: 0-9-1
tags:
- name: "env:staging"
description: "This environment is a replica of the production environment"
description: "This environment is a replica of the production environment."
production:
url: api.gigantic-server.com
description: Production server
host: rabbitmq.in.mycompany.com:5672
description: RabbitMQ broker for the production environment.
protocol: amqp
protocolVersion: 0.9.1
protocolVersion: 0-9-1
tags:
- name: "env:production"
description: "This environment is the live environment available for final users"
description: "This environment is the live environment available for final users."
```

The following shows how variables can be used for a server configuration:

#### <a name="serverObject"></a>Server Object

An object representing a message broker, a server or any other kind of computer program capable of sending and/or receiving data. This object is used to capture details such as URIs, protocols and security configuration. Variable substitution can be used so that some details, for example usernames and passwords, can be injected by code generation tools.

##### Fixed Fields

Field Name | Type | Description
---|:---:|---
<a name="serverObjectHost"></a>host | `string` | **REQUIRED**. The server host name. It MAY include the port. This field supports [Server Variables](#serverObjectVariables). Variable substitutions will be made when a variable is named in `{`braces`}`.
<a name="serverObjectProtocol"></a>protocol | `string` | **REQUIRED**. The protocol this server supports for connection.
<a name="serverObjectProtocolVersion"></a>protocolVersion | `string` | The version of the protocol used for connection. For instance: AMQP `0.9.1`, HTTP `2.0`, Kafka `1.0.0`, etc.
fmvilas marked this conversation as resolved.
Show resolved Hide resolved
<a name="serverObjectDescription"></a>description | `string` | An optional string describing the server. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.
<a name="serverObjectVariables"></a>variables | Map[`string`, [Server Variable Object](#serverVariableObject) \| [Reference Object](#referenceObject)]] | A map between a variable name and its value. The value is used for substitution in the server's `host` template.
fmvilas marked this conversation as resolved.
Show resolved Hide resolved
<a name="serverObjectSecurity"></a>security | [[Security Requirement Object](#securityRequirementObject)] | A declaration of which security mechanisms can be used with this server. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a connection or operation.
<a name="serverObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of servers.
<a name="serverObjectBindings"></a>bindings | [Server Bindings Object](#serverBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the server.

This object MAY be extended with [Specification Extensions](#specificationExtensions).

##### Server Object Example

A single server would be described as:

```json
{
"servers": {
"production": {
"url": "{username}.gigantic-server.com:{port}/{basePath}",
"description": "The production API server",
"protocol": "secure-mqtt",
"variables": {
"username": {
"default": "demo",
"description": "This value is assigned by the service provider, in this example `gigantic-server.com`"
},
"port": {
"enum": [
"8883",
"8884"
],
"default": "8883"
},
"basePath": {
"default": "v2"
}
}
}
}
"host": "kafka.in.mycompany.com:9092",
"description": "Production Kafka broker.",
"protocol": "kafka",
"protocolVersion": "9"
fmvilas marked this conversation as resolved.
Show resolved Hide resolved
}
```

```yaml
servers:
production:
url: '{username}.gigantic-server.com:{port}/{basePath}'
description: The production API server
protocol: secure-mqtt
variables:
username:
# note! no enum here means it is an open value
default: demo
description: This value is assigned by the service provider, in this example `gigantic-server.com`
port:
enum:
- '8883'
- '8884'
default: '8883'
basePath:
# open meaning there is the opportunity to use special base paths as assigned by the provider, default is `v2`
default: v2
host: kafka.in.mycompany.com:9092
description: Production Kafka broker.
protocol: kafka
protocolVersion: '9'
fmvilas marked this conversation as resolved.
Show resolved Hide resolved
```


#### <a name="serverVariableObject"></a>Server Variable Object

An object representing a Server Variable for server URL template substitution.
Expand All @@ -552,8 +479,39 @@ Field Name | Type | Description

This object MAY be extended with [Specification Extensions](#specificationExtensions).

##### Server Variable Object Example

```json
{
"servers": {
"production": {
"host": "{org}.mycompany.com",
"path": "/api/v1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path ? where is this coming from?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were having a "URL" and now we have a host. A host does not have the "path" part so we have to add it separately.

Copy link
Member Author

@fmvilas fmvilas Dec 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other option is to remove the protocol field and go with a URL as we do now. Just not sure how this would play with protocols like kafka-secure (e.g., kafka-secure://hostname:port/path) and secure-mqtt (e.g., secure-mqtt://hostname:port/path), which are not "real" protocols. In such a case, we should probably get rid of the "secure" variants (that would include https and wss) and allow the user to specify it in the Security Requirement Object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we are actually fixing something, or making things a bit more complex. You add now path example that is a typical REST example for me. All the other examples I know (for example for Kafka) include a version in the topic name. In case of websocket it is completely fine to add path to channel name, but also if someone wants, can add it to url. The only use case for path that makes sense is HTTP, but then, if it is protocol specify, shouldn't it end up in the binding?

so basically my question is, do we really need to change url to host and path or, as majority of people in #274 wrote that we basically need to make description and examples better?

Copy link
Member Author

@fmvilas fmvilas Dec 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two things here:

  1. We often show examples where the url is "whatever.example.com". That's not a URL and that should fail because it doesn't have the protocol part of the URL (you know, protocol://).
  2. We have a field called protocol to define the protocol we want to use but it's already in the URL (!) ☝️ So you can end up with url: kafka://broker.mycompany.com and protocol: https in the same server definition, which is incongruent.

So we either remove the need to put a protocol in the url field (which makes it a host instead) or we remove the protocol field.

You add now path example that is a typical REST example for me.

I think you're mixing concepts here. A path is not about REST or not even HTTP. A path is a part of a URL. URLs are composed by protocol://, username:password (optional), hostname, port (optional), /path/to/resource (optional), ?query=parameters (optional), and #fragment (optional). These have nothing to do with REST or HTTP. I can have an AMQP broker at amqp://broker.mycompany.com/public and another one at amqp://broker.mycompany.com/partners. Depending on the path (public or partners), I'll reach one broker or another. This is actually a common pattern, BTW.

So what I'm doing here is making path optional (defaulting to / as it's assumed by the URL RFC). In the majority of cases, this path will not be needed but in some cases, it will. And yeah, especially in the case of HTTP and WS it's going to be needed but it's also frequent in AMQP and MQTT brokers.


So yeah, I took the approach to keep the protocol field and convert the url field to a host (hostname + port) one. Another approach is to remove protocol altogether as it's already in the URL field. A matter of preference, I guess.

so basically my question is, do we really need to change url to host and path or, as majority of people in #274 wrote that we basically need to make description and examples better?

We definitely have to improve the examples but this incongruency goes beyond showing examples or improving description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well one thing is "concepts" and one thing is "just a simple association"

When I see

"host": "{org}.mycompany.com",
"path": "/api/v1",
"protocol": "https"

My brains says "REST". Then my brain also reminds me of AsyncAPI 1.0 and baseTopic. And then it tries to map it to concepts 😄 but yeah, enough with my brain 😄

Can we then improve the example and not put https protocol but something that will not cause brains to fart?
For example your amqp example. I guess there are different patterns, as I thought people prefer to split public/private or public/partners by host as then they do different authentication, rate limits and stuff like that. But yeah, it is flexible and people can do it as they wish.

or best would be to have 2 examples, one with path and one without it:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the origin of my question

path ? where is this coming from?

was that you use path but it is not described in the spec in your PR.

also side note: I think it should be pathname as we do not want to allow search (query params) here -> https://url.spec.whatwg.org/#dom-url-pathname

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we then improve the example and not put https protocol but something that will not cause brains to fart?

or best would be to have 2 examples, one with path and one without it:

Absolutely. I'll add two examples.

was that you use path but it is not described in the spec in your PR.

True. My fault. Adding it.

also side note: I think it should be pathname as we do not want to allow search (query params) here -> https://url.spec.whatwg.org/#dom-url-pathname

Good catch. Changing it 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@derberg have a look again, please.

"description": "The production API server.",
"protocol": "https",
"variables": {
"org": {
"default": "demo",
"description": "This value is assigned by the service provider, in this example `mycompany.com`."
}
}
}
}
}
```

```yaml
servers:
production:
host: '{org}.mycompany.com'
path: '/api/v1'
description: The production API server.
protocol: https
variables:
org:
default: demo
description: This value is assigned by the service provider, in this example `mycompany.com`.
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You added here Server Variable Object Example but that describes the whole Server Object, here only the:

        default: demo
        description: This value is assigned by the service provider, in this example `mycompany.com`.

should be written.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case it's justified to have the whole Server Object. Otherwise, there would be no context of where this demo variable is coming from.



#### <a name="defaultContentTypeString"></a>Default Content Type
Expand Down