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: asyncapi fixes #14

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/publish-packages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Publish NPM Packages

on:
workflow_dispatch: # Only allow manual trigger

jobs:
publish:
runs-on: ubuntu-latest

strategy:
matrix:
package-dir: ['dist/asyncapi', 'dist/openapi']

steps:
- name: Checkout repository
uses: actions/checkout@v3

- uses: actions/setup-node@v4
with:
node-version: 18
registry-url: https://registry.npmjs.org/

- name: Install dependencies for the sub-package
working-directory: ${{ matrix.package-dir }}
run: npm ci

- name: Publish Sub-package to NPM
working-directory: ${{ matrix.package-dir }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm publish --access public

- name: Clear npm cache
run: npm cache clean --force
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ The aim of this project is the creation of OpenAPI (for JSON-RPC) and AsyncAPI (

## Directory Structure

```
```bash
./
├── README.md <!-- Main project documentation file -->
├── addRequestTemplate.js <!-- Script for adding request templates -->
Expand Down Expand Up @@ -185,14 +185,12 @@ Semantic Versioning (Semver) is a versioning system that helps to avoid dependen

## Code Generation

<<<<<<< HEAD
- The code generator will live outside of all projects (clio , rippled, JavaScript, python, etc…). It can be written in C++, Go, a LISP language, or other languages supporting easy manipulation of Abstract Syntax Trees.
=======

1. `required` is specified at the bottom of request / response schemas by listing required fields - NOT specified in every individual field. (This makes it easier to at-a-glance see if the list of required fields are all there / what they are, but makes it slightly harder to read individual fields and know if they’re required or not).
2. In order to specify the request / response type for JSON RPC, we need to use a generic path (`/`) and a [`discriminator`](https://redocly.com/docs/resources/discriminator/) which allows us to derive the “type” of an object from the value in a specific parameter in the request. (In the case of the JSON RPC API, the `method` field tells us the type of request, which corresponds exactly with 1 or 2 response types)
- The one case where this isn’t enough information is when a request has a `binary` option - in which case there are 2 possible response structures.
- The one case where this isn’t enough information is when a request has a `binary` option - in which case there are 2 possible response structures.
3. Error responses in the "path" section represent HTTP response / errors. `rippled` or `clio` errors are treated as valid responses, and should be documented as `oneOf` the possible representations for each individual request response. Although rippled errors share a similar shape, ultimately we want to be very clear on what the specific error codes that are possible from each request.
>>>>>>> d950159 (docs updates)

- Provide flexibility for project specific behaviors while focusing on core data types and methods.

Expand Down
21 changes: 21 additions & 0 deletions async_api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# XRPL AsyncAPI Specification

This package provides the AsyncAPI specification for the XRP Ledger ([XRPL](https://xrpl.org)) WebSockets API.

## Installation

Install the package via npm:

```bash
npm install @xrpl/rippled-asyncapi-spec
```

## Usage

Once installed, import the AsyncAPI specification file directly from the package:

```javascript
import xrplSpec from '@xrpl/rippled-asyncapi-spec/asyncapi.json'
```

You can then use the specification with tools like Postman, or AsyncAPI clients to [generate client libraries](https://github.com/ripple/openapi-codegen-xrpl).
19 changes: 19 additions & 0 deletions async_api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@xrpl/rippled-asyncapi-spec",
"version": "1.0.0",
"description": "AsyncAPI Specification for the XRPL rippled API",
"author": "Ripple",
"repository": {
"type": "git",
"url": "https://github.com/ripple/rippled-api-spec.git"
},
"keywords": [
"asyncapi",
"asyncapi-spec",
"xrpl",
"rippled"
],
"license": "MIT",
"main": "asyncapi.json",
"sideEffects": false
}
4 changes: 3 additions & 1 deletion async_api/requests/account_channels_async_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ components:
- $ref: '../../shared/requests/account_channels.yaml#/components/schemas/AccountChannelsRequest'
properties:
command:
description: The account_channels method returns information about an account's Payment Channels. This includes only channels where the specified account is the channel's source, not the destination. (A channel's "source" and "owner" are the same.) All information retrieved is relative to a particular version of the ledger. Returns an {@link AccountChannelsResponse}.
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
constant: account_channels
id:
# Not specifying a type is how we express "any" value is acceptable
description: 'A unique identifier for the request.'
Expand Down Expand Up @@ -82,9 +82,11 @@ components:
properties:
result:
type: object
$id: AccountChannelsSuccessResult
allOf:
- $ref: '../../shared/requests/account_channels.yaml#/components/schemas/AccountChannelsSuccessResponse'
status:
type: string
$id: AccountChannelsStatusSuccess
enum:
- success
3 changes: 3 additions & 0 deletions async_api/requests/account_info_async_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ components:
- type: object
properties:
command:
description: The `account_info` command retrieves information about an account, its activity, and its XRP balance. All information retrieved is relative to a particular version of the ledger. Returns an {@link AccountInfoResponseV1}.
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
id:
# Not specifying a type is how we express "any" value is acceptable
Expand Down Expand Up @@ -153,10 +154,12 @@ components:
$id: AccountInfoSuccessResponseV1
properties:
result:
$id: AccountInfoSuccessV1Result
type: object
allOf:
- $ref: '../../shared/requests/account_info.yaml#/components/schemas/AccountInfoSuccessResponseV1'
status:
$id: AccountInfoSuccessV1Success
type: string
enum:
- success
Expand Down
1 change: 1 addition & 0 deletions async_api/requests/account_lines_async_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ components:
- type: object
properties:
command:
description: The account_lines method returns information about an account's trust lines, including balances in all non-XRP currencies and assets. All information retrieved is relative to a particular version of the ledger. Expects an {@link AccountLinesResponse}.
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
id:
# Not specifying a type is how we express "any" value is acceptable
Expand Down
3 changes: 3 additions & 0 deletions async_api/requests/ledger_entry_async_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ components:
- type: object
properties:
command:
description: The `ledger_entry` method returns a single ledger object from the XRP Ledger in its raw format. Expects a response in the form of a {@link LedgerEntryResponse}.
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
id:
description: 'A unique identifier for the request.'
Expand Down Expand Up @@ -73,11 +74,13 @@ components:
$id: LedgerEntrySuccessResponse
properties:
result:
$id: LedgerEntrySuccessResponseResult
type: object
allOf:
- $ref: '../../shared/requests/ledger_entry.yaml#/components/schemas/LedgerEntrySuccessResponse'
status:
type: string
$id: LedgerEntryStatusSuccess
enum:
- success
required:
Expand Down
41 changes: 16 additions & 25 deletions async_api/requests/submit_async_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ components:
- Submit-only mode takes a signed, serialized transaction as a binary blob, and submits it to the network as-is. Since signed transaction objects are immutable, no part of the transaction can be modified or automatically filled in after submission.
- Sign-and-submit mode takes a JSON-formatted Transaction object, completes and signs the transaction in the same manner as the sign method, and then submits the signed transaction. We recommend only using this mode for testing and development.
To send a transaction as robustly as possible, you should construct and sign it in advance, persist it somewhere that you can access even after a power outage, then submit it as a tx_blob. After submission, monitor the network with the tx method command to see if the transaction was successfully applied; if a restart or other problem occurs, you can safely re-submit the tx_blob transaction: it won't be applied twice since it has the same sequence number as the old transaction.
properties:
allOf:
- $ref: '../../shared/requests/submit.yaml#/components/schemas/SubmitRequest'
properties:
command:
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
id:
# Not specifying a type is how we express "any" value is acceptable
description: 'A unique identifier for the request.'
required:
- command
- id
allOf:
- $ref: '../../shared/requests/submit.yaml#/components/schemas/SubmitRequestV1'
- type: object
properties:
command:
$ref: '../../shared/base.yaml#/components/schemas/CommandTypes'
id:
description: 'A unique identifier for the request.'
required:
- command
- id
example:
id: 2
command: submit
Expand All @@ -34,14 +33,10 @@ components:
properties:
result:
type: object
discriminator:
propertyName: status
mapping:
success: '../../shared/requests/submit.yaml#/components/schemas/SubmitSuccessResponseV1'
error: '../../shared/requests/account_info.yaml#/components/schemas/SubmitErrorResponse'
discriminator: status
oneOf:
- $ref: '../../shared/requests/account_info.yaml#/components/schemas/SubmitSuccessResponseV1'
- $ref: '../../shared/requests/account_info.yaml#/components/schemas/SubmitErrorResponse'
- $ref: '../../shared/requests/submit.yaml#/components/schemas/SubmitSuccessResponseV1'
- $ref: '../../shared/requests/submit.yaml#/components/schemas/SubmitErrorResponse'
# TODO: Decide if it's worth having these fields (id and type) here or better to just include them in both the BaseSuccess and BaseError objects for maintainability / readability.
id:
# Not specifying a type is how we express "any" value is acceptable
Expand Down Expand Up @@ -93,13 +88,9 @@ components:
properties:
result:
type: object
discriminator:
propertyName: status
mapping:
success: '../../shared/requests/submit.yaml#/components/schemas/SubmitSuccessResponseV2'
error: '#/components/schemas/SubmitErrorResponse'
discriminator: status
oneOf:
- $ref: '../../shared/requests/account_info.yaml#/components/schemas/SubmitSuccessResponseV2'
- $ref: '../../shared/requests/submit.yaml#/components/schemas/SubmitSuccessResponseV2'
- $ref: '#/components/schemas/SubmitErrorResponse'
# TODO: Decide if it's worth having these fields (id and type) here or better to just include them in both the BaseSuccess and BaseError objects for maintainability / readability.
id:
Expand Down
18 changes: 18 additions & 0 deletions async_api/websocket_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ channels:
- $ref: '#/components/messages/AccountInfoRequest'
- $ref: '#/components/messages/AccountLinesRequest'
- $ref: '#/components/messages/LedgerEntryRequest'
- $ref: '#/components/messages/SubmitRequest'
# ... (Add references for additional requests)
publish:
operationId: publishToRoot
Expand All @@ -64,6 +65,7 @@ channels:
- $ref: '#/components/messages/AccountInfoResponseV1'
- $ref: '#/components/messages/AccountLinesResponse'
- $ref: '#/components/messages/LedgerEntryResponse'
- $ref: '#/components/messages/SubmitResponse'
# ... (Add references for additional responses)

# Moved message definitions to a separate components section
Expand Down Expand Up @@ -101,6 +103,14 @@ components:
payload:
$ref: './requests/ledger_entry_async_api.yaml#/components/schemas/LedgerEntryRequest'

# Submit request message
SubmitRequest:
name: SubmitRequest
messageId: SubmitRequest
contentType: application/json
payload:
$ref: './requests/submit_async_api.yaml#/components/schemas/SubmitRequest'

# ... (Add definitions for additional message types)

# Account channels response message
Expand Down Expand Up @@ -134,4 +144,12 @@ components:
contentType: application/json
payload:
$ref: './requests/ledger_entry_async_api.yaml#/components/schemas/LedgerEntryResponse'

# Submit response message
SubmitResponse:
name: SubmitResponse
messageId: SubmitResponse
contentType: application/json
payload:
$ref: './requests/submit_async_api.yaml#/components/schemas/SubmitResponseV1'
# ... (Add definitions for additional response types)
24 changes: 12 additions & 12 deletions docs/contributing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

We currently use Redocly's tooling to test that our api is following the specification. We also use it to verify that we can generate, submit, and receive responses that match our api description with Redocly's "Try It" feature that let's you send requests directly from the auto-generated docs.

1. Install `redocly cli` - https://redocly.com/docs/cli/installation/
2. Run `redocly lint json_api.yaml` (Docs on their lint command: https://redocly.com/docs/cli/commands/lint/)
1. Install `redocly cli` - [https://redocly.com/docs/cli/installation/](https://redocly.com/docs/cli/installation/)
2. Run `redocly lint openapi.yaml` (Docs on their lint command: [https://redocly.com/docs/cli/commands/lint/](https://redocly.com/docs/cli/commands/lint/))

- Resolve any errors that appear by looking up error codes here: https://redocly.com/docs/cli/rules/recommended/
- Resolve any errors that appear by looking up error codes here: [https://redocly.com/docs/cli/rules/recommended/](https://redocly.com/docs/cli/rules/recommended/)

3. Log in if you have Redocly credentials to use the premium version (the community version also works, but does not have the ["Try It"](https://redocly.com/docs/api-reference-docs/guides/try-it-console/) feature)
3. Log in if you have Redocly credentials to use the premium version (the community version also works, but does not have the ["Try It"](https://redocly.com/docs/api-reference-docs/guides/try-it-console/) feature)

- To Log in run `redocly login` (then follow the instructions)
- To Log in run `redocly login` (then follow the instructions)

4. Run `redocly preview-docs json_api.yaml` - https://redocly.com/docs/cli/commands/preview-docs/
5. In order to use the "Try it!" feature to see if the specification can be used to send a valid request and correctly validate a real response, you'll need to get around CORS errors. One way to do that is to run this script to create an unprotected Chrome, then view your generated docs from there: `open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security`
4. Run `redocly preview-docs openapi.yaml` - [https://redocly.com/docs/cli/commands/preview-docs/](https://redocly.com/docs/cli/commands/preview-docs/)
5. In order to use the "Try it!" feature to see if the specification can be used to send a valid request and correctly validate a real response, you'll need to get around CORS errors. One way to do that is to run this script to create an unprotected Chrome, then view your generated docs from there: `open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security`

# How to add a new Amendment
## How to add a new Amendment

New Amendments usually introduce new transactions and/or requests. Please follow [these](./add-a-new-request.md#how-to-add-a-new-request) [documents](./add-a-new-transaction.md#how-to-add-a-new-transaction) for implementing changes, in addition to updating the rippled API version spec as detailed [here](./add-a-new-rippled-api-version.md).

# Plan & Actions
## Plan & Actions

We targets toward the end of November 2024 to have a first version available, not necessarily encompassing all the below tasks.

Expand Down Expand Up @@ -113,16 +113,16 @@ AsyncAPI Docs Work
- [ ] Upgrade XRPL AI to include AI function calling that allows the bot to execute commands automatically against the XRPL simply by reading the API specification
- [ ] Integrate OpenAPI and AsyncAPI into Redocly, including styling

# Future work
## Future work

- [ ] Publish specs to other package managers such as Cargo (for Rust)
- [ ] Work with https://xrplcluster.com to see about integration
- [ ] Work with [https://xrplcluster.com](xrplcluster) to see about integration

## Moving to OpenAPI 4.0 due to limitation of OpenAPI 3.0 mapping input parameters to exact output response objects

The `discriminator` property on input parameters can map input parameters to input schemas, but it does not do the same for mapping input parameters to response schema.

```
```yaml
paths:
/:
post:
Expand Down
Loading
Loading