Skip to content

Commit

Permalink
cleaning up http spec (#370)
Browse files Browse the repository at this point in the history
* housekeeping

* more examples

* removed 500 as a required error response

* change example tbdex message protocol to 2.0. update tbdex protocol spec mermaid diagram

* Apply suggestions from code review

Co-authored-by: Angie Jones <jones.angie@gmail.com>

* add wording around query param support being optional

* add wording around service endpoint being a base URL

---------

Co-authored-by: Angie Jones <jones.angie@gmail.com>
  • Loading branch information
Jiyoon Koo and angiejones authored Aug 15, 2024
1 parent c645cc3 commit a15e1be
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 67 deletions.
131 changes: 68 additions & 63 deletions specs/http-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Version: Draft
- [Error response structure](#error-response-structure)
- [ErrorDetail structure](#errordetail-structure)
- [Example](#example-1)
- [Exceptions](#exceptions)
- [Query Params](#query-params)
- [Pagination](#pagination)
- [Example](#example-2)
Expand All @@ -39,8 +38,6 @@ Version: Draft
- [Create Exchange](#create-exchange)
- [Description](#description-1)
- [Endpoint](#endpoint-1)
- [Authentication](#authentication-1)
- [Authorization](#authorization)
- [Protected](#protected-1)
- [Request Body](#request-body)
- [`CreateExchangeRequest`](#createexchangerequest)
Expand Down Expand Up @@ -73,25 +70,30 @@ Version: Draft
# Discoverability
PFIs can become publicly discoverable by advertising their API endpoint as a [Service](https://www.w3.org/TR/did-core/#services) within their DID Document. In order to increase the likelihood of being discovered The `service` entry **SHOULD** include the following properties:

| Property | Value |
| ----------------- | ------------------------------------------------------------------------------------------- |
| `id` | see [DID-CORE spec](https://www.w3.org/TR/did-core/#services) |
| `type` | `PFI` |
| `serviceEndpoint` | PFI's publicly addressable API endpoint or DID which has PFIs publicly addressable endpoint |
If the serviceEndpoint is itself a DID, this DID should resolve to a document and then its serviceEndpoints can be examined for the `PFI` type entry. The ID can be chosen at the discretion of the PFI, but the service entry should be of type `PFI`.
| Property | Value |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | see [DID-CORE spec](https://www.w3.org/TR/did-core/#services) |
| `type` | `PFI` |
| `serviceEndpoint` | PFI's publicly addressable API endpoint, the [base URL](https://swagger.io/docs/specification/api-host-and-base-path/) with which tbDEX HTTP requests can be made. |


## Example
```json
{
"id": "did:example:pfi",
"service": [{
"id":"my-pfi",
"id":"#my-pfi",
"type": "PFI",
"serviceEndpoint": "https://pfi.organization.com"
}]
}
```

This example illustrates that:
* The ID can be chosen at the discretion of the PFI, but the service entry should be of type `PFI`.
* The `serviceEndpoint` of the PFI `https://pfi.organization.com` is the PFI's base URL.
* The PFI's base URL is combined with relative paths listed below (i.e. `POST /exchanges`) by the client to create an tbDEX HTTP request to the PFI.

> [!NOTE]
>
> _Decentralized_ discoverability is dependent upon whether the underlying [verifiable registry](https://www.w3.org/TR/did-core/#dfn-verifiable-data-registry) of the selected [DID Method](https://www.w3.org/TR/did-core/#methods) is crawlable
Expand Down Expand Up @@ -127,31 +129,16 @@ If the serviceEndpoint is itself a DID, this DID should resolve to a document an
}
```

# Exceptions
Custom exceptions are thrown in many scenarios as a way to provide more narrow and detailed information when the client encounters an error.

| Exception | Description | Typescript | Kotlin | Rust | Swift |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------- | ------ | ---- | ----- |
| `RequestError` | General error thrown when making HTTP requests. |||||
| `ResponseError` | General error thrown when getting HTTP responses. |||||
| `RequestTokenError` | General error thrown for request token related issues. |||||
| `RequestTokenSigningError` | Type of `RequestTokenError`. Thrown when a request token cannot be signed. |||||
| `RequestTokenVerificationError` | Type of `RequestTokenError`. Thrown when a request token cannot be verified. |||||
| `RequestTokenMissingClaimsError` | Type of `RequestTokenError`. Thrown when a request token is missing required claims. |||||
| `RequestTokenAudienceMismatchError` | Type of `RequestTokenError`. Thrown when a request token aud does not match the PFI did for which its intended. |||||
| `ValidationError` | General error thrown when validating data. |||||
| `InvalidDidError` | Type of `ValidationError`. Thrown when a DID is invalid. |||||
| `MissingServiceEndpointError` | Type of `ValidationError`. Thrown when a PFI's service endpoint can't be found. |||||


# Query Params
Query parameters, also known as query strings, are a way to send additional information to the server as part of a URL. They allow clients to provide specific input or customize the server's response. Query parameters typically follow the main URL and start with a `?` character. They consist of key-value pairs, and multiple pairs can be separated by `&` characters

Query params are supported by many of the `GET /${resource}` endpoints in the following ways

* Simple Example: `?simple=field`
* Simple Example: `?field=simpleValue`
* Same Field; Multiple Values: `field=value&field=anotherValue`

Query Param support is **optional** for all `GET` endpoints that return a list that can be filtered by parameters.

## Pagination
Pagination is supported using the following query params:

Expand All @@ -163,17 +150,42 @@ Pagination is supported using the following query params:
### Example
`/?page[offset]=0&page[limit]=10`

Pagination support is **optional** for all `GET` endpoints that return a list.

---

# Idempotency
The IDs of individual tbDEX messages are used as idempotency keys
The IDs of individual tbDEX messages are used as idempotency keys. For example, in a tbDEX Order message:

```json
{
"metadata": {
"from": "did:key:z6MkvUm6mZxpDsqvyPnpkeWS4fmXD2jJA3TDKq4fDkmR5BD7",
"to": "did:ex:pfi",
"exchangeId": "rfq_01ha83pkgnfxfv41gpa44ckkpz",
"kind": "order",
"id": "order_01ha83pkgsfk6t1kxg7q42s48j",
"createdAt": "2023-09-13T20:28:40.345Z",
"protocol": "2.0"
},
"data": {},
"signature": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3ZVbTZtWnhwRHNxdnlQbnBrZVdTNGZtWEQyakpBM1RES3E0ZkRrbVI1QkQ3I3o2TWt2VW02bVp4cERzcXZ5UG5wa2VXUzRmbVhEMmpKQTNUREtxNGZEa21SNUJENyJ9..tWyGAiuUXFuVvq318Kdz-EJJgCPCWEMO9xVMZD9amjdwPS0p12fkaLwu1PSLxHoXPKSyIbPQnGGZayI_v7tPCA"
}
```

The `ID` here that serves as idempotency key is `order_01ha83pkgsfk6t1kxg7q42s48j`. Each tbDEX message's idempotency key can be accessed via `message.metadata.id` like so:

```kotlin
val order = Order.create(...)
val orderId = order.metadata.id
```

---

# Callbacks
Callbacks are implemented via the `replyTo` property on the [request to create an exchange](#create-exchange).
Callbacks are implemented via the `replyTo` property on the [request to create an exchange](#create-exchange).

`replyTo` is a fully qualified URI which could either be a DID or just a URL.
`replyTo` is a fully qualified URI which could either be a DID or a URL.

If `replyTo` is present, a PFI will send any/all new messages for a given exchange to the supplied URI. This makes the URI scoped to each exchange, allowing the caller to specify a different URI per exchange if they so wish.

Expand Down Expand Up @@ -269,12 +281,6 @@ Submits an RFQ (Request For Quote). Alice is asking the PFI to provide a Quote s
### Endpoint
`POST /exchanges`

### Authentication
Refer to [Signature Verification Section]() of the tbDEX spec

### Authorization
No Authorization required to create an exchange

### Protected
False

Expand All @@ -283,7 +289,7 @@ False
#### `CreateExchangeRequest`
| field | data type | required | description |
| --------- | --------- | -------- | ---------------------------------------------------------------------------- |
| `message` | object | Y | The request for quote |
| `message` | object | Y | The request for quote (RFQ) tbDEX message |
| `replyTo` | string | N | A string containing a valid URI where new messages from the PFI will be sent |

> [!IMPORTANT]
Expand All @@ -300,7 +306,7 @@ False
"id": "rfq_01ha835rhefwmagsknrrhvaa0k",
"exchangeId": "rfq_01ha835rhefwmagsknrrhvaa0k",
"createdAt": "2023-09-13T20:19:28.430Z",
"protocol": "1.0"
"protocol": "2.0"
},
"data": {
"offeringId": "abcd123",
Expand Down Expand Up @@ -344,8 +350,7 @@ False

### Request Body
> [!IMPORTANT]
> See Order structure [here](../protocol/README.md#order)
> See Cancel structure [here](../protocol/README.md#cancel)
> See Order structure [here](../protocol/README.md#order). See Cancel structure [here](../protocol/README.md#cancel)
```javascript
{
Expand All @@ -359,6 +364,7 @@ False
| `202: Accepted` | N/A |
| `400: Bad Request` | `{ errors: Error[] }` |


### Errors
| Status | Description |
| ------ | --------------------------- |
Expand All @@ -377,17 +383,16 @@ Retrieves all messages associated to a specific exchange
`GET /exchanges/:exchange_id`

### Protected
True

True. See [Authentication](#authentication) section for more details.

### Response

| Status | Body |
| ------------------ | -------------------------- |
| `200: OK` | `{ data: TbdexMessage[] }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |
| `403: Forbidden` | N/A |
| Status | Body |
| ------------------- | -------------------------- |
| `200: OK` | `{ data: TbdexMessage[] }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `401: Unauthorized` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |

---

Expand All @@ -400,15 +405,15 @@ Returns a list of exchange IDs
`GET /exchanges`

### Protected
True
True. See [Authentication](#authentication) section for more details.

### Response
| Status | Body |
| ------------------ | ------------------------ |
| `200: OK.` | `{ data: [id, id, id] }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |
| `403: Forbidden` | N/A |
| Status | Body |
| ------------------- | ---------------------------------------------- |
| `200: OK` | List of exchangeIds, i.e. `{ data: string[] }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `401: Unauthorized` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |

---

Expand All @@ -419,18 +424,18 @@ This endpoint is *OPTIONAL*. It is only relevant for PFIs which expose a stored
Returns an array of balance resources for each currency held by the caller.

### Protected
True
True. See [Authentication](#authentication) section for more details.

### Endpoint
`GET /balances`

### Response
| Status | Body |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200: OK. ` | `{ data: Balance[] }` See [Balance spec](https://github.com/TBD54566975/tbdex/blob/main/specs/protocol/README.md#balance) for the full schema of a Balance resource |
| `400: Bad Request` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |
| `403: Forbidden` | N/A |
| Status | Body |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `200: OK` | `{ data: Balance[] }` See [Balance structure](https://github.com/TBD54566975/tbdex/blob/main/specs/protocol/README.md#balance) |
| `400: Bad Request` | `{ errors: Error[] }` |
| `401: Unauthorized` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |

# References
* JSON:API spec: https://jsonapi.org/format/
10 changes: 6 additions & 4 deletions specs/protocol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Version: Draft
- [Example Order](#example-order)
- [`OrderInstructions`](#orderinstructions)
- [`PaymentInstruction`](#paymentinstruction)
- [Example Quote](#example-quote-1)
- [Example OrderInstructions](#example-orderinstructions)
- [`OrderStatus`](#orderstatus)
- [`Status`](#status)
- [`Close`](#close)
Expand Down Expand Up @@ -600,8 +600,8 @@ This table enumerates the structure of `PrivateData`
### `OrderInstructions`
> PFI -> Alice: "Here's how to pay us, and how to let us pay you."
| field | data type | required | description |
| -------- | ------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| field | data type | required | description |
| -------- | ------------------------------------------- | -------- | ----------------------------------------------------------------------------- |
| `payin` | [`PaymentInstruction`](#PaymentInstruction) | Y | Object that describes how to pay the PFI (e.g. BTC address, payment link) |
| `payout` | [`PaymentInstruction`](#PaymentInstruction) | Y | Object that describes how be paid by the PFI (e.g. BTC address, payment link) |

Expand Down Expand Up @@ -838,9 +838,11 @@ sequenceDiagram
PFI1->>Alice: Offering
PFI2->>Alice: Offering
PFIn->>Alice: Offering
Alice->>PFI1: RequestForQuote (RFQ)
Alice->>PFI1: RFQ (Request For Quote)
PFI1->>Alice: Quote
Alice->>PFI1: Order
PFI1->>Alice: OrderInstructions
Alice->>PFI1: Alice completes payin per OrderInstructions
PFI1->>Alice: OrderStatus
PFI1->>Alice: OrderStatus
PFI1->>Alice: OrderStatus
Expand Down

0 comments on commit a15e1be

Please sign in to comment.