Skip to content

REST

This extension enables you to query JSON-based REST APIs and post messages with content to them.

It provides various options regarding methods of transport, headers and authentication, and is an open-ended way to cover as many use cases as possible. JSON objects are directly converted into Arden Syntax objects, and the other way around when written.

Configuration

The following basic options can be configured for the REST extension:

  • Base URL: The base URL that is prepended to all URLs specified within an MLM
  • Timeout: Amount of milliseconds the extension will wait on any query until it returns NULL
  • Headers: List of headers by name and value that are always sent with every request

Authentication

For Authentication, Authentication Type can be set to one of three values, which each require their own different options:

  • Basic: Simple HTTP Basic Username/Password authentication
    • Username
    • Password
  • Bearer: For use with fixed authentication tokens
    • Token
  • OAuth: Authentication by the OAuth client_credentials method
    • Base URL: Base URL of the OAuth API
    • Grant Type: Only supports the client_credentials flow
    • Client ID: ID of your registered client with this application
    • Client Secret: Secret of your registered client with this application

Example configuration

REST example config

Usage

The extension can be used from an MLM in three basic ways:

  • READ can be used for retrieval like GET operations. It can query an API in a single line and is more readable than an INTERFACE call, but can only be used in the data slot. Use it if you only perform a query in a data slot once.
  • WRITE can be used for posting data to an API via POST, PATCH, etc. It is the preferred way to write a final result and can only be used in the action slot.
  • INTERFACE can be used to define a REST operation in the data slot and be CALLed anytime. Use it if you need to do calls in the logic slot.

READ

Every call made by read is a GET request without any content allowed, and responses are expected to be JSON formatted.

Parameters

NameRequiredExampleDescription
pathYespath "/api/resource?incl=true&limit=15"Path to call, may include query parameters, is appended to the Base URL. No absolute URLs are allowed.
headerNo, can be provided multiple timesheader X-Clacks-Overhead "GNU Terry Pratchett"Set any custom header. If the same header is allready set in extension configurations, this mapping clause overwrites the header. Allows variable injection of the header value or literal strings as content
timeoutNotimeout 30000How many milliseconds until a request is failed with NULL. Overwrites configuration.

Examples

READ with custom headers and query parameter filters only

arden-syntax
data:
      all_diagnoses := READ {FROM rest-configuration WITH path "/patient/01/diagnoses?not-before=2023-01-01" AND header Accept-Language "de-AT,de-DE,de"};
      ;;

READ with post-request filter

INFO

Unlike FHIR operations, the data returned here is first fetched and then filtered by Arden Syntax.

arden-syntax
data:
      all_diagnoses := READ {FROM rest-configuration WITH path "/patient/01/diagnoses"} WHERE it.first_symptom_ts >= 2023-01-01;
      ;;

READ with custom path and headers using variable injection

arden-syntax
data:
      dynamic_path := "/patient/" | ARGUMENTS | "/diagnoses";
      acceptable_languages_header := "de-AT,de-DE,de";
      all_diagnoses := READ {FROM rest-configuration WITH path $dynamic_path AND header Accept-Language $acceptable_languages_header};
      ;;

WRITE

WRITE operations can only be invoked in an action slot, concluding a successful MLM execution. The response body is discarded in the WRITE statement, as it is intended to write a result and conclude the MLM. It supports the common HTTP methods for that purpose (PUT, POST, PATCH or DELETE).

Parameters

WRITE operations follow the schema WRITE <content> AT <destination>. A DESTINATION is required for the destination and contains path, method and the other common parameters. For content, either a variable or a MESSAGE can be provided (see below). When a variable is provided, two rules dictate serialization to JSON:

  • An object or a list are serialized to JSON
  • A string is directly passed on as HTTP message

DESTINATION parameters:

NameRequiredExampleDescription
pathYespath "/api/resource?incl=true&limit=15"Path to call, may include query parameters, is appended to the Base URL. No absolute URLs are allowed.
timeoutNotimeout 30000How many milliseconds until a request is failed with NULL. Overwrites configuration.
methodYesmethod PUTHTTP method to sent the request. Allowed are PUT, POST, PATCH, or DELETE

MESSAGE (discouraged) parameters:

NameRequiredExampleDescription
contentNocontent $variable_injectedContent to send to a server. Only Arden Objects (will be converted to json) and Strings (encode to UTF-8 byte content in the Http request) are allowed contents. Allows variable injection ($ + variable name, which exists at time of CALL invokation) or literal strings as content.
headerNo, can be provided multiple timesheader X-Clacks-Overhead "GNU Terry Pratchett"Set any custom header. If the same header is already configured in the REST configuration, this mapping clause overrides it. Allows variable injection of the header value or literal strings as content

INFO

The message mapping clause is mainly supported to comply with the Arden standard and allow custom headers. If content were the only parameter in your clause, we actually encourage to supply the content directly, either as string or variable, inside the WRITE statement. It is much more readable (see examples below).

Examples

WRITE object as JSON with POST request

arden-syntax
data:
      record_diagnosis_destination := DESTINATION {FROM rest-configuration WITH method POST AND path "/diagnosis"};
      diagnosis := NEW Condition WITH [ code := "disease" ];
      ;;
logic: CONCLUDE TRUE; ;;
action:
        WRITE diagnosis AT record_diagnosis_destination;
        ;;

WRITE object with custom headers and variable injection, using MESSAGE statement

TIP

If possible, it is recommended to supply the request content as object variable inside the WRITE statement, as it reduces the implementer-specific logic you have to deal with in an MLM

arden-syntax
data:
      diagnosis := NEW Condition WITH [ code := "disease" ];
      never_forgotten := "GNU Terry Pratchett"
      record_diagnosis_destination := DESTINATION {FROM rest-configuration WITH method POST AND path "/diagnosis"};
      diagnosis_request := MESSAGE { FROM rest-configuration WITH content $diagnosis AND header Set-Cookie "credentials=u1234" AND header X-Clacks-Overhead $never_forgotten};
      ;;
logic: CONCLUDE TRUE; ;;
action:
        WRITE diagnosis_request AT record_diagnosis_destination;
        ;;

WRITE literal JSON string body, without MESSAGE statement

arden-syntax
data:
      record_diagnosis_destination := DESTINATION {FROM rest-configuration WITH method POST AND path "/diagnosis"};
      diagnosis_request_json := "[ { \"code\": \"diagnosis\", \"val\": 0.92 }, { \"code\": "npa" } ]";
      ;;
logic: CONCLUDE TRUE; ;;
action:
        WRITE diagnosis_request_json AT record_diagnosis_destination;
        ;;

WRITE object with literal JSON string body, using MESSAGE statement

TIP

If possible, we recommend to supply the request content as object variable inside the WRITE statement, as it reduces the implementer-specific logic you have to deal with in an MLM

arden-syntax
data:
      record_diagnosis_destination := DESTINATION {FROM rest-configuration WITH method POST AND path "/diagnosis"};
      diagnosis_request := MESSAGE { FROM rest-configuration WITH content "{ "code": "diagnosis", "val": 0.92 }" };
      ;;
logic: CONCLUDE TRUE; ;;
action:
        WRITE diagnosis_request AT record_diagnosis_destination;
        ;;

INTERFACE

Arden Syntax INTERFACE operations can be used to define any REST call, which may be executed at any time (or multiple times) within an MLM. For singular calls for data preparation or result writing in the data and action slots, it is recommended to use READ or WRITE instead for brevity and to signal intentionality.

Parameters

NameRequiredExampleDescription
pathYespath "/api/resource?incl=true&limit=15"Path to call, may include query parameters, is appended to the Base URL. No absolute URLs are allowed.
headerNo, can be provided multiple timesheader X-Clacks-Overhead "GNU Terry Pratchett"Set any custom header. If the same header is allready set in extension configurations, this mapping clause overwrites the header. Allows variable injection of the header value or literal strings as content
timeoutNotimeout 30000How many milliseconds until a request is failed with NULL. Overwrites configuration.
methodYesmethod PUTHTTP method to sent the request. Allowed are PUT, POST, PATCH, DELETE, and GET
contentNocontent $variable_injectedContent to send to a server. Only Arden Objects (will be converted to json) and Strings (encode to UTF-8 byte content in the Http request) are allowed contents. Allows variable injection ($ + variable name, which exists at time of CALL invokation) or literal strings as content.

Using CALL operation arguments as content body

Arden Syntax allows CALL INTERFACE operations with parameters supplied as operation arguments on call, like this: var := CALL rest_interface WITH variable_name;. This option can be used with a REST configuration to supply the content outside of the mapping clause. The following rules apply:

  • If no argument is supplied, no content is sent.
  • If one argument is supplied, it is sent as complete body (Object being parsed as JSON body, List being parsed as JSON list,String being sent literally)
  • If more than one argument is supplied, all are sent within a JSON list. Each argument is parsed to the same rules as above
  • If both mapping clause content and arguments are defined, the REST extension returns NULL (intent error)

Examples

CALL GET interface conditionally

arden-syntax
data:
      rest_read_call := INTERFACE {FROM rest-configuration WITH method GET AND path "/clinic/patient/01"};
      called_by_patient_status := ARGUMENTS;
      ;;
logic:
       IF called_by_patient_status.is_sick IS TRUE THEN
         patient := CALL rest_read_call;
       ENDIF
       ;;

CALL POST resource with mapping clause variable injection

arden-syntax
data:
      rest_write_call := INTERFACE {FROM rest-configuration WITH method POST AND path "/clinic/patient" AND content $patient};
      ;;
logic:
       LET patient BE NEW Patient WITH [ name := "Dr. Example" ];
       patient_created_response := CALL rest_write_call;
       
       // overwrite patient, but re-use interface method
       LET patient BE NEW Patient WITH [ name := "Thomas Example" ];
       patient_created_response := CALL rest_write_call;
       ;;

CALL PUT resource with CALL arguments

arden-syntax
data:
      rest_put_call := INTERFACE {FROM rest-configuration WITH method PUT AND path "/clinic/patient/01"};
      ;;
logic:
       LET patient BE NEW Patient WITH [ name := "Dr. Example" ];
       patient_created_response := CALL rest_put_call WITH patient;
       ;;

CALL GET resource with mapping clause Http-Headers variable injection

arden-syntax
data:
      rest_read_call := INTERFACE {FROM rest-configuration WITH method POST AND path "/clinic/patient" AND header X-Clacks-Overhead $never_forgotten};
      ;;
logic:
       LET never_forgotten BE "GNU" | " Terry Pratchett";
       patient_response := CALL rest_read_call;
       ;;