Skip to content

Commit

Permalink
Initial HTTP API (#2)
Browse files Browse the repository at this point in the history
This is a first take at specifying the Nexus RPC HTTP protocol, changes to be expected.
  • Loading branch information
bergundy authored Sep 20, 2023
1 parent c32a539 commit 9eee750
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Continuous Integration

on: # rebuild any PRs and main branch changes
pull_request:
push:
branches:
- main
- "releases/*"

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dprint/[email protected]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Temporal Technologies Inc. All Rights Reserved

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Nexus API

Nexus RPC HTTP Specification.

## Spec Location

The specification is edited in the [SPEC.md](./SPEC.md) markdown file.

## Contributing to this repo

### Prerequisites

- [dprint](https://dprint.dev/install/)

### Check formatting

```shell
dprint check
```

### Format markdown

```shell
dprint fmt
```
275 changes: 275 additions & 0 deletions SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
# Nexus RPC HTTP Specification

## Overview

The Nexus protocol, as specified below, is a synchronous RPC protocol. Arbitrary length operations are modelled on top
of a set of pre-defined synchronous RPCs.

A Nexus **caller** calls a **handler**. The handler may respond inline or return a reference for a future, asynchronous
operation. The caller can cancel an asynchronous operation, check for its outcome, or fetch its current state. The caller
can also specify a callback URL, which the handler uses to asynchronously deliver the result of an operation when it
is ready.

## Operation Addressability

An operation is addressed using three components:

- The containing service, a URL prefix (e.g. `http://api.mycompany.com/v1/myservice/`)
- [Operation Name](#operation-name)
- [Operation ID](#operation-id)

Both the name and ID MUST not be empty and may contain any arbitrary character sequence as long as they're encoded into
the URL.

## Schema Definitions

### Failure

The `Failure` object represents protocol level failures returned in non successful HTTP responses as well as `failed` or
`canceled` operation results. The object MUST adhere to the following JSON schema:

```yaml
type: object
properties:
message:
type: string
description: A simple text message.

metadata:
type: object
additionalProperties:
type: string
description: |
A key-value mapping for additional context. Useful for decoding the 'details' field, if needed.
details:
type: any
properties:
description: |
Additional structured data.
```
### OperationInfo
The `OperationInfo` object MUST adhere to the given schema:

```yaml
type: object
properties:
id:
type: string
description: |
An identifier for referencing this operation.
state:
enum:
- succeeded
- failed
- canceled
- running
description: |
Describes the current state of an operation.
```

## Endpoint Descriptions

### Start Operation

Start an arbitrary length operation.
The response of the operation may be delivered synchronously (inline), or asynchronously, via a provided callback or the
[Get Operation Result](#get-operation-result) endpoint.

**Path**: `/{operation}`

**Method**: `POST`

#### Query Parameters

- `callback`: Optional. If the operation is asynchronous, the handler should invoke this URL once the operation's
result is available.

#### Request Body

The body may contain arbitrary data. Headers should specify content type and encoding.

#### Response Codes

- `200 OK`: Operation completed successfully.

**Headers**:

- `Nexus-Operation-State: succeeded`

**Body**: Arbitrary data conveying the operation's result. Headers should specify content type and encoding.

- `201 Created`: Operation was started and will complete asynchronously.

**Headers**:

- `Content-Type: application/json`

**Body**: A JSON serialized [`OperationInfo`](#operationinfo) object.

- `424 Failed Dependency`: Operation completed as `failed` or `canceled`.

**Headers**:

- `Content-Type: application/json`
- `Nexus-Operation-State: failed | canceled`

**Body**: A JSON serialized [`Failure`](#failure) object.

- `409 Conflict`: This operation was already started with a different request ID.

**Headers**:

- `Content-Type: application/json`

**Body**: A JSON serialized [`Failure`](#failure) object.

### Cancel Operation

Request to cancel an operation.
The operation may later complete as canceled or any other outcome.
Handlers should ignore multiple cancelations of the same operation and return successfully if cancelation was already
requested.

**Path**: `/{operation}/{operation_id}/cancel`

**Method**: `POST`

#### Response Codes

- `202 Accepted`: Cancelation request accepted.

**Body**: Empty.

- `404 Not Found`: Operation ID not recognized or references deleted.

**Headers**:

- `Content-Type: application/json`

**Body**: A JSON serialized [`Failure`](#failure) object.

### Get Operation Result

Retrieve operation result.

**Path**: `/{operation}/{operation_id}/result`

**Method**: `GET`

#### Query Parameters

- `wait`: Optional. Duration indicating the waiting period for a result, defaulting to no wait.
If by the end of the wait period the operation is still running, the request should resolve with a 412 status code
(see below).

Format of this parameter is number + unit, where unit can be `ms` for milliseconds, `s` for seconds, and `m` for
minutes. Examples:

- `100ms`
- `1m`
- `5s`

#### Response Codes

- `200 OK`: Operation completed successfully.

**Headers**:

- `Nexus-Operation-State: succeeded`

**Body**: Arbitrary data conveying the operation's result. Headers should specify content type and encoding.

- `408 Request Timeout`: The server gave up waiting for operation completion. The request may be retried by the caller.

**Body**: Empty.

- `412 Precondition Failed`: Operation still running.

When waiting for completion, the caller may re-issue this request to start a new long poll.

**Body**: Empty.

- `424 Failed Dependency`: Operation completed as `failed` or `canceled`.

**Headers**:

- `Content-Type: application/json`
- `Nexus-Operation-State: failed | canceled`

**Body**: A JSON serialized [`Failure`](#failure) object.

- `404 Not Found`: Operation ID not recognized or references deleted.

**Headers**:

- `Content-Type: application/json`

**Body**: A JSON serialized [`Failure`](#failure) object.

### Get Operation Info

Retrieve operation details.

**Path**: `/{operation}/{operation_id}`

**Method**: `GET`

#### Response Codes

- `200 OK`: Successfully retrieved info.

**Headers**:

- `Content-Type: application/json`

**Body**:

A JSON serialized [`OperationInfo`](#operationinfo) object.

- `404 Not Found`: Operation ID not recognized or references deleted.

**Headers**:

- `Content-Type: application/json`

**Body**: A JSON serialized [`Failure`](#failure) object.

## General Information on HTTP Response Codes

The Nexus protocol follows standard HTTP practices, response codes not specified here should be interpreted according to
the HTTP specification.

## Callback URLs

Any HTTP URL can be used to deliver operation completions.

Callers should ensure URLs contain sufficient information to correlate completions with initiators.

For invoking a callback URL:

- Issue a POST request to the caller-provided URL.
- Include the `Nexus-Operation-State` header.
- If state is `succeeded`, deliver non-empty results in the body with corresponding `Content-*` headers.
- If state is `failed` or `canceled`, content type should be `application/json` and the body must have a serialized
[`Failure`](#failure) object.
- Upon successful completion delivery, the handler should reply with a `200 OK` status and an empty body.

### Security

There's no enforced security for callback URLs at this time. However, some specific Nexus server implementations may
deliver additional details as headers or have other security requirements of the callback endpoint.
When starting an operation, callers may embed a signed token into the URL, which can be verified upon delivery of
completion.

[rfc3986-section-2.3]: https://datatracker.ietf.org/doc/html/rfc3986#section-2.3

## Q/A

1. What potential security concerns should be taken into consideration while implementing this protocol?

Security is not part of this specification, but as this is a thin layer on top of HTTP, standard practices should be
used to secure these APIs. For securing callback URLs, see [Callback URLs > Security](#security).
6 changes: 6 additions & 0 deletions dprint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"markdown": {},
"includes": ["*.md"],
"excludes": [],
"plugins": ["https://plugins.dprint.dev/markdown-0.15.3.wasm"]
}

0 comments on commit 9eee750

Please sign in to comment.