Coder Social home page Coder Social logo

xrp-api's People

Contributors

ayaggarwal avatar dependabot[bot] avatar fksripple avatar fredkschott avatar intelliot avatar mduo13 avatar sfittje-ripple avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

xrp-api's Issues

Errors don't follow documented format

getAccountInfo Example:

GET http://localhost:3000/v1/accounts/1/info

Expected result:

400 Bad Request

{
  "message": "...",
  "errors": [...]
}

Actual result:

200 OK

{
  "error": {
    "name": "RippledError",
    "data": {
      "account": "rBayiNwjomzHtiJgCYVinWvkykrqmx8RQj",
      "error": "actNotFound",
      "error_code": 19,
      "error_message": "Account not found.",
      "id": 2,
      "ledger_current_index": 687576,
      "request": {
        "account": "1",
        "command": "account_info",
        "id": 2,
        "ledger_index": "current"
      },
      "status": "error",
      "type": "response",
      "validated": false
    }
  }
}
  • Wrong response code (should be 400 Bad Request, is 200 OK)
  • Not a message/errors array (just a single "error" object in the wrong format)

getAccountSettings Example

GET http://localhost:3000/v1/accounts/1/settings

Actual result:

200 OK

{
  "errors": [
    {
      "name": "ValidationError",
      "message": "instance.address does not conform to the 'address' format,instance.address does not match pattern '^r[1-9A-HJ-NP-Za-km-z]{25,34}$'"
    }
  ]
}
  • Wrong response code (should be 400 Bad Request)
  • Required top-level message field is missing (should be a sibling of errors per the API spec)
  • Array member uses wrong field name (should be code, not name, per the API spec)

Unify transaction formats

Similar to XRPLF/rippled#2599, this API has a lot of slightly different formats for transactions. It's actually even worse here because the mix of formats derived from ripple-lib and rippled APIs. Here's a list of the ones I've seen in the schemas here:

  • Payment object and instructions
  • Payment Object
  • Transaction
  • Transaction Instructions
  • TransactionStatus
  • Transaction JSON

Now, some of this is just a naming problem because there are different wrappers and whatnot that all need names (e.g. the immediate "engine result" from submitting a transaction vs. the result of looking up a transaction) but we may want to consider how many different things we want at all and when we want them.

At a minimum we should pick either the "RippleAPI-style" transaction JSON or the "rippled-style" transaction JSON and match that where possible. If we go with rippled-style transactions, I think it's fine to have some "extensions" like representing transaction Flags as a map of booleans rather than an integer and parsing string encoding of memos and Domain as text rather than hex.

(Fun fact: the field names from the rippled-style JSON are not strictly defined by the protocol, since the actual canonical format is the binary blob, so you could theoretically go straight from a different JSON format to a signed binary. But in all likelihood, the easiest way to do that is by converting to something pretty similar to the rippled format anyway.)

"Not found" errors should be 404

Responses from the API should use the HTTP code 404 Not Found if the thing in question was not found. (Unlike #5, this issue involves also adding the "404" responses to the API spec.)

Basically any API method with a path parameter should probably be able to return 404. Also anything that lets you use a ledger query parameter.

  • Get account (info/settings/transactions/whatever)
  • Get transaction
  • Get ledger, or get anything from a specific ledger
  • Other things to be added to the API later

API Style Guide

We should develop (possibly in this issue) a "style guide" for the API itself that can be used to make decisions about how the API should represent data. This guide can lay out the principles for how the API should operate and decisions about individual API details can reference this guide as a starting point.

Section 1: REST-like Interface

A strictly RESTful interface is not a great fit for blockchain tech because the details of how you modify data in a decentralized consensus model add latency and other complications. However, it's not a bad idea to follow REST-like API design principles where they do work, as laid out in the following rules:

  1. Request and response bodies should be valid JSON and should represent native data structures with as minimal "wrapping" as possible.
    • That's different from the JSON-RPC model where things are wrapped in a result field, etc.
    • See some later points for exceptions and clarifications around this rule, e.g. pagination
  2. Commands that fetch data should use the GET HTTP method. Commands that submit data should use the POST method, or PUT if they're idempotent. GET commands should not be able to modify data on the server side; POST/PUT/DELETE commands should always modify data if they're successful.
    • It's OK, but not preferable, to use POST for "search-like" read-only operations where trying to fit all the parameters into the path & query parameters would result in especially long and complex URLs.
  3. The API should return 2xx HTTP status codes only when the intended operation was successful.
    • 200 OK is fine for just about everything, but we can consider other 2xx codes like 201 Created or 204 No Content if there's a specific reason to prefer it over 200 OK.
    • The API should return 4xx status codes when the intended operation failed because of something to do with the request (such as invalid formatting, or requesting a resource that's not found)
    • The API should return 5xx status codes when the operation failed because of something to do with the server (such as not being connected to a valid/synced rippled server, or being misconfigured)

Section 2: Data Types

  1. All body data should be formatted as JSON objects. We should never have a top-level JSON array or number, for example.
    • The API MAY accept (or even return!) actual binary as the request or response body in specific cases. The Content-Type header MUST use application/octet-stream (or another, more specific type) in these cases.
    • The API SHOULD assume application/json if a request omits the Content-Type header. The response MUST ALWAYS use the correct Content-Type header.
  2. Any field that may represent a number outside of IEEE 64 Double precision (such as XRP drops, which are UInt64) should be represented as a number string. Values returned by the API should be normalized as canonically as possible; the API MAY accept values that don't follow all the rules of canonicity as described here:
    1. May have a leading - (for negative numbers) but no leading +
    2. No leading zeroes
    3. May have . for a decimal component.
    4. Decimals may not have trailing zeroes.
    5. May have an exponent such as 5E-1.25 which would be equivalent of the scientific notation 5.0 ร— 10-1.25. The E is uppercase.
    6. The exponent follows the same rules as the significand. (No leading zeroes, may be negative or decimal, + is not allowed, etc.)
    7. There is no "negative zero".
    8. No whitespace, commas, etc.
    9. Some data types may place additional restrictions on the values that can be used, such as being positive, integer, or within a specific range.
  3. Some fields may represent binary data within a JSON structure. Those will be represented as hexadecimal strings using uppercase letters.
  4. Fields that represent bitwise flags in the XRP Ledger should represented as objects where each key is the name of the flag and the value is a boolean with the flag's value. Fields whose value is false MAY be omitted. (In the rare cases where false is not the flag's default value for some reason, the API should always explicitly specify the flag.)
  5. Fields that represent currency values, including XRP, should always be represented by an object with currency and value fields (and counterparty for issued currencies, when we get there). Both drops (integer) and XRP (decimal) should be accepted currency values on input, but drops should be the default for responses from the API (or maybe that could be configurable?).

Section 3: Versioning

While the API is still on major version 0, breaking changes will be made frequently without warning or documentation. When we think the API is stable enough we should declare the software version 1.

The remainder of the rules described in this section only apply after version 1 has been released.

  1. URLs should start with a "version prefix" such as v1. If any incompatible changes to an API method are introduced, the new method will have a different version number such as v2.
  2. The API MAY have multiple versions of an API method available simultaneously at different version prefixes, to allow for graceful migration of dependent software.
  3. The version prefix MAY change even if there are no incompatible changes to the method, but ONLY in the case where all non-legacy methods are upgraded to use a new version prefix.
  4. Adding new fields to an existing response format is not considered a breaking change unless those fields are necessary to properly understand the object in context of the data structures previously returned in the same context. Similarly, adding new optional fields/query parameters to an existing request format is not considered a breaking change.
    • Examples of breaking changes include: making required fields optional in a response format, adding new required fields to a request format, allowing an existing response field to contain new data types.

Section 4: Submitting Changes

Needs discussion. We could have fairly "RESTful" API methods that submits a data structure and the API translates that into the transaction(s) that should result in the specified data structure, but I think that's a bad idea.

  • Since an account's Sequence number increases with every transaction, there are no idempotent operations, and making changes to the ledger costs XRP as well. So seemingly-intuitive patterns like, "PUT {the settings I want}" are likely to shoot people in the foot, resulting in race conditions or latency traps.
  • Frequently, fields users can't modify directly are stored side-by-side in the XRP Ledger with fields they can modify.

I think we should have a generic "Prepare Transaction" method that does a bunch of "best practice" pre-processing on something that mostly resembles the native rippled transaction format, and produces a JSON + binary value that can be signed. It can have convenience features like translating a map of booleans into a Flags integer, encoding memos, accepting counterparty in places where the rippled API wants issuer, auto-filling Sequence, Fee, and any other fields we think are good like LastLedgerSequence, etc. etc.. We may or may not want to combine this with the Sign operation.

Section 5: Field Names

This needs discussion. I'd like to see things follow the rippled convention where capital letters indicate fields that are canonically written to some binary data structure and lower case letters indicate fields that are dynamically derived, but I'm not committed to that.

I also like snake_case names more than camelCase names for legibility, but that seems unpopular in OpenAPI specs (maybe because OpenAPI itself uses a lot of camelCase field names?).

Support Payment Channel claims

One of the most important features of the XRP Ledger for ILP compatibility is payment channels. To properly use payment channels, though, you need:

  • The ability to send channel-related transactions (create, fund for topping off, request close, redeem claim)
  • The ability to look up a channel's status. I think the rippled API mostly uses the "channel ID" for this, which you can also derive from the combination of sender, receiver, and sequence number used to create the channel. So we could consider paths like /channels/{channel_id} or /accounts/{address}/channels/{destination}/{seq}
  • The ability to check claims for validity. In the rippled API, the channel_verify method does some of this, although it doesn't cover all the things you might want to do like checking when the channel expires and whether the channel currently holds enough XRP to fulfill the claim.
  • The ability to sign new claims (channel_authorize), which you might involve setting up some more secret key stuff since you don't necessarily want to use your account's key for the channel's public key.

Suggestion: getAccountInfo should be GET /accounts/{address}

The "Account Info" (which basically just returns an AccountRoot object) is the core definition of an account, so I think it makes sense in the hierarchy to put that operation at GET /accounts/{address} instead of its current place at GET /accounts/{address}/info.

Suggestion: Use validated ledger by default

I think @JoelKatz would argue that you usually want the "latest" data even if it's pending, but I think there's a good case to be made that you should query "validated" ledger data unless otherwise specified.

Basically, the way I see it is this. Validated data is stuff you can take action on. Pending stuff, it's nice to know about, but you don't necessarily want to do anything about it.

Both types of data are subject to change. With "validated" data, there may be new, forthcoming changes that you aren't seeing if you're looking at that ledger. With "pending" data, that's still possible but you also have to consider the possibility of rollbacks, because a tentative transaction may not have executed or may have executed differently by the time it becomes validated. So you can make much more concrete inferences about what's possible and what might happen from a "validated" ledger than you can from a "current" ledger.

I think it's good to be able to query either one (for example, I like that my bank shows "pending" transactions in the UI) but I think the "validated" ledger is a more reasonable default to work with.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.