Inteli OpenAPI service for interacting with the DSCP (Digital Supply-Chain Platform)
inteli-api
is configured primarily using environment variables as follows:
variable | required | default | description |
---|---|---|---|
SERVICE_TYPE | N | info |
Logging level. Valid values are [trace , debug , info , warn , error , fatal ] |
PORT | N | 80 |
The port for the API to listen on |
EXTERNAL_ORIGIN | N | The origin from which the OpenAPI service is accessible. If not provided the value will default to http://localhost:${PORT} |
|
EXTERNAL_PATH_PREFIX | N | A path prefix from which this service is served | |
LOG_LEVEL | N | info |
Logging level. Valid values are [trace , debug , info , warn , error , fatal ] |
API_VERSION | N | package.json version |
API version |
API_MAJOR_VERSION | N | v1 |
API major version |
DSCP_API_HOST | Y | - | dscp-api host |
DSCP_API_PORT | Y | - | dscp-api port |
DB_HOST | Y | - | PostgreSQL database hostname |
DB_PORT | N | 5432 |
PostgreSQL database port |
DB_NAME | N | inteli |
PostgreSQL database name |
DB_USERNAME | Y | - | PostgreSQL database username |
DB_PASSWORD | Y | - | PostgreSQL database password |
FILE_UPLOAD_SIZE_LIMIT_BYTES | N | 1024 * 1024 * 100 |
Maximum file size in bytes for upload |
IDENTITY_SERVICE_HOST | Y | Hostname of the dscp-identity-service |
|
IDENTITY_SERVICE_PORT | Y | Port of the dscp-identity-service |
|
AUTH_TYPE | N | NONE |
Authentication type for routes on the service. Valid values: [NONE , JWT ] |
The following environment variables are additionally used when AUTH_TYPE : 'JWT'
variable | required | default | description |
---|---|---|---|
AUTH_JWKS_URI | N | https://inteli.eu.auth0.com/.well-known/jwks.json |
JSON Web Key Set containing public keys used by the Auth0 API |
AUTH_AUDIENCE | N | inteli-dev |
Identifier of the Auth0 API |
AUTH_ISSUER | N | https://inteli.eu.auth0.com/ |
Domain of the Auth0 API ` |
AUTH_TOKEN_URL | N | https://inteli.eu.auth0.com/oauth/token |
Auth0 API endpoint that issues an Authorisation (Bearer) access token |
Start dependencies:
docker compose up -d
Install packages:
npm i
Run DB migrations:
npx knex migrate:latest --env test
Run the application in development mode:
npm run dev
Assuming devDefault
environment variables, view OpenAPI documentation for all routes with Swagger:
localhost:3000/v1/swagger/
The Swagger route is constructed as localhost:{PORT}/{API_MAJOR_VERSION}/swagger
. OpenAPI docs can also be viewed as JSON localhost:{PORT}/{API_MAJOR_VERSION}/api-docs
.
If AUTH_TYPE
env is set to JWT
, the endpoints on inteli-api
require Bearer Authentication using a JSON Web Token. Tokens are generated externally as an Auth0 Machine to Machine token. You will need to create your own Auth0 API, which can be done for free, and set the appropriate environment variables (those prefixed with AUTH
). Follow the start of this tutorial to create an API. Go here and here to see where the environment variables are used.
Integration tests for AUTH_TYPE: 'JWT'
use a preconfigured Auth0 test application and user to authenticate across multiple dscp
services. Follow the tutorial here to create your own.
Once a test application and user is created, running integration tests locally requires a /test/test.env
file containing the following environment variables:
variable | required | default | description |
---|---|---|---|
AUTH_TEST_USERNAME | Y | - | Username of the auth0 user for testing |
AUTH_TEST_PASSWORD | Y | - | Password of the auth0 user for testing |
AUTH_TEST_CLIENT_ID | Y | - | Client ID of the auth0 application for testing |
AUTH_TEST_CLIENT_SECRET | Y | - | Client secret of the auth0 application for testing |
Start dependencies with AUTH_TYPE: 'JWT'
:
AUTH_TYPE=JWT docker compose up -d
Run tests:
npm run test:jwt
inteli-api
provides a RESTful OpenAPI-based interface for third parties and front-ends to interact with the DSCP
system. The design prioritises:
- RESTful design principles:
- all endpoints describing discrete operations on path derived entities.
- use of HTTP verbs to describe whether state is modified, whether the action is idempotent etc.
- HTTP response codes indicating the correct status of the request.
- HTTP response bodies including the details of a query response or details about the entity being created/modified.
- Simplicity of structure. The API should be easily understood by a third party and traversable.
- Simplicity of usage:
- all APIs that take request bodies taking a JSON structured request with the exception of attachment upload (which is idiomatically represented as a multipart form).
- all APIs which return a body returning a JSON structured response (again with the exception of attachments.
- Abstraction of the underlying DLT components. This means no token Ids, no block numbers etc.
- Conflict free identifiers. All identifiers must be conflict free as updates can come from third party organisations.
These are the top level physical concepts in the system. They are the top level RESTful path segments. Note that different states of an entity will NOT be represented as different top level entities.
recipe
orders
build
part
Additionally, there is one more top level entity attachment
which accepts a multipart/form-data
payload for uploading a file. This returns an attachmentId
that can then be used when preparing entity updates to attach files.
Entity queries allow the API user to list those entities (including a query) and to get a specific entity. For order
for example:
GET /order
- list ordersGET /order/{orderId}
- get order
Allows the creation of an initial local state for an entity. Note this is essentially just to establish an internal identifier for the entity and the state is not shared across the blockchain network at this point.
POST /order
Allows different kind of updates to be prepared and applied to an entity. For example, an order
must be submitted via a submission
action. Each update can have specific files attached along with other specific metadata.
POST /order/{orderId}/submission
- create an ordersubmission
action and send it to the blockchain.GET /order/{orderId}/submission
- list ordersubmissions
and their status.GET /order/{orderId}/submission/{submissionId}
- get the details of an ordersubmission
.
The last top level entity attachment
, which accepts a multipart/form-data
payload for uploading a file or application/json
for uploading JSON as a file. This will return an attachmentId
that can then be used when preparing entity updates to attach files.
POST /attachment
GET /attachment/{attachmentId}
Demoing the routes in inteli-api
requires two personas: buyer
and supplier
. Each persona runs their own instance of inteli-api
and its dependencies.
Before transacting, each persona sets aliases in dscp-identity-service
for other parties' node addresses so they can refer to them by human-friendly names. The self
alias should also be set for a persona's own node address.
buyer
wants to create arecipe
, which describes how a particularsupplier
will make apart
. Arecipe
always includes an imageattachment
, so firstbuyer
must upload an image to their local database withPOST /attachment
.- They use the returned
imageattachmentId
in the request body toPOST /recipe
, as well as settingsupplier: 'supplier'
and providing an array ofrequiredCerts
for therecipe
. Later on,supplier
will need to add a certificate file for eachrequiredCert
for thepart
built from therecipe
. At this point, therecipe
only exists in thebuyer
database. - When
buyer
is ready for therecipe
to exist on chain theyPOST recipe/{id}/creation
.supplier
can now see therecipe
if their node is running and connected. buyer
creates anorder
of 1-10recipes
in their local database withPOST /order
, again settingsupplier: 'supplier'
. The request will fail if any of the listed recipes are set with a different supplier.- When
buyer
is ready for theorder
to exist on chain theyPOST order/{id}/submission
. supplier
canPOST order/{id}/rejection
orPOST order/{id}/acceptance
the order. For simplicity they will accept, signifying their intent to buildparts
to fulfil theorder
.supplier
creates abuild
of 1-10recipes
in their local database. They must have thesupplier
role for eachrecipe
.- When
supplier
is ready for thebuild
to exist on chain theyPOST build/{id}/schedule
. This also creates a newpart
on chain for eachrecipe
. supplier
can assign an individualpart
to anorder
withPOST part/{id}/order-assignment
.itemIndex
in the request body matches the index on theorder
for the specificrecipe
that was used to build thatpart
.builds
(andparts
) can be started and completed before anorder
is made and later assigned to one.- A required certificate (
attachment
) for apart
is added with/part/{id}/certification
bysupplier
.certificationIndex
in the request matches the index on therecipe
for therequiredCert
that the uploaded certificate is fulfilling. supplier
can change the estimated date of completion or add general build files (attachments
) to thebuild
withPOST build/{id}/progress-update
.supplier
can add general, non-required files (attachments
) to thepart
withPOST build/{id}/metadata-update
.- Finally,
supplier
can complete thebuild
withPOST build/{id}/completion
.