Skip to content

Commit

Permalink
Add support for URI templates (#3932)
Browse files Browse the repository at this point in the history
fix #3736

---------

Co-authored-by: Christopher Radek <[email protected]>
  • Loading branch information
timotheeguerin and chrisradek authored Aug 6, 2024
1 parent 8a3e941 commit e492ff7
Show file tree
Hide file tree
Showing 32 changed files with 1,028 additions and 268 deletions.
12 changes: 12 additions & 0 deletions .chronus/changes/uri-templates-2024-6-24-20-7-39.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/http"
---

`@route` can now take a uri template as defined by [RFC-6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3)

```tsp
@route("files{+path}") download(path: string): void;
```
9 changes: 9 additions & 0 deletions .chronus/changes/uri-templates-2024-6-24-21-37-52.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/openapi3"
- "@typespec/rest"
---

Add support for URI templates in routes
7 changes: 7 additions & 0 deletions .chronus/changes/uri-templates-2024-6-25-9-3-39-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: deprecation
packages:
- "@typespec/http"
---

API deprecation: `HttpOperation#pathSegments` is deprecated. Use `HttpOperation#uriTemplate` instead.
13 changes: 13 additions & 0 deletions .chronus/changes/uri-templates-2024-6-25-9-3-39.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
changeKind: deprecation
packages:
- "@typespec/http"
---

Deprecated `@query({format: })` option. Use `@query(#{explode: true})` instead of `form` or `multi` format. Previously `csv`/`simple` is the default now.
Decorator is also expecting an object value now instead of a model. A deprecation warning with a codefix will help migrating.

```diff
- @query({format: "form"}) select: string[];
+ @query(#{explode: true}) select: string[];
```
8 changes: 8 additions & 0 deletions .chronus/changes/uri-templates-2024-7-6-16-39-59.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/compiler"
---

Add `ArrayEncoding` enum to define simple serialization of arrays
24 changes: 20 additions & 4 deletions docs/libraries/http/reference/data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,21 @@ model TypeSpec.Http.PasswordFlow
| refreshUrl? | `string` | the refresh URL |
| scopes? | `string[]` | list of scopes for the credential |

### `PathOptions` {#TypeSpec.Http.PathOptions}

```typespec
model TypeSpec.Http.PathOptions
```

#### Properties

| Name | Type | Description |
| -------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name? | `string` | Name of the parameter in the uri template. |
| explode? | `boolean` | When interpolating this parameter in the case of array or object expand each value using the given style.<br />Equivalent of adding `*` in the path parameter as per [RFC-6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3) |
| style? | `"simple" \| "label" \| "matrix" \| "fragment" \| "path"` | Different interpolating styles for the path parameter.<br />- `simple`: No special encoding.<br />- `label`: Using `.` separator.<br />- `matrix`: `;` as separator.<br />- `fragment`: `#` as separator.<br />- `path`: `/` as separator. |
| allowReserved? | `boolean` | When interpolating this parameter do not encode reserved characters.<br />Equivalent of adding `+` in the path parameter as per [RFC-6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3) |

### `PlainData` {#TypeSpec.Http.PlainData}

Produces a new model with the same properties as T, but with `@query`,
Expand Down Expand Up @@ -495,10 +510,11 @@ model TypeSpec.Http.QueryOptions

#### Properties

| Name | Type | Description |
| ------- | --------------------------------------------------------------------- | --------------------------------------------------------- |
| name? | `string` | Name of the query when included in the url. |
| format? | `"multi" \| "csv" \| "ssv" \| "tsv" \| "simple" \| "form" \| "pipes"` | Determines the format of the array if type array is used. |
| Name | Type | Description |
| -------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| name? | `string` | Name of the query when included in the url. |
| explode? | `boolean` | If true send each value in the array/object as a separate query parameter.<br />Equivalent of adding `*` in the path parameter as per [RFC-6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3)<br /><br />\| Style \| Explode \| Uri Template \| Primitive value id = 5 \| Array id = [3, 4, 5] \| Object id = {"role": "admin", "firstName": "Alex"} \|<br />\| ------ \| ------- \| -------------- \| ---------------------- \| ----------------------- \| -------------------------------------------------- \|<br />\| simple \| false \| `/users{?id}` \| `/users?id=5` \| `/users?id=3,4,5` \| `/users?id=role,admin,firstName,Alex` \|<br />\| simple \| true \| `/users{?id*}` \| `/users?id=5` \| `/users?id=3&id=4&id=5` \| `/users?role=admin&firstName=Alex` \| |
| format? | `"multi" \| "csv" \| "ssv" \| "tsv" \| "simple" \| "form" \| "pipes"` | Determines the format of the array if type array is used.<br />**DEPRECATED**: use explode: true instead of `multi` or `@encode` |

### `Response` {#TypeSpec.Http.Response}

Expand Down
56 changes: 30 additions & 26 deletions docs/libraries/http/reference/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ None
Explicitly specify that this property is to be interpolated as a path parameter.

```typespec
@TypeSpec.Http.path(paramName?: valueof string)
@TypeSpec.Http.path(paramNameOrOptions?: valueof string | TypeSpec.Http.PathOptions)
```

#### Target
Expand All @@ -287,9 +287,9 @@ Explicitly specify that this property is to be interpolated as a path parameter.

#### Parameters

| Name | Type | Description |
| --------- | ---------------- | --------------------------------------------------- |
| paramName | `valueof string` | Optional name of the parameter in the url template. |
| Name | Type | Description |
| ------------------ | --------------------------------------------- | -------------------------------------------------------------- |
| paramNameOrOptions | `valueof string \| TypeSpec.Http.PathOptions` | Optional name of the parameter in the uri template or options. |

#### Examples

Expand Down Expand Up @@ -347,7 +347,7 @@ None
Specify this property is to be sent as a query parameter.

```typespec
@TypeSpec.Http.query(queryNameOrOptions?: string | TypeSpec.Http.QueryOptions)
@TypeSpec.Http.query(queryNameOrOptions?: valueof string | TypeSpec.Http.QueryOptions)
```

#### Target
Expand All @@ -356,30 +356,20 @@ Specify this property is to be sent as a query parameter.

#### Parameters

| Name | Type | Description |
| ------------------ | -------------------------------------- | ------------------------------------------------------------------------------- |
| queryNameOrOptions | `string \| TypeSpec.Http.QueryOptions` | Optional name of the query when included in the url or query parameter options. |
| Name | Type | Description |
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------- |
| queryNameOrOptions | `valueof string \| TypeSpec.Http.QueryOptions` | Optional name of the query when included in the url or query parameter options. |

#### Examples

```typespec
op read(@query select: string, @query("order-by") orderBy: string): void;
op list(
@query({
name: "id",
format: "multi",
})
ids: string[],
): void;
op list(@query(#{ name: "id", explode: true }) ids: string[]): void;
```

### `@route` {#@TypeSpec.Http.route}

Defines the relative route URI for the target operation

The first argument should be a URI fragment that may contain one or more path parameter fields.
If the namespace or interface that contains the operation is also marked with a `@route` decorator,
it will be used as a prefix to the route URI of the operation.
Defines the relative route URI template for the target operation as defined by [RFC 6570](https://datatracker.ietf.org/doc/html/rfc6570#section-3.2.3)

`@route` can only be applied to operations, namespaces, and interfaces.

Expand All @@ -393,16 +383,30 @@ it will be used as a prefix to the route URI of the operation.

#### Parameters

| Name | Type | Description |
| ------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| path | `valueof string` | Relative route path. Cannot include query parameters. |
| options | `{...}` | Set of parameters used to configure the route. Supports `{shared: true}` which indicates that the route may be shared by several operations. |
| Name | Type | Description |
| ------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| path | `valueof string` | |
| options | `{...}` | _DEPRECATED_ Set of parameters used to configure the route. Supports `{shared: true}` which indicates that the route may be shared by several operations. |

#### Examples

##### Simple path parameter

```typespec
@route("/widgets")
op getWidget(@path id: string): Widget;
@route("/widgets/{id}") op getWidget(@path id: string): Widget;
```

##### Reserved characters

```typespec
@route("/files{+path}") op getFile(@path path: string): bytes;
```

##### Query parameter

```typespec
@route("/files") op list(select?: string, filter?: string): Files[];
@route("/files{?select,filter}") op listFullUriTemplate(select?: string, filter?: string): Files[];
```

### `@server` {#@TypeSpec.Http.server}
Expand Down
1 change: 1 addition & 0 deletions docs/libraries/http/reference/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ npm install --save-peer @typespec/http
- [`OkResponse`](./data-types.md#TypeSpec.Http.OkResponse)
- [`OpenIdConnectAuth`](./data-types.md#TypeSpec.Http.OpenIdConnectAuth)
- [`PasswordFlow`](./data-types.md#TypeSpec.Http.PasswordFlow)
- [`PathOptions`](./data-types.md#TypeSpec.Http.PathOptions)
- [`PlainData`](./data-types.md#TypeSpec.Http.PlainData)
- [`QueryOptions`](./data-types.md#TypeSpec.Http.QueryOptions)
- [`Response`](./data-types.md#TypeSpec.Http.Response)
Expand Down
13 changes: 13 additions & 0 deletions docs/standard-library/built-in-data-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ model UpdateableProperties<Source>
#### Properties
None

### `ArrayEncoding` {#ArrayEncoding}

Encoding for serializing arrays
```typespec
enum ArrayEncoding
```

| Name | Value | Description |
|------|-------|-------------|
| pipeDelimited | | Each values of the array is separated by a \| |
| spaceDelimited | | Each values of the array is separated by a <space> |


### `BytesKnownEncoding` {#BytesKnownEncoding}

Known encoding to use on bytes
Expand Down
11 changes: 11 additions & 0 deletions packages/compiler/lib/std/decorators.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,17 @@ enum BytesKnownEncoding {
base64url: "base64url",
}

/**
* Encoding for serializing arrays
*/
enum ArrayEncoding {
/** Each values of the array is separated by a | */
pipeDelimited,

/** Each values of the array is separated by a <space> */
spaceDelimited,
}

/**
* Specify how to encode the target type.
* @param encodingOrEncodeAs Known name of an encoding or a scalar type to encode as(Only for numeric types to encode as string).
Expand Down
Loading

0 comments on commit e492ff7

Please sign in to comment.