Skip to content

Latest commit

 

History

History
383 lines (316 loc) · 19 KB

add-a-new-request.md

File metadata and controls

383 lines (316 loc) · 19 KB

How to add a new request

For these instructions:

  • There's a decent amount of boilerplate code, so each step will include a template you should copy along with a list of which fields need updating.
  • ... in the template indicates you should edit something (Ex. Replacing ...Request with AccountChannelsRequest)
  • If this is for a request documented on xrpl.org, please copy and paste the documentation from there.
  • Read through shared/base.yaml after doing a draft of your spec to see if there are any re-usable components that make sense for your requests/responses

Generate boilerplate for a new request

Run the following command to generate boilerplate code for a new request where you can edit based on the steps in the latter sections:

npm run template <request_name>

For the above command, <request_name> should be the name of the new request in snake_case convention (e.g. account_channels). This would create 3 different files:

  • shared/requests/<request_name.yaml> (instructions to edit here).
  • open_api/requests/<request_name.yaml> (instructions to edit here).
  • async_api/requests/<request_name.yaml> (instructions to edit here).

How to create a new request in the shared directory

  1. If you've already created a spec in the shared folder for this request, skip to the OpenAPI specific steps!

  2. Some of the steps mentioned here could be automatically generated by this instruction. If you've already done so, only fill in the details that are missing.

  3. Create a new file for the rippled request / response information in shared/requests/<request_name.yaml>

  4. In that shared file, add the Request type.

    1. ... indicates you should edit something (Ex. Replacing ...Request with AccountChannelsRequest)
    2. If this is for a request documented on xrpl.org, please copy and paste the documentation from there.
    3. Read through shared/base.yaml to see if there are any re-usable components that make sense for your request
    • Fields to update:
      1. ...Request with the name of the request (ex. AccountChannelsRequest)
      2. summary: with a description of this request
      3. If there are any common fields in shared/base.yaml that can be re-used, do so with allOf - otherwise delete that TODO comment.
      4. properties with the parameters for this request (in alphabetical order)
      5. required with a list of any required parameters (in alphabetical order)
    ...Request:
      summary: >
        ...
      type: object
      # TODO: Add any common fields from `shared/base.yaml` that are applicable using `allOf`. Otherwise delete these comments! For example:
      # allOf:
      #  - $ref: '../base.yaml#/components/schemas/LookupByLedgerRequest'
      #  - ...
      properties:
        # Example property
        # account:
          # type: string
          # description: The unique identifier of an account, typically the account's address.
        ...
      required:
        - ...
    
  5. Create the ...SuccessResponse schema for when rippled responds with success.

    • Fields to update:
      1. ...SuccessResponse with the name of the request (ex. AccountChannelsSuccessResponse)
      2. If there are any common fields in shared/base.yaml that can be re-used, do so with allOf - otherwise delete that TODO comment.
      3. properties with the parameters for this request (in alphabetical order)
      4. required with a list of any required parameters (in alphabetical order)
    ...SuccessResponse:
      # TODO: Add any common fields from `shared/base.yaml` that are applicable using `allOf`. Otherwise delete these comments! For example:
      # allOf:
      #  - $ref: '../base.yaml#/components/schemas/LookupByLedgerRequest'
      #  - ...
      type: object
      properties:
        # Example property
        # account:
          # type: string
          # description: The unique identifier of an account, typically the account's address.
        ...
      required:
        - ...
    
  6. Create the ...ErrorResponse schema for when rippled responds with an error code.

    • Fields to update:
      1. ...ErrorResponse with the name of the request (ex. AccountChannelsErrorResponse)
      2. enum: with a yaml list of the specific error codes that are associated with this specific response (ex. invalidParams). Do not include errors which are already in the UniversalErrorResponseCodes listed in shared/base.yaml.
      3. request should have a reference to the shared ...Request. (NOT the ...Request object that is in this file!)
    ...ErrorResponse:
      type: object
      properties:
        error:
          type: string
          oneOf:
            - $ref: '../base.yaml#/components/schemas/UniversalErrorResponseCodes'
            # Add the error codes specific to this response here (ex. invalidParams)
            - enum:
                - ...
          # Include a bullet descrip for every
          description: >
            ...
        status:
          type: string
          enum:
            - error
        request:
          # This should link to the ...Request type you defined above
          $ref: ...
      required:
        - status
        - error
        - request
    
  7. If you want to add a request to the OpenAPI spec, follow these steps here (otherwise skip this step)

  8. If you want to add a request to the AsyncAPI spec, follow these steps here (otherwise skip this step)

OpenAPI-specific steps for adding a new request

This section assumes you've already completed the shared work steps for this request in How to add a new request

At a high level, we're going to wrap the core types we defined in shared/ in boilerplate so it matches the JSON RPC formatting rippled expects / produces, then we're going to reference our wrapped types in the core json_api.yaml file.

Some of the steps mentioned here could be automatically generated by this instruction. If you've already done so, only fill in the details that are missing.

  1. Create a new file in open_api/requests named ..._open_api.yaml for your new request. Ex. account_channels_open_api.yaml

    • The reason to include _open_api in the name is to make it easier to tell which file we're referencing throughout the codebase, and to make filename searches less confusing when debugging. Including it at the end also makes it easier to at a glance find the right file in the explorer.
    • Example file: open_api/requests/account_channels_open_api.yaml
  2. Add a ...Request schema with the following boilerplate and an example which references the ...Request we defined in shared/requests. See template below:

    • Fields to update:
      1. ...Request with the name of the request (Ex. AccountChannelRequest)
      2. description with a long explanation of what the request is (use xrpl.org text if available)
      3. method with the request name (ex. account_channels)
      4. items's $ref: to reference the ...Requestwe defined in shared/requests
      5. example with a valid request of this type that includes most if as many optional fields as possible while still being valid
     ...Request:
       type: object
       description: >
         ...
       properties:
         method:
           type: string
           enum: # This is the most supported way to define a specific string as the only valid input. `const` is a new keyword which is supported in OpenAPI, but not in all corresponding codegen tools. https://github.com/OAI/OpenAPI-Specification/issues/1313
             - ...
         params:
           type: array
           items:
             $ref: # Reference the shared `...Request` schema
       required:
         - method
       example:
         # Provide a valid example here, such as:
         # method: 'account_channels'
         # params:
         #   - account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn'
         #     destination_account: 'ra5nK24KXen9AHvsdFTKHSANinZseWnPcX'
         #     ledger_index": 'validated'
    
  3. Add the ...Response object which is mostly boilerplate, but still has a couple fields to update:

    • Fields to update:
      1. ...Response with the name of the request (Ex. AccountChannelResponse)
      2. In the mapping: 3. Map success to a reference to the ...SuccessResponse in this file (NOT the shared file!) 4. Map error to the the ...ErrorResponse in the SHARED file
      3. In the oneOf, add BOTH of the above references in a list.
      4. example with a valid successful response of this type, ideally the exact response to sending the example in ...Request in this file.
    ...Response:
       type: object
       properties:
         result:
           type: object
           discriminator:
             propertyName: status
             mapping:
               success: # Include a reference to ...SuccessResponse from this file
               error: # Include a reference to the **shared** ...ErrorResponse
           oneOf:
             - $ref: # Include a reference to ...SuccessResponse from this file
             - $ref: # Include a reference to the **shared** ...ErrorResponse
       required:
         - result
       example:
         # result:
         #   account: rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
         #   channels:
         #     - account: rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
         #       amount: '1000'
         #       balance: '0'
         #       channel_id: C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7
         #       destination_account: ra5nK24KXen9AHvsdFTKHSANinZseWnPcX
         #       public_key: aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw
         #       public_key_hex: 03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2
         #       settle_delay: 60
         #   ledger_hash: 27F530E5C93ED5C13994812787C1ED073C822BAEC7597964608F2C049C2ACD2D
         #   ledger_index: 71766343
         #   status: success
         #   validated: true
         ...
    
  4. Create the ...SuccessResponse schema to combine the BaseSuccessResponse and the shared success schema. (This is done to match the JSON RPC response format while re-using our shared schema)

    • Fields to update:
      1. ...SuccessResponse
      2. Update the 2nd reference in allOf to the SHARED ...SuccessResponse (NOT the one in this file!)
    ...SuccessResponse:
      type: object
      allOf:
        - $ref: '../../shared/base.yaml#/components/schemas/BaseSuccessResponse'
        - $ref: # Reference the `...SuccessResponse` in the **SHARED** folder
    
  5. Lastly, we need to update the open_api/json_api.yaml file:

    • Fields to update:
    1. Update #paths///post/requestBody/content/application/json/schema/discriminator/mapping with a mapping between the request name and your ...Request object from the ..._open_api.yaml file (NOT the shared file!)

      • Ex. account_channels: 'requests/account_channels_open_api.yaml#/components/schemas/AccountChannelsRequest'
    2. Update the oneOf just below the mapping you modified with another reference to the ...Request object from the ..._open_api.yaml file

      • Ex. - $ref: 'requests/account_channels_open_api.yaml#/components/schemas/AccountChannelsRequest'
    3. Update #paths///post/responses/200/content/application/json/schema/oneOf with a reference to the ...Response (NOT ...Request) object from the ..._open_api.yaml file.

      • Ex. - $ref: 'requests/account_channels_open_api.yaml#/components/schemas/AccountChannelsResponse'

Note: If you want to also add this request to the AsyncAPI, continue by following these steps here

AsyncAPI-specific steps for adding a new request

This section assumes you've already completed the shared work steps for this request in How to add a new request

At a high level, we're going to wrap the core types we defined in shared/ in boilerplate so it matches the Websocket formatting rippled expects / produces, then we're going to reference our wrapped types in the core websocket_api.yaml file.

Some of the steps mentioned here could be automatically generated by this instruction. If you've already done so, only fill in the details that are missing.

  1. Create a new file in async_api/requests named ..._async_api.yaml for your new request. Ex. account_channels_async_api.yaml

    • The reason to include _async_api in the name is to make it easier to tell which file we're referencing throughout the codebase, and to make filename searches less confusing when debugging. Including it at the end also makes it easier to at a glance find the right file in the explorer.
    • Example file: async_api/requests/account_channels_async_api.yaml
  2. Add a ...Request schema with the following boilerplate and an example which references the ...Request we defined in shared/requests. See template below:

    • Fields to update:
      1. ...Request with the name of the request (Ex. AccountChannelRequest)
      2. description with a long explanation of what the request is (use xrpl.org text if available)
      3. allOf's -$ref: to reference the ...Requestwe defined in shared/requests
      4. command with the request name (ex. account_channels)
      5. example with a valid request of this type that includes most if as many optional fields as possible while still being valid
    ...Request:
       description: >
         ...
       type: object
       allOf:
         - $ref: ... # Reference the Request in `shared/requests` here
       properties:
         command:
           type: string
           enum: # This is the most supported way to define a specific string as the only valid input. `const` is a new keyword which is supported in OpenAPI, but not in all corresponding codegen tools. https://github.com/OAI/OpenAPI-Specification/issues/1313
             - ...
         id:
           # Not specifying a type is how we express "any" value is acceptable
           description: 'A unique identifier for the request.'
       required:
         - command
         - id
       example:
         # Show a valid request that follows the schema here, for example for account_channels:
         # id: 1
         # command: account_channels
         # account: rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
         # destination_account: ra5nK24KXen9AHvsdFTKHSANinZseWnPcX
         # ledger_index: validated
         ...
    
  3. Add the ...Response object which is mostly boilerplate, but still has a couple fields to update:

    • Fields to update:
      1. ...Response with the name of the request (Ex. AccountChannelResponse)
      2. In the oneOf, the first entry should reference the ...SuccessResponse in this file (NOT the shared file!)
      3. In the oneOf, the second entry should reference the ...ErrorResponse in this file (NOT the shared file!)
      4. example with a valid successful response of this type, ideally the exact response to sending the example in ...Request in this file.
    ...Response:
      discriminator: status
      oneOf:
        - $ref: # Reference the ...SuccessResponse in this file
        - $ref: # Reference the ...ErrorResponse in this file
      type: object
      properties:
        id:
          # Not specifying a type is how we express "any" value is acceptable
          description: 'A unique identifier for the request.'
        type:
          type: string
          description: The value response indicates a direct response to an API request. Asynchronous notifications use a different value such as `ledgerClosed` or `transaction`.
          enum: # This is the most supported way to define a specific string as the only valid input. `const` is a new keyword which is supported in OpenAPI, but not in all corresponding codegen tools. https://github.com/OAI/OpenAPI-Specification/issues/1313
            - response
      required:
        - id
        - type
      example:
       # Example formatting for `account_channels` response
       # id: 1
       # result:
       #   account: rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
       #   channels:
       #     - account: rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
       #       amount: '1000'
       #       balance: '0'
       #       channel_id: C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7
       #       destination_account: ra5nK24KXen9AHvsdFTKHSANinZseWnPcX
       #       public_key: aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw
       #       public_key_hex: 03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2
       #       settle_delay: 60
       #   ledger_hash: 27F530E5C93ED5C13994812787C1ED073C822BAEC7597964608F2C049C2ACD2D
       #   ledger_index: 71766343
       #   validated: true
       # status: success
       # type: response
       ...
    
  4. Create the ...SuccessResponse schema to combine the BaseSuccessResponse and the shared success schema. (This is done to match the JSON RPC response format while re-using our shared schema)

    • Fields to update:
      1. ...SuccessResponse
      2. Update the 2nd reference in allOf to the SHARED ...SuccessResponse (NOT the one in this file!)
    AccountChannelsSuccessResponse:
      type: object
      allOf:
        - $ref: '../../shared/base.yaml#/components/schemas/BaseSuccessResponse'
        - $ref: # Reference the `...SuccessResponse` in the **SHARED** folder
    
  5. Lastly, we're going to update the websocket_api.yaml file to reference our newly created Websocket wrapper of our rippled request / response types.

    1. In subscribe add a new message object for your new request which references the ...Request we made in the ..._async_api.yaml (NOT the shared version!)

      • Fields to update:
        1. name with the name of your request + Request (Ex. AccountChannelsRequest)
        2. $ref with a reference to the ...Request object in the ..._async_api.yaml file (NOT the shared version!)
          • Ex. './requests/account_channels_async_api.yaml#/components/schemas/AccountChannelsRequest'
      message:
        name: '...Request'
        payload:
          $ref: ...
      
    2. Do the same in the publish section except for Response instead of Request

      • Fields to update:
        1. name -> ...Response
        2. $ref should point to the ...Response (not ...Request) schema from the ..._async_api.yaml file (NOT the shared version!)

Note: If you want to also add this request to the OpenAPI spec and haven't already, continue by following these steps here