Web request

The Web Request Action Node is a generic component used to integrate with other systems. The component lets you integrate with all modern API endpoints, such as Slack, Jira, Microsoft Dynamics, Google Cloud, etc.

An important part of implementing integrations is to know the system you want to integrate towards. Most modern systems provide a (REST) API and documentation of the various endpoints you may access, as well as the format of its input and response.

A good approach when it comes to integrations is to use an external tool, such as Postman, for testing communication towards the external system. Postman is quite easy to get started with, and once you have successfully made a request in Postman, it is fairly straightforward to set this up in Appfarm!

An example setup of a web request is showcased in our Showroom! You may view a demo, as well as access the setup in Create. If you do not have access, you may register here.

Key settings

In this section, we will describe the different settings of the Web Request Action node, followed by some practical examples.

URI

The address to the endpoint you want to communicate towards. This is normally defined by the API documentation of the external system.

Path parameter

Often, the URI/URL contains some dynamic parts, called path parameters. In that case, the URL should be set using the Function Editor.

When fetching company information about companies from the Norwegian government, the API link might look like this:

https://data.brreg.no/enhetsregisteret/api/enheter/919697199

The URL has one static (https://data.brreg.no/enhetsregisteret/api/enheter/) and one dynamic part (919697199). In this example, you might set the URL by using the Function Editor, adding the company organization number as a variable, and returning the URI + variable.

return "https://data.brreg.no/enhetsregisteret/api/enheter/" + orgNumber 

Query Parameters

Sometimes, the API we are calling has parameters in the URI. In the above example, the external API might define that you may send a parameter OrgNo as a parameter instead. You may add OrgNo as a Query Parameter in the web request, and set the value to Company.OrgNumber. If the base URI is https://data.brreg.no/enhetsregisteret/api/enheter, adding a Query Parameter OrgNo will produce a URI such as https://data.brreg.no/enhetsregisteret/api/enheter?OrgNo=919697199.

Request Headers (custom headers)

Add Custom Header tags to your Web Request.

In some cases, the external application requires some headers. Request Headers are, opposite to Query Parameters, not part of the URL. They are part of the header of the request.

Authorization

This is where you set up the Authorization normally required by the external system. There are primarily two types of authorization: Basic and Bearer. When testing in Postman - you see them in the Authorization section. Basic allows you to input a username and password, whereas Bearer allows you to enter a token. When using Basic Authorization, you should add the Username and Password here. Note: These should be stored as Secrets in Appfarm Create, and these Secrets should be selected in this action node. When using Bearer Authorization, you should add the bearer token here. Normally, you would also tick the option Prefix bearer keyword (the header will then be Bearer <YOUR_TOKEN>)

Note: A Bearer token is normally not static, and must be retrieved and stored on a schedule.

An example setup of how to get a Bearer (OAuth2) token is showcased in our Showroom! You may view a demo, as well as access the setup in Create. If you do not have access, you may register here.

For other types of Authorization (other than Basic or Bearer), you may use Request Headers.

Method

Defined by the external API. Possibilities: GET, POST, PUT, PATCH, DELETE. GET and POST are by far the most used. A GET does not send Body Data - and is normally used for sending a request to receive some information from another system A POST sends some Body Data. Changing the method from GET to POST will give you the option to set the Body Data of the web request. POST is normally used for sending data to another system.

Body Data (for POST methods)

Here you will need to create a JSON string with a structure defined by the external system. You will typically use a function for creating this. An example of sending order status 2 for a given Order to another system:

// orderID has been added as a function parameter
return `{ "ExternalOrderID": ${orderID}, "Status": 2 }`;

Result Mapping

When performing either GET or POST operations - the other system might send some data back, typically in JSON format. Appfarm supports JSON "out of the box", but in cases where SOAP (old web services/xml) is used, you may transform the result to JSON first using the Result Parser (not demonstrated here).

Looking up company info with a GET web request, might send back the following JSON-formatted structure (defined by the external system API, or as seen when playing around in Postman), in this case a simplified example:

{
  "orgNo" : "919697199",
  "name" : "Appfarm AS",
  "orgType" : {
    "code" : "AS",
    "description" : "Aksjeselskap"
    },
  "addresses": [
   {
    "country" : "Norge",
    "line1" : "Torggata 15",
    "postalCode": "0515"
   },
   {
    "country" : "Norge",
    "line1" : "Dummy street 1",
    "postalCode": "0515"
   }
  ]
}

Setting up the Result Mapping: First, add an item. You normally just need 1 item. 1 item allows you to map properties of the received JSON structure to a data source.

  • Root path: If you want to start looking up properties at a level deeper down in the structure than the root level. Typically - leave it blank.

  • Data source: This needs to be a runtime-only data source. If the data you receive is a list (e.g. a list of orders) - select a runtime-only Orders data source with cardinality many. In the example above, add a runtime-only data source Company (single cardinality).

  • Update Object / Update Existing / Mapping Property:

    • If the data source has cardinality One, you will see the Update Object option. By default, if unchecked, the data source will be replaced (meaning, any existing object in that data source will be removed, and replaced with a new object). If checked, the existing object will be updated with new values on the properties defined with a Property mapping (see below).

    • If the data source has cardinality Many, you will see the Update Existing option, and if checked, a Mapping Property option as well. Update Existing means that if an existing object is found in the data source, it should be updated instead of adding a new record to the data source. You need to define how to locate that existing object, and you do that by defining the Mapping Property. Example: As seen in the above screenshot, the JSON property "customerNumber" is mapped to the internal Object Class Property Cust No. Cust No is defined as Mapping Property, meaning that if customerNumber "123456" is returned from the web request, Appfarm will see if an entry with Cust No "123456" exists in that data source, and if so - update the Name and Org No of that entry.

  • Nested Data Mapping: If the response contains nested structures (such as a list of Orders, and for each Order - a list of Order Lines) you may use Nested Data Mapping for first map Orders, and then map Order Lines - and connect these. You would need to define the Root path at the top level (e.g. to orders), and for the Nested Data Mapping - define the Path (e.g. to orderLines) and the Root Connection (e.g. Order Lines (temp).Order).

  • Automap Node Names: If the name of the properties of the JSON returned by the web request matches the node name of the Object Class Properties of the Appfarm Data Source - you may tick Automap Node Names. This will simply autofill the Property Mapping with the node names of the Object Class Properties.

  • Property Mapping: See the illustration below. Note the [] expression in the received JSON. This implies a list, and we might access the property line1 of the first item in the list by stating addresses.0.line1

Notes to the Property Mapping in the example above:

  • By defining a root path, the property mapping will start at the first level of "children" of the root path. E.g. if the root path was set to orgType in the above JSON example, you could map the object class property Org type simply by referencing description.

  • If the root path holds a list of objects (as is the case for addresses in the JSON above, as seen by the square brackets), the Data Source set in the Result Mapping must be of cardinality Many. E.g. if the root path is set to addresses in the above JSON example, we might set the Data Source to Addresses (temp) (a runtime-only, multi-cardinality data source), and the property mapping would be line1 and country - resulting in Addresses (temp) to be populated with 2 objects.

  • As seen in the illustration above, we set the property mapping to addresses.0.line1 and addresses.0.country. Since the addresses node has a list of objects as children - this is a syntax for just retrieving the properties of the first child (the first address in the list).

Other settings

Send from client

A web request is by default sent from the server - e.g. when initiated from an app, the request is sent to the Appfarm server before it is sent to the actual destination.

When you tick Send from client - you send directly from the client. In some cases, this may reveal a more detailed log if something fails. Send from client is normally used for debugging. Note that when "Send from client" is ticked, you need to add the hostname to the "Allowed web request targets" section in Create -> Config -> Environment Config (for each environment). Note that it is quite common for external APIs to block web requests initiated directly from the clients/web browsers.

Use static IP

This setting is only visible if the static IP feature is enabled for your solution, and this has to be enabled by Appfarm. When Use static IP is ticked, the request will be routed through a proxy with a static / fixed IP address (the default IP for this is 35.233.86.224).

Content Type (for POST operations)

This is the content type for the Body of a POST request. The default setting is JSON, but if the external system requires some other content type, this might be adjusted here.

Response Type

Normally no need to set it, the default is JSON, but it may be overwritten (e.g. an Array buffer for receiving files and converting the binary data to a base64 string). Note that you may use the Create file object action node with Source Type "URL" for downloading a file from a URL and uploading it into your own file object class.

Result parser

The Result parser (if set) is applied before the Result Mapping is executed.

Result parser is normally used when the response contains xml - i.e. when dealing with SOAP endpoints. The Result parser may also be used if - in some cases - the JSON response of the external system is not possible to map directly using the Result Mapping. In such cases, you may use a result parser to transform the received JSON into another JSON format, or to add other properties to the JSON before doing result mapping.

If the response contains the following JSON:

{ "CompanyName": "Appfarm", "OrgNo": "123456789"}

Using a Result parser, the rawResponseData is a JSON object containing the value above.

If we want to add a property "CompanyStatus": "active" to the JSON before the Result mapping is done, you may add a Result parser with the following function:

rawResponseData.CompanyStatus = "active"

return rawResponseData

Inside the Result parser, the parameter rawResponseData holds the response received from the web request. You may use javascript to transform it. The result parser should always return a valid JSON structure, and the JSON structure returned from the Result Parser should be mapped in the Result Mapping.

Use Mutual TLS

Some integrations, such as Apple Pay, require mutual TLS. This is defined as when "two or more entities verify the others' legality before any data or information is transmitted". Checking the mutual TLS checkbox reveals 3 more settings:

  • CA Certificate: The certificate of the Certificate Authority (CA). This is not required in all cases. Upload the certificate as a secret or resource file, and select it.

  • Certificate: Your private certificate. Save the certificate as a secret and select the secret.

  • Key: Your private key. Save the private key as a secret and select the secret.

Debugging a Web Request

When testing your Web Request, you may inspect the actual response received, or the request sent using the Console log in your browser.

In the above screenshot, you may see the log for a the Web Request when doing a POST operation. The JSON {"Test": "OK"} is sent in the Request.

By expanding the log-entry named payload, you may inspect the Header, URL and Body of the Request, as well as the StatusCode and Body of the Response (depending on whether a POST or GET is performed).

Handling SOAP integrations

When the other system has a SOAP endpoint, an XML structure must be sent, and XML will be received. You should try to set up the request in Postman - if you succeed, it is only a matter of setting up the Result parser.

Method Must be set to POST, even if you are only querying data.

Body Content An example of the function of the Body Content:

return `
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://accountingsystem.com/webservices">
   <soapenv:Header/>
   <soapenv:Body>
      <web:Login>
         <web:credential>
            <web:ApplicationId>${applicationId}</web:ApplicationId>
            <web:IdentityId>${identity}</web:IdentityId>
            <web:Password>${password}</web:Password>
            <web:Username>${username}</web:Username>
         </web:credential>
      </web:Login>
   </soapenv:Body>
</soapenv:Envelope>
`

Request Headers Some headers are normally required. An example: A header with a key "SOAPAction" and value "http://accountingsystem.com/webservices/login".

Result Parser The rawResponseData contains an XML. Here's an example of the result parser, when the response from the Login request is an xml:

var parser = new DOMParser();
var doc = parser.parseFromString(rawResponseData, "text/xml");

return {
    sessionId: doc.getElementsByTagName("LoginResult")[0].textContent
}

Result Mapping Same as for REST integrations. In the example above, the returned structure from the Result parser is

{
    sessionID: "<some-id>"
}

You would just need to map "sessionID" to your object class property in the Property Mapping section.

Last updated