730 lines
32 KiB
Markdown
730 lines
32 KiB
Markdown
# 5.1. WIP over HTTP
|
|
|
|
WIP over HTTPは、[3. Protocol](3-protocol.md)のlogical data modelをHTTP request / responseとJSONへ対応付ける標準Transport Bindingである。HTTP上の表現は、[5. Transport Bindings](5-transports.md)の共通要件に従って定める。
|
|
|
|
## 目的と範囲
|
|
|
|
HTTPへ対応付けるCore interactionは、次の三つである。
|
|
|
|
- `observe`
|
|
- `fetch_interface`
|
|
- `call_operation`
|
|
|
|
HTTP version、communication scheme、TLS、authentication方式、connection reuse、multiplexing、proxy、gateway、cache、Host内部のframework、backend接続方式は規定しない。これらはHTTP実装とdeploymentが、WIPとは独立して選択する。複数のCore interactionが必要な場合も、それぞれを独立したHTTP request / responseとして交換する。
|
|
|
|
Operationは、WebSocket等のendpointをApplication dataとして返してよい。ただし、そのendpoint上のprotocol、状態、lifecycleは、WIPの規定対象外である。
|
|
|
|
## Endpoint
|
|
|
|
WIP endpointは、一つのWorldspace access surfaceを指すabsolute hierarchical base URLである。URLのpath prefixはdeploymentが任意に選択できる。Clientはorigin直下や`/wip`等の既定prefixを仮定せず、Worldspace pathとの対応も仮定しない。
|
|
|
|
Endpoint URLには、次の条件を適用する。
|
|
|
|
- HTTP実装がrequest先として使用できるabsolute URLである。
|
|
- Authorityとhostを持つ。
|
|
- Queryとfragmentを持たない。
|
|
- Pathが`/`で終わるcanonical formである。
|
|
|
|
利用者から末尾`/`のないURLを受け付ける実装は、routeを解決する前に`/`を追加し、canonical formへ変換する。URL schemeと通信securityはHTTP実装とdeploymentが選択し、このbindingは制約しない。
|
|
|
|
各routeは、endpoint URLをbase URLとして、次のrelative referenceをRFC 3986に従って解決する。すべてのinteractionで`POST`を使用する。
|
|
|
|
| Interaction | Method | Relative reference |
|
|
| --- | --- | --- |
|
|
| `observe` | `POST` | `v1/observe` |
|
|
| `fetch_interface` | `POST` | `v1/fetch_interface` |
|
|
| `call_operation` | `POST` | `v1/call_operation` |
|
|
|
|
`v1`は、WIP over HTTP Bindingのmajor versionを表す。Interactionごとに独立したrouteを設定したり、固定suffixを別名へ置き換えたりしない。
|
|
|
|
例えば、endpointが次のURLである場合、
|
|
|
|
```text
|
|
http://gateway.example/tenants/acme/filesystem/wip/
|
|
```
|
|
|
|
`observe` routeは次のURLになる。
|
|
|
|
```text
|
|
http://gateway.example/tenants/acme/filesystem/wip/v1/observe
|
|
```
|
|
|
|
このpath prefixはHTTP deployment上のroutingであり、Worldspace内のpathではない。Worldspace pathは、request bodyのlogical fieldとして渡す。標準route URLはqueryを持たず、query付きURLや追加path segmentを同じrouteとして扱わない。
|
|
|
|
Clientは、異なるcanonical endpoint間でKnown Space、Object observation、Interface observation、validatorを混在させない。同じendpointでも、認証主体、tenant、capability、その他のsecurity contextによって異なるWorldspaceが見える場合は、異なるeffective Worldspace viewとして分離する。
|
|
|
|
## HTTP request metadata
|
|
|
|
標準routeへのrequestには、次の条件を適用する。
|
|
|
|
- Methodは`POST`。
|
|
- `Content-Type`は`application/json`または`application/json; charset=utf-8`。
|
|
- BodyはUTF-8のJSON text。
|
|
- 標準Clientは`Accept: application/json`を送る。
|
|
- Request URLは標準routeと完全に一致し、queryを持たない。
|
|
|
|
Media typeとparameter名は、HTTPの規則に従ってcase-insensitiveに比較する。`charset`を指定する場合に許可するのは`utf-8`だけである。同じparameterの重複、UTF-8以外のcharset、その他のmedia type parameterは、標準bindingでは使用しない。
|
|
|
|
Hostは、`Accept`がないrequestを受理してよい。`Accept`がある場合はHTTP content negotiationの規則を適用し、`application/json`に対するeffective quality valueが正である場合だけ、JSON responseを返す。
|
|
|
|
すべての実装はHTTP identity content codingを扱える。Requestとresponseのcontent codingはoptionalなHTTP機能であり、このbindingは特定の圧縮方式を必須にしない。Hostが対応しないrequest content codingは、Transport-levelの`415 Unsupported Media Type`として拒否する。Clientが対応しないresponse content codingは、Transport failureとして扱う。
|
|
|
|
## Routeとmetadataのfailure
|
|
|
|
Route、method、content negotiation、Transport authenticationは、logical WIP requestの外側で扱う。次のresponseには、Protocol error envelopeを要求しない。
|
|
|
|
| 条件 | HTTP response |
|
|
| --- | --- |
|
|
| 未知route、query付きroute、追加path segment | `404 Not Found` |
|
|
| 既知routeへの`POST`以外のmethod | `405 Method Not Allowed`と`Allow: POST` |
|
|
| Unsupportedな`Content-Type`またはrequest content coding | `415 Unsupported Media Type` |
|
|
| JSON responseを拒否する`Accept` | `406 Not Acceptable` |
|
|
| Transport authenticationが必要 | `401 Unauthorized`、必要なら`WWW-Authenticate` |
|
|
| Endpoint access surface全体へのaccess拒否 | `403 Forbidden` |
|
|
|
|
Clientは、これらを`InvalidRequest`、`NotFound`、`PermissionDenied`等へ変換しない。
|
|
|
|
一方、標準route、method、media type、authenticationを受理した後に、bodyがmalformed JSONである、logical requestへdecodeできない、required fieldがない、未知fieldがある、またはfield semanticsに違反する場合は、Protocol failureとなる。Hostは`400 Bad Request`と、`invalid_request`のProtocol error envelopeを返す。
|
|
|
|
HTTP server、proxy、gateway、Clientの運用設定によってmessage size、timeout、rate等の上限に達した場合は、Transport failureである。HTTP statusがProtocol error mappingと同じでも、validなProtocol error envelopeを持たないresponseをProtocol failureへ変換しない。
|
|
|
|
## HTTP response
|
|
|
|
各interactionが成功した場合、Hostは`200 OK`を返す。Response bodyには、対応するProtocol responseを直接encodeし、`result`等の共通envelopeで包まない。
|
|
|
|
Protocol failureの場合は非2xx statusを返し、bodyにProtocol error envelopeをencodeする。
|
|
|
|
WIP Hostが生成するbody付きresponseは、`Content-Type: application/json`または`application/json; charset=utf-8`を持つ。Protocol successとProtocol failureのbodyは、いずれもUTF-8 JSON textである。
|
|
|
|
HTTP statusは、大分類とHTTP infrastructureのための補助情報である。Protocol failureの意味を決定するものではなく、Clientはstatus、reason phrase、人間向けmessageから`ProtocolErrorCode`を推測しない。
|
|
|
|
非2xx responseが、正しいContent-TypeとvalidなProtocol error envelopeを持たない場合、ClientはTransport failureとして扱う。Proxyやgatewayが生成したresponseを、Host由来のProtocol failureと誤認しないためである。
|
|
|
|
これに対し、次のresponseは`InvalidResponse`となる。
|
|
|
|
- `200 OK`以外の2xx statusにvalidなsuccess bodyがある。
|
|
- 2xx statusにProtocol error envelopeがある。
|
|
- 非2xx statusにvalidなsuccess bodyがある。
|
|
- Success bodyまたはProtocol error envelopeがschema、request correlation、interactionごとのcode制約に違反する。
|
|
|
|
## JSON共通規則
|
|
|
|
JSON encodingには、次の規則を適用する。
|
|
|
|
- JSON textはUTF-8でencodeする。
|
|
- RecordはJSON object、listはJSON arrayで表す。
|
|
- Field名と列挙stringはcase-sensitiveである。
|
|
- 同じJSON object内のduplicate memberを拒否する。
|
|
- 本章がschemaを定義するobjectでは、許可していないmemberを拒否する。Descriptorの未知formatとTypeExpr `Json`のobjectには、それぞれ後述する例外を適用する。
|
|
- Required fieldは必ず存在する。
|
|
- Protocol structのoptional fieldはmemberの省略で表し、`null`で置き換えない。
|
|
- JSON objectのmember順に意味を持たせない。
|
|
- Protocol listのarray順は保持する。
|
|
- StringへUnicode normalizationを適用しない。
|
|
- JSON syntaxが表現できないNaNと正負Infinityを使用しない。
|
|
|
|
Schema表で`optional`と記していないfieldは、requiredとして扱う。
|
|
|
|
`Vec<u8>`はcanonical base64 stringとしてencodeする。RFC 4648 Section 4のstandard base64 alphabetを使用し、必要な`=` paddingを含める。Whitespace、URL-safe alphabet、padding省略、同じoctet列に対する別表現は受理しない。
|
|
|
|
Path、Interface参照、Object identity、名前、validatorの意味は、fieldの位置とProtocolの型によって決まる。JSON上の表現は次のとおりである。
|
|
|
|
| Logical field | JSON encoding |
|
|
| --- | --- |
|
|
| Path / `entry` | canonical absolute Worldspace pathのstring |
|
|
| Object、Operation、Type、Field、Parameter、Case名 | string |
|
|
| Interface参照 | `InterfaceReference` object |
|
|
| `ref` | string |
|
|
| `format` | string |
|
|
| Object / Interface validator | canonical base64 string |
|
|
|
|
ただし、JSON serialization全体をcanonical化するわけではない。Whitespace、escapeの選択、object member順はcanonical化せず、同じlogical valueがbyte-for-byte同一のJSONになることも要求しない。
|
|
|
|
## Interface Reference
|
|
|
|
`InterfaceReference`は、次のfieldだけを持つexactなJSON objectとしてencodeする。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `scope` | canonical absolute Worldspace pathのstring | required |
|
|
| `name` | 空でないUnicode string | required |
|
|
|
|
```json
|
|
{
|
|
"scope": "/github",
|
|
"name": "issue.read"
|
|
}
|
|
```
|
|
|
|
`Object.interfaces`の各要素、`FetchInterfaceRequest.interface`、`FetchInterfaceResponse.interface`、`InterfaceTarget.reference`で、この形を共通して使用する。Scopeの省略、relative scope、`null`、空name、追加member、旧形式のopaque string、`"/github::issue.read"`等の短縮表記stringは認めない。Requestで違反した場合は`400 Bad Request`と`invalid_request`を返し、responseで違反した場合はClient-localな`InvalidResponse`とする。
|
|
|
|
参照は、JSON decode後の`scope`と`name`の完全一致で比較する。Object member順やJSON escapeの違いは、同一性に影響しない。ScopeへURL encoding / decodingを追加せず、name内の`::`や`#`も通常の文字として保持する。
|
|
|
|
ScopeはWorldspace上のpathである。HTTP endpointのprefixを加えたり、scope用のHTTP routeを生成したりしない。合成によるscope変換は、[ProtocolのWorldspace composition](3-protocol.md#worldspace-composition)に従う。
|
|
|
|
## ObjectとObjectObservation
|
|
|
|
`Object`は、次のfieldを持つJSON objectとしてencodeする。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `description` | string | optional |
|
|
| `interfaces` | `InterfaceReference` objectのarray | required |
|
|
| `ref` | string | optional |
|
|
| `validator` | canonical base64 string | optional |
|
|
|
|
ObjectのJSON表現の例:
|
|
|
|
```json
|
|
{
|
|
"name": "123",
|
|
"description": "First item",
|
|
"interfaces": [
|
|
{ "scope": "/", "name": "item-interface-v1" },
|
|
{ "scope": "/", "name": "item-marker-interface-v1" }
|
|
],
|
|
"ref": "item:123",
|
|
"validator": "aXRlbS12YWxpZGF0b3I="
|
|
}
|
|
```
|
|
|
|
`interfaces`のarray順にはHostの立項順を保持し、`(scope, name)`の完全一致による重複を含めない。各参照のscopeは、観測pathに対してProtocolの祖先制約を満たす。
|
|
|
|
`ObjectObservation`は、Objectとchildrenの観測を次のJSON objectで表す。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `object` | `Object` | required |
|
|
| `children` | `ObjectObservation`のarray | optional |
|
|
|
|
`children`の省略は未観測を表す。空arrayは、観測済みで直接のindexable childが存在しないことを表す。Requested depthより浅いnodeでは`children`を必ず含め、depth境界のnodeでは省略する。
|
|
|
|
Success responseはrequested depthまで完全であり、truncated markerやpartial successを返さない。
|
|
|
|
## Interface Descriptor
|
|
|
|
### Format discriminator
|
|
|
|
標準v1のInterface Descriptor formatは、`wip-interface/1`である。このformatのJSON grammarは、以下の定義に従う。
|
|
|
|
Clientは、Descriptor objectのstring `format`を先に読み、対応しないformatを`UnsupportedDescriptorFormat`として扱える。未知formatでも、DescriptorはJSON objectであり、string `format`を必ず持つ。
|
|
|
|
それ以外のmemberはformat固有であるため、未知formatを`wip-interface/1`のschemaで検証しない。Memberの存在、欠落、型をこのschemaで判定せず、内容をOperationへ使用しない。標準v1 Hostは`wip-interface/1`を返す。
|
|
|
|
### Documentation
|
|
|
|
`Documentation`は、説明を次のJSON objectで表す。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `summary` | string | required |
|
|
| `details` | string | optional |
|
|
|
|
### Descriptor root
|
|
|
|
`InterfaceDescriptor`のrootは、次のJSON objectである。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `format` | string。標準v1では`wip-interface/1` | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `types` | `TypeDeclaration`のarray | required |
|
|
| `operations` | `OperationDeclaration`のarray | required |
|
|
|
|
`types`と`operations`のarrayには、declaration順を保持する。
|
|
|
|
### TypeDeclaration
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `definition` | `TypeExpr` | required |
|
|
|
|
### TypeExpr
|
|
|
|
すべての`TypeExpr`を、string `kind`を持つJSON objectとしてencodeする。`kind`ごとに持つmemberは、次のものに限定する。
|
|
|
|
| TypeExpr | `kind` | その他のmember |
|
|
| --- | --- | --- |
|
|
| Unit | `unit` | なし |
|
|
| Boolean | `boolean` | なし |
|
|
| Integer | `integer` | なし |
|
|
| Number | `number` | なし |
|
|
| String | `string` | なし |
|
|
| Bytes | `bytes` | なし |
|
|
| Json | `json` | なし |
|
|
| Entry | `entry` | なし |
|
|
| Named | `named` | required string `name` |
|
|
| Record | `record` | required `FieldDeclaration` array `fields` |
|
|
| List | `list` | required `TypeExpr` `items` |
|
|
| Enum | `enum` | required `EnumCase` array `cases` |
|
|
| Union | `union` | required `UnionCase` array `cases` |
|
|
|
|
ListのitemsがNamedであるTypeExprの例:
|
|
|
|
```json
|
|
{
|
|
"kind": "list",
|
|
"items": {
|
|
"kind": "named",
|
|
"name": "ItemSummary"
|
|
}
|
|
}
|
|
```
|
|
|
|
Primitive kindのobjectに、別memberを追加してはならない。例えばUnitの表現は、`{"kind":"unit"}`だけである。
|
|
|
|
### FieldDeclaration
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `required` | boolean | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `type` | `TypeExpr` | required |
|
|
|
|
### EnumCase
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
|
|
### UnionCase
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `payload` | `TypeExpr` | optional |
|
|
|
|
`payload`を省略したcaseは、payloadを持たない。
|
|
|
|
### OperationDeclaration
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `parameters` | `ParameterDeclaration`のarray | required |
|
|
| `returns` | `ReturnDeclaration` | required |
|
|
|
|
### ParameterDeclaration
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `name` | string | required |
|
|
| `required` | boolean | required |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `type` | `TypeExpr` | required |
|
|
|
|
### ReturnDeclaration
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `documentation` | `Documentation` | optional |
|
|
| `type` | `TypeExpr` | required |
|
|
|
|
JSON shapeの検証だけでは、Descriptorのvalidityは確認できない。名前一意性、Named参照、cycle、型整合性等も、[3. Protocol](3-protocol.md)に従って検証する。
|
|
|
|
Typesとoperationsを含む、完全なDescriptorの例:
|
|
|
|
```json
|
|
{
|
|
"format": "wip-interface/1",
|
|
"documentation": {
|
|
"summary": "Reads items and their relationships."
|
|
},
|
|
"types": [
|
|
{
|
|
"name": "Relation",
|
|
"definition": {
|
|
"kind": "enum",
|
|
"cases": [
|
|
{ "name": "parent" },
|
|
{ "name": "sibling" }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"name": "RelatedItem",
|
|
"definition": {
|
|
"kind": "union",
|
|
"cases": [
|
|
{
|
|
"name": "found",
|
|
"payload": { "kind": "entry" }
|
|
},
|
|
{ "name": "not_found" }
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"operations": [
|
|
{
|
|
"name": "get_related_item",
|
|
"parameters": [
|
|
{
|
|
"name": "relation",
|
|
"required": true,
|
|
"type": {
|
|
"kind": "named",
|
|
"name": "Relation"
|
|
}
|
|
}
|
|
],
|
|
"returns": {
|
|
"type": {
|
|
"kind": "named",
|
|
"name": "RelatedItem"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Operation Value
|
|
|
|
Operationのargumentsとresultは、選択したInterface Descriptorの`TypeExpr`に従ってJSONへencodeする。Raw `Value` variantを示す共通tagged envelopeは使用しない。
|
|
|
|
| TypeExpr | JSON encoding |
|
|
| --- | --- |
|
|
| Unit | `null` |
|
|
| Boolean | boolean |
|
|
| Integer | 小数部と指数部を持たないJSON number。`-9007199254740991`から`9007199254740991`まで |
|
|
| Number | finiteなJSON number |
|
|
| String | string |
|
|
| Bytes | canonical base64 string |
|
|
| Json | JSONの`null`、boolean、number、string、array、object |
|
|
| Entry | canonical absolute Worldspace pathのstring |
|
|
| Named | 同じDescriptor内の参照先TypeExprと同じencoding |
|
|
| Record | declarationされたfieldをmemberとするobject |
|
|
| List | items TypeExprに従うarray |
|
|
| Enum | 宣言されたcase名のstring |
|
|
| Union | `$case`と、必要なら`value`を持つobject |
|
|
|
|
`Json`内部のnumberにも、相互運用可能なsafe integerまたはfinite binary64という制約を適用する。小数部と指数部を持たずsafe integer範囲にあるJSON numberはlogical `Integer`として、それ以外のfiniteなJSON numberはlogical `Number`としてdecodeする。
|
|
|
|
`Json`内部にはBytesの特別なencodingを適用しない。Base64らしいstringがあっても、Bytesと推測しない。
|
|
|
|
RecordとOperation argumentsでは、`required = false`のfieldやparameterを省略できる。ただし、省略と`null`は異なる。TypeExprがUnit、Json、またはそれらへ解決されるNamedである場合、存在するmemberの`null`はその型のvalueであり、省略を表さない。それ以外の型では`null`を使用してはならない。
|
|
|
|
Record valueには、declarationされていないmemberを含めない。Operation argumentsは、parameter名をmember名とするJSON objectであり、位置引数を使用しない。引数のないOperationには空objectを使用する。
|
|
|
|
Enumはcase名だけをstringで表し、object envelopeは使用しない。
|
|
|
|
Payloadを持つUnionは、`$case`と`value`を持つ次の形で表す。
|
|
|
|
```json
|
|
{
|
|
"$case": "found",
|
|
"value": "/items/123"
|
|
}
|
|
```
|
|
|
|
Payloadを持たないUnionでは、`value`を省略する。
|
|
|
|
```json
|
|
{
|
|
"$case": "not_found"
|
|
}
|
|
```
|
|
|
|
Union objectに含めるmemberは、`$case`と必要な`value`だけである。Payloadありcaseでは`value`がrequiredとなり、payloadなしcaseでは`value`を禁止する。
|
|
|
|
Clientは、Descriptorに従ってvalueをdecodeする。Worldspace entryとして認識するのは、`entry`と宣言された位置のstringだけである。通常のStringやopaqueなJsonに含まれるpathらしいstringから、entryを推測しない。
|
|
|
|
## `observe`
|
|
|
|
### Request
|
|
|
|
`POST v1/observe`のbodyには、次のJSON objectを使用する。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `path` | canonical absolute Worldspace pathのstring | required |
|
|
| `depth` | `0`以上`4294967295`以下のinteger | required |
|
|
|
|
```json
|
|
{
|
|
"path": "/items",
|
|
"depth": 1
|
|
}
|
|
```
|
|
|
|
### Success response
|
|
|
|
Success bodyには、rootの`ObjectObservation`を直接encodeする。
|
|
|
|
```json
|
|
{
|
|
"object": {
|
|
"name": "items",
|
|
"description": "Item collection",
|
|
"interfaces": [{ "scope": "/", "name": "item-collection-interface-v1" }],
|
|
"validator": "cm9vdC12YWxpZGF0b3I="
|
|
},
|
|
"children": [
|
|
{
|
|
"object": {
|
|
"name": "123",
|
|
"description": "First item",
|
|
"interfaces": [{ "scope": "/", "name": "item-interface-v1" }],
|
|
"ref": "item:123",
|
|
"validator": "aXRlbS12YWxpZGF0b3I="
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Responseのpath、name、depth、children completenessは、requestと[3. Protocol](3-protocol.md)に従って検証する。Hostがresource budget内で完全なresponseを構築できない場合は、partial successにせず、`resource_limit_exceeded`を返す。
|
|
|
|
## `fetch_interface`
|
|
|
|
### Request
|
|
|
|
`POST v1/fetch_interface`のbodyには、次のJSON objectを使用する。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `interface` | `InterfaceReference` object | required |
|
|
|
|
```json
|
|
{
|
|
"interface": { "scope": "/", "name": "item-interface-v1" }
|
|
}
|
|
```
|
|
|
|
### Success response
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `interface` | `InterfaceReference` object | required |
|
|
| `scope_ref` | scope Objectの`ref`を表すstring | optional |
|
|
| `descriptor` | Interface Descriptor object | required |
|
|
| `validator` | canonical base64 string | optional |
|
|
|
|
```json
|
|
{
|
|
"interface": { "scope": "/", "name": "item-interface-v1" },
|
|
"scope_ref": "world:root",
|
|
"descriptor": {
|
|
"format": "wip-interface/1",
|
|
"types": [],
|
|
"operations": []
|
|
},
|
|
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
|
|
}
|
|
```
|
|
|
|
Responseの`interface`は、requestと完全一致しなければならない。`scope_ref`、Descriptor、validatorは、一つのInterface observationとして扱う。
|
|
|
|
`scope_ref`はscope Objectの`ref`と同じopaque stringであり、base64化しない。Scope Objectが`ref`を持つ場合は含め、持たない場合は省略する。`null`は使用しない。
|
|
|
|
Scope Objectに`ref`がない場合も、次のresponseはvalidである。
|
|
|
|
```json
|
|
{
|
|
"interface": { "scope": "/", "name": "item-interface-v1" },
|
|
"descriptor": {
|
|
"format": "wip-interface/1",
|
|
"types": [],
|
|
"operations": []
|
|
}
|
|
}
|
|
```
|
|
|
|
`scope_ref`もvalidatorもない観測は許可される。この場合、scopeのidentityは追跡できず、Descriptorは参照の有効期間中immutableとして扱う。
|
|
|
|
## `call_operation`
|
|
|
|
### Request
|
|
|
|
`POST v1/call_operation`のbodyには、次のJSON objectを使用する。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `target` | `Target` object | required |
|
|
| `interface` | `InterfaceTarget` object | required |
|
|
| `operation` | Operation名のstring | required |
|
|
| `arguments` | 選択したOperation declarationに従うobject | required |
|
|
|
|
`Target`は、pathとoptionalなvalidatorを次のfieldで表す。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `path` | canonical absolute Worldspace pathのstring | required |
|
|
| `validator` | canonical base64 string | optional |
|
|
|
|
`InterfaceTarget`は、参照とその観測metadataを次のfieldで表す。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `reference` | `InterfaceReference` object | required |
|
|
| `scope_ref` | 観測したscope Objectの`ref`を表すstring | optional |
|
|
| `validator` | canonical base64 string | optional |
|
|
|
|
```json
|
|
{
|
|
"target": {
|
|
"path": "/items/current",
|
|
"validator": "b2JqZWN0LXZhbGlkYXRvcg=="
|
|
},
|
|
"interface": {
|
|
"reference": { "scope": "/", "name": "item-interface-v1" },
|
|
"scope_ref": "world:root",
|
|
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
|
|
},
|
|
"operation": "get_related_item",
|
|
"arguments": {
|
|
"relation": "sibling"
|
|
}
|
|
}
|
|
```
|
|
|
|
`interface.reference`と`operation`は、別fieldである。表示用の`/::item-interface-v1#get_related_item`を、一つのfieldへencodeしない。`scope_ref`も`InterfaceReference`のmemberや短縮表記の一部にはせず、`InterfaceTarget`の独立したoptional fieldとして送る。
|
|
|
|
Clientは、`fetch_interface`の観測に`scope_ref`があればコピーし、なければ省略する。`null`や非stringを`scope_ref`に指定したrequestは、`invalid_request`となる。
|
|
|
|
Validなstringを指定していても、現在のscope Objectの`ref`と一致しない場合は、Protocolの検証順に従って`interface_mismatch`とする。現在の`ref`が欠落している場合も含む。`scope_ref`を省略した場合はscope identity preconditionを適用せず、省略だけを理由に拒否しない。
|
|
|
|
Hostはまず、Descriptorに依存しない`target`、`interface`、`operation`のshapeを検証する。次に、Protocolのerror precedenceに従って現在のObjectとInterface observationを固定し、そのDescriptorに従って`arguments`をdecodeする。
|
|
|
|
### Success response
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `result` | Operation return TypeExprに従うJSON value | required |
|
|
| `validator` | 実行後のObject validatorを表すcanonical base64 string | optional |
|
|
|
|
```json
|
|
{
|
|
"result": {
|
|
"$case": "found",
|
|
"value": "/items/123"
|
|
},
|
|
"validator": "bmV3LW9iamVjdC12YWxpZGF0b3I="
|
|
}
|
|
```
|
|
|
|
`result`のencodingには、requestで指定し、Hostがprecondition確認時に固定したOperation declarationのreturn TypeExprを使用する。
|
|
|
|
## Validator
|
|
|
|
Object validatorとInterface validatorは、対応する次のJSON body fieldにcanonical base64としてencodeする。
|
|
|
|
- `Object.validator`
|
|
- `Target.validator`
|
|
- `FetchInterfaceResponse.validator`
|
|
- `InterfaceTarget.validator`
|
|
- `CallOperationResponse.validator`
|
|
|
|
WIP validatorを`ETag`、`If-Match`、その他のHTTP headerだけへ移し、body fieldを省略してはならない。
|
|
|
|
Host、gateway、HTTP cacheは、通常のHTTP representation metadataとして`ETag`等を追加してよい。ただし、その値はWIP validatorとは独立している。ClientはHTTP metadataを、Object identity、Interface observation、Operation preconditionとして解釈しない。
|
|
|
|
## Protocol error envelope
|
|
|
|
各interactionのProtocol failureは、次のexactなJSON objectとしてencodeする。
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": "invalid_arguments",
|
|
"message": "Required argument `relation` is missing"
|
|
}
|
|
}
|
|
```
|
|
|
|
Top-level objectに含めるのは`error`だけである。`error` objectも、次のfieldだけを持つ。
|
|
|
|
| Field | JSON type | Presence |
|
|
| --- | --- | --- |
|
|
| `code` | 下表のstableなsnake_case string | required |
|
|
| `message` | boundedな人間向け診断string | required |
|
|
|
|
Clientは`message`を分岐に使用しない。Hostは秘密情報、credential、非公開Object、backend path、内部stack traceをmessageへ含めない。
|
|
|
|
`ProtocolErrorCode`には、次のwire spellingとcanonical HTTP statusを対応付ける。
|
|
|
|
| Protocol error code | Wire spelling | HTTP status |
|
|
| --- | --- | --- |
|
|
| `InvalidRequest` | `invalid_request` | `400 Bad Request` |
|
|
| `NotFound` | `not_found` | `404 Not Found` |
|
|
| `InterfaceNotFound` | `interface_not_found` | `404 Not Found` |
|
|
| `InterfaceMismatch` | `interface_mismatch` | `409 Conflict` |
|
|
| `OperationNotFound` | `operation_not_found` | `404 Not Found` |
|
|
| `InvalidArguments` | `invalid_arguments` | `422 Unprocessable Content` |
|
|
| `ValidatorRequired` | `validator_required` | `428 Precondition Required` |
|
|
| `ValidatorMismatch` | `validator_mismatch` | `412 Precondition Failed` |
|
|
| `InterfaceValidatorRequired` | `interface_validator_required` | `428 Precondition Required` |
|
|
| `InterfaceValidatorMismatch` | `interface_validator_mismatch` | `412 Precondition Failed` |
|
|
| `PermissionDenied` | `permission_denied` | `403 Forbidden` |
|
|
| `ResourceLimitExceeded` | `resource_limit_exceeded` | `422 Unprocessable Content` |
|
|
| `Internal` | `internal` | `500 Internal Server Error` |
|
|
| `OperationOutcomeUnknown` | `operation_outcome_unknown` | `500 Internal Server Error` |
|
|
|
|
`resource_limit_exceeded`は、WIP Protocolが扱うlogical requestまたはresponseの上限超過を表す。Observation completeness、logical nesting、collection件数等が対象であり、HTTP statusには`422 Unprocessable Content`を使用する。HTTP implementationやdeploymentのmessage-size上限超過を、このcodeへ変換しない。
|
|
|
|
Rate limitやdeployment concurrency limitによる`429 Too Many Requests`は、Transport / deployment concernである。ValidなProtocol error envelopeがない限り、`ResourceLimitExceeded`へ変換しない。
|
|
|
|
Hostは、interactionごとに[3. Protocol](3-protocol.md)で許可されたcodeだけを返す。ClientがvalidなProtocol error envelopeを取得した場合、回復actionは`code`に従う。HTTP statusがcanonical mappingと一致しなくても、statusから別codeを推測しない。Status mismatchは、Binding違反として診断してよい。
|
|
|
|
`InvalidResponse`と`UnsupportedDescriptorFormat`はClient-local classificationであり、Hostがerror envelopeで返してはならない。Domain failureもProtocol errorへ変換せず、Operation return typeに従うApplication dataとしてencodeする。
|
|
|
|
## HTTP authentication boundary
|
|
|
|
Authentication方式、credential、mTLS、proxy、gateway等は、HTTP implementationとdeploymentが設定・運用する。このbindingは規定しない。
|
|
|
|
HTTP layerがWIP interactionを開始せずに返す`401 Unauthorized`や`403 Forbidden`は、validなProtocol error envelopeを持たないTransport failureである。Clientはこれらを`PermissionDenied`へ変換しない。
|
|
|
|
WIP interactionを開始した後のObject、Interface、Operation visibilityとauthorizationは、Protocol semanticsに従う。Protocolの`PermissionDenied`は、validなWIP error envelopeを持つ`403 Forbidden`であり、HTTP layerのaccess rejectionとは区別する。
|
|
|
|
## HTTP replay
|
|
|
|
`3xx` response自体は、WIP successやProtocol failureではなく、Transport failureである。Endpoint discovery、redirect、proxy routingの扱いは、HTTP implementationとdeploymentが決定する。
|
|
|
|
ただし、これらの機構によって、一つのlogical `call_operation` requestを複数回dispatchしてはならない。Dispatch後にredirect responseを受け取った場合も、methodとbodyを維持して別endpointへ自動再送しない。
|
|
|
|
## Dispatchとretry
|
|
|
|
Failureをnot dispatchedとして扱えるのは、requestがHostへ送信されていないとTransport実装が証明できる場合である。送信開始後にresponseを取得できない場合、ClientはHostがrequestを受理した可能性を否定しない。
|
|
|
|
`observe`と`fetch_interface`の再送とtimeout・retry・cancellation policyは、ClientとHTTP実装が決定する。Response ownershipとProtocol上のcache semanticsは、[4. Client](4-client.md)に従う。
|
|
|
|
`call_operation`には、次の規則を適用する。
|
|
|
|
- Redirect、connection retry、HTTP stackのautomatic replay、proxy retryによって再送しない。
|
|
- `Retry-After`またはHTTP statusだけを理由に再送しない。
|
|
- Response不達またはlocal cancellationを、Operationが未実行またはrollback済みである証拠として扱わない。
|
|
- `internal`または`operation_outcome_unknown`を受信しても自動再実行しない。
|
|
- 同じOperationを利用者が改めて実行する場合は、Protocolの回復規則に従って必要なObjectまたはInterfaceを再観測する。
|
|
|
|
HTTP implementationとdeploymentは、失敗した`POST v1/call_operation`を透過的にreplayしない。
|
|
|
|
## HTTP facilitiesとの境界
|
|
|
|
HTTP cache、proxy、gateway、compression、connection管理、TLS、message size、timeout、concurrency、rate limit等の設定と運用は、このbindingの規定対象外である。
|
|
|
|
HTTP cache metadataは、WIP ClientのKnown Space、Interface cache、Object validator、Interface validatorとは別の機構である。`ETag`、`If-Match`、Age、Last-Modified等を、WIP observationやvalidatorとして解釈しない。それ以外のHTTP cache policyは、HTTP implementationとdeploymentが決定する。
|
|
|
|
HTTP implementationやdeploymentの都合でrequestやresponseを交換できない場合、ClientはTransport failureとして扱う。WIPはこれらの運用設定を規定せず、そのfailureを`resource_limit_exceeded`その他のProtocol errorへ包み直さない。
|
|
|
|
## 非目標
|
|
|
|
このbindingの定義には、次のものを含めない。
|
|
|
|
- Host内部のAPI、database、filesystem、queueとの接続方法。
|
|
- Endpoint discovery service。
|
|
- 固定のauthentication scheme。
|
|
- HTTP cacheを使ったWorldspace同期。
|
|
- Operation idempotency keyまたはexactly-once execution。
|
|
- Operation cancellation protocol。
|
|
- Streaming、subscription、server push、WebSocket binding。
|
|
- 複数のCore interactionを一つのWIP requestへまとめる共通envelope。
|
|
- Domain failureの共通HTTP mapping。
|