diff --git a/doc/adr/0014-rest-api-not-using-jsonapi.md b/doc/adr/0014-rest-api-not-using-jsonapi.md new file mode 100644 index 0000000000..73c6115f5a --- /dev/null +++ b/doc/adr/0014-rest-api-not-using-jsonapi.md @@ -0,0 +1,98 @@ +# 0014 Creation of a REST web service API -- Custom REST service based on HATEOS + +Date: Unknown + +## Status + +Accepted + +## Context + +LedgerSMB's original API, inherited from SQL-Ledger, was simply the form +interfact used by the front-end. This has always been a nightmare to integrate +with -- typos in field names, multiple posts needed to build up an invoice, and +lots of challenges for a client developer to work against. + +There has long been demand for a more formal, stable API, and this is something +the project has discussed for many years. + +"REST" has been the current style of APIs for quite some time, and several +specific standards have emerged to help API developers reuse patterns that work +in other applications. We considered two of these standards before deciding to +"roll our own": + +- GraphQL +- JSON:API + +The goal of both of these approaches is to minimize the number of round-trips a +client app needs to make when exchanging data with the server, while providing +self-documentation within the API itself. Both of these are current favorite API +styles among developers at this writing (2023). + +However, both suffer from crucial drawbacks for an accounting system. Looking at +an invoice as an example -- not only does it illustrate the problems, it also is +the most desired object to expose via an API. + +First the key requirements: + +* An invoice has several different formats to represent: json, xml, PDF, HTML. +* An invoice is composed of many different objects: customer account, line items + referencing parts, line items with calculated amounts, fields on the invoice +itself, and a specific workflow state +* Some of these related objects are independent of the invoice, while others + (line items) are wholly dependent on the invoice +* The server needs to define and enforce the allowed workflow transitions, and + the client needs to know which transitions are available for a specific +invoice in a specific state for a specific user + +While all of this is possible to do in either GraphQL or JSON:API, both require +a lot of boilerplate to get set up for both client and server for the complexity +of the relationships of the invoice object. These are general purpose tools +being applied to a very specific payload shape -- it's far easier to define the +shape of the payload to meet these requirements directly, than to build up all +the relationships using one of these standards. + +So creating our own payload shape simplifies things for both clients and +server-side development. + +We will base our API on principles as described in these resources: + +- [Bob Jones from RedHat in his July 1st, 2020 blog on REST + architecture](https://www.redhat.com/en/blog/rest-architecture) +- [Hypermedia as the Engine of Application State + (HATEOAS)"](https://sookocheff.com/post/api/on-choosing-a-hypermedia-format/). + +We will use the defacto standard for documenting web service APIs, +[Swagger/OpenAPI](https://swagger.io/specification/). + + + +## Decision + +The project will create a REST web services API with strong HATEOAS to make sure +the server is in control of the process a resource goes through. The aim being +to keep clients thin and low on maintenance. The API will be documented using +OpenAPI 3.0.x. The API will *not* make use of the JSON:API standard, instead +opting to develop our own API practices. These will include design of: + + * A consistent URL schema, which uses [semantic + versioning](https://semver.org/) for version numbering + * OpenAPI documentation of individual endpoints as well as common practices + * A generic means to convey transitions (HATEOAS) + +## Consequences + +- A new namespace `/erp/api/` needs to be developed. +- API versioning will happen encoding major version numbers, on the + `/erp/api/vXX` namespace (where XX is the version number). +- As per semantic versioning, `/erp/api/v0` is the "unstable" API; API endpoints + will be promoted to `/erp/api/v1` (or higher) once the endpoint has been +sufficiently stabilized. +- Documentation can (and should) be distributed as rendered HTML from the + OpenAPI documentation. +- Clients need to be 'thin': they will not include knowledge of the process and + transitions available to mutate a resource -- the server will present these. +- The prior bullet allows for customization of resource specific processes using + server code and/or server configuration, without impact on the client. + +## Annotations