Rest APIs using Athena

One feature in Athena is the ability to use the language to make Rest API calls.

Requirements

To follow this documentation, you should have:

  • A Satisfaction.AI application
  • Basic knowledge of Athena Addins
  • Knowledge about Rest API

The Rest addin

To make Rest API calls, Athena provide a dedicated addin: rest

Here are the basic methods available:

  • headers
  • body
  • bodyFromObject
  • get
  • post
  • put

Some of the rest addin methods have the particularity to be expandable:

@rest.headers().body().post()

In the above example, methods of rest addin are linked with a dot. This means that first the addin will executes the methods in a specific order, and are all specific to the current query:

  1. Start with the definition of the headers of the ongoing query
  2. Then set the body content of the ongoing query
  3. And finally post the data with the headers on the specified url

How to set headers

Headers of a Rest API call are meta-data associated with the query, here are 2 examples:

  • Content-Type : The Content-Type entity header is used to indicate the media type of the resource. source
  • Authorization : The HTTP Authorization request header contains the credentials to authenticate a user agent with a server, usually after the server has responded with a 401 Unauthorized status and the WWW-Authenticate header. source

The headers method accepts a json like object with the parameters.

{"Content-Type":"application/json"}

You can add as many headers as you want in the same object.

{"Content-Type":"application/json", "Authorization": "credentials"}

Because it is a json like object and therefore contains double quotes, we need to ensure that Athena won’t fail parsing the addin method by surounding this code with three double quotes on each side, instead of one:

-: @rest.headers("""{"Content-Type":"application/json"}""")

Dealing with json API

When working with rest API that accepts json, it is strongly recommanded to add the content-type header when posting data.

Most of the languages does not accept json data when the header is not present, even if the json is valid.

How to set data

Two methods exists to add data to the ongoing query:

  1. body()
  2. bodyFromObject()

The main difference between them is th way the data is passed to addin.

Using body, the data is written directly in the addin argument:

body("dataPassedToTheServer")

Using the bodyFromObject, the data is retrieved from context within the addin:

bodyFromObject("myVariableName")

But keep in mind that bodyFromObject will transform the data into JSON, so it’s only suitable with JSON rest API

body

Use this method when your data is not json and is not a big object (this will keep your athena code cleaner)

You are allowed to use variable inside the data, for example:

{"login":"%login"}

Like the headers method, you need to surround the parameter with three double quotes.

Here are some examples:

@rest.headers("""{"Content-Type":"application/json"}""").body("""{"login":"%login"}""").post("https://api.foo.com/login")
@rest.headers("""{"Content-Type":"application/xml"}""").body("""<login>%login</login>""").post("https://api.foo.com/login")

bodyFromObject

In some cases, it’s better to use a variable as the data that needs to be sent to the server:

  • Your data have special characters that are not handled by athena : line returns for instance
  • You already have an object that have been build through a scenario
  • You want to keep your Athena lines short

But there’s is a limitation: the api needs to speak JSON, the bodyFromObject will only serialize your data into JSON.

To create an object, you need to use the createObject method of the core addin.

In this example, the two first lines create an object, and the last one sets the data:

-: %data = @core.createObject()
-: %data.login = "%login"
-: @rest.headers("""{"Content-Type":"application/json"}""").bodyFromObject("data").post("https://api.foo.com/login")

It’s really important to write the variable name without the percentage symbol:

This code is valid bodyFromObject("data")

This code is invalid bodyFromObject("%data")

If you use the second form, athena will replace the data parameter with its own content, which will generate:

bodyFromObject("{"login":"%login"}")

Making the call

Depending on your needs, you will use a different method on the API endpoint:

  • GET
  • POST
  • PUT
  • DELETE

These methods accepts one or two parameter:

  1. uri
  2. uri and a variable name

Difference between the two signature

Both of the signature make the identical same call to the api, the difference resides in how they will set the values returned by the API.

When using the first signature (uri only), the addin method will set different variable:

  1. %rest will contains the response data
  2. %rest_fail is boolean variable that will inform you about the success ot the request call
  3. %rest_response is an object that will contains: statusCode and data

When using the second signature, the addin will set the third variable using your variable name:

  1. %varName is an object that will contains: statusCode and data

We encourage using the second signature. It will be easier to deal with error codes and different variable names.

Examples

The following example send json data to the foo api:

-: %userInfo = @core.createObject()
-: %userInfo.id = "uniqueId"
-: %userInfo.firstName = "John"
-: %userInfo.lastName = "Doe"
-: @rest.headers("""{"Content-Type":"application/json"}""").bodyFromObject("userInfo").put("https://api.foo.com/%userInfo.id")
-: @rest.get("https://api.foo.com/stats", "stats")
- Sorry, an unexpected error occured while retrieved the foo.com statistics
-| %stats.statusCode == 200
- We currently have %stats.data.currentUsers users.