Skip to content
Erik Huelsmann edited this page Dec 28, 2020 · 1 revision

API

Goals

The intent is to have a full API for LedgerSMB, eventually. This desire has existed for a long time. To help make the discussion less abstract, we're using two cases to evaluate help evaluate the design:

  • API for GL accounts

  • API for Contacts, including:

    • Customers
    • Vendors

    but excluding:

    • Employees
    • Users

In general, the API should support the following functionalities:

  • Creation of a new element
  • Listing of existing elements, optionally
    • limited by search parameters
  • Transitioning through the [document state transition diagram](Document states)

Non-goals

  • An exact description of the protocol (headers, etc)

Assumptions

  • Any object may be subject to approval in one organization or another (not just financial transactions)
  • It's best to have a single API for financial and non-financial objects
  • A REST API will integrate best with existing tools and libraries

REST vs RPC considerations

REST

While a REST API probably integrates best with current thinking about web applications and the Dojo library already in use in the project in particular, there's a desire for a few RPC characteristics as well: current experience is with the existing ('old code') UI which POSTs entire documents to the server, leaving to the server to figure out which parts have changed and which parts the user does not expect to change. The design of a REST api could easily exhibit exactly this problem, putting the development team right back where they started.

Properties generally considered to be part of a REST api which can easily be re-used include:

  • Grouping objects of a specific type into a collection found at a specific URI
  • Retrieving objects through a URI which is a child of the collection URI
  • Listing objects through the collection URI
  • Searching objects with specific properties through the collection URI with a query string

not REST

State transitions

The part where a REST api doesn't work well is in the application of the state transitions: Whereas often times a document will change state from saved to posted on its own, there are multiple scenarios where documents have to change states in groups:

  • An invoice with its payments entered on invoice creation
  • A voiding invoice with the 'payment' transaction marking voided and voiding paid
  • A reposted transaction, marking voided and voiding paid and posting the copy
  • (and possibly others)

As demonstrated, the changing of status of a transaction is not an operation on the level of a single data object; instead, it's an action that groups/affects multiple transactions.

This being the case, the conclusion must be that transitions should not include any changes to a document other than the transition of state. Even more: only documents in the Locked state can be edited through a REST like protocol (as in: receive new content or have existing content 'replaced'), as long as such editing doesn't lead to a state transition.

To this extent, it's not logical to use a REST type API to model state transitions: the indirect effect on the state of other objects does not belong in a REST api. Instead, it's much more logical to invoke an RPC call, identifying the document(s) and invoking the desired state transition. Done this way, the server only needs to verify allowable state transitions.

Derived documents

The application supports many cases where documents don't change state (saved->posted), but where one document is derived from another (e.g. order->shipment, shipment->invoice). By implementing the logic to derive one document from another server-side, there is no need for clients to "understand" both document types (for the purpose of creation).

Document groups

The idea of document groups changing state together, might not be restricted to financial transactions: consider multiple exclusive offers having been made to a client. When one gets accepted, the others - by virtue of exclusiveness - change to a 'closed' state. (This scenario is much less likely to get built into LedgerSMB than the scenario with the grouped financial transactions.)

URI schema

Establishing a session

A session is established per-company. Multiple sessions may be established simultaneously.

(todo: add the session identification)

A session to a company can be established by posting to the the URI:

/company/<company name>/login

Listing available resource collections

A list available top-level resources by issuing a GET request on:

/company/<company name>/

The initial proposal discussed in this document has 2 top-level collections:

/company/<company name/
                       gl/accounts/
                       actors/entity/

where gl/ and actors/ are the modules the collections belong to.

Mapping of HTTP verbs (collection as a target)

GET    -->   (with search parameters)
             Retrieve a (subset) of objects in the collection
POST   -->   Create a new object in the collection

Mapping of HTTP verbs (object as a target)

GET    -->   Retrieval of the named object
PUT    -->   Save the provided object data
PATCH  -->   Run the provided RPC command
DELETE -->   Delete the resource (highly unlikely to be used in LedgerSMB)

The DELETE method is highly unlikely to be used, because state transitions are triggered through the PATCH method, which includes the delete state transition.

Relation between document states and allowable HTTP verbs

Note that this section specifically applies to "HTTP verbs (object as a target)".

The PUT method strictly applies to resources of which the document is in a Locked state. The DELETE method isn't expected to be