Skip to main content
Skip table of contents

HTTP Nodes Tutorial

Introduction

This tutorial will guide you through how to use the following HTTP nodes:

  1. HTTP In - The HTTP In node allows you to create an HTTP endpoint that can receive incoming HTTP requests, enabling flow to respond to web-based triggers.

  2. HTTP Request - The HTTP Request node is used to make HTTP requests to external web services or APIs, enabling your flow to fetch data or interact with remote services.

  3. HTTP Response - The HTTP Response node is used to send HTTP responses back to clients or services that have made requests to your flow endpoints, allowing you to send data or messages as responses.

Tutorial Flow Source Code

To explore the HTTP nodes featured in this tutorial, simply download the attached JSON file below and import it into your flow app.

http_nodes.json

You can do this by either pressing Ctrl + I simultaneously or by navigating to the main settings and selecting the Import option.

Tutorial

HTTP Response Nodes

Every HTTP In node should be connected to one or more HTTP Response Nodes, that would provide the HTTP status code of the call to the client. More information about the HTTP response status codes, can be found: here.

You can set-up the status code in three different ways:

By default, the HTTP Response node status code would be set automatically to an appropriate value. If you want to overwrite it, you can:

  1. Set-up directly the status code in the HTTP Response node dialog window, or

  2. Set-up the msg.statusCode from outside the HTTP Response node

HTTP Response Body

If you want to return any payload to the client initiating the HTTP request, you can set the msg.payloadwhich will be returned to the caller along with the HTTP Status node.

HTTP Request URL and Method

There are two possibilities to set the URL and Method of the HTTP Request nodes:

  1. Setting it up directly in the dialog window of the HTTP Request node

  2. Setting it up outside the HTTP Request node by setting the msg.url to set the URL and msg.method to set the method.

In the example HTTP Nodes flow that’s attached above, I am setting up the msg.url in the inject node using JSONata expression to construct the request URL.

Example:
$env("BASE_URL") & "/hello" would translate to https://flow-qiiopfx378xt8.demo-01.qibb.com/hello.

BASE_URL

The base URL of your flow is contained into an environmnetal variable called BASE_URL.

Testing Yout API Endpoint

You are encouraged to test your API endpoints through an API client like Postman, Insomnia, curl, or by directly accessing the respective URL from your browser.

Please be aware that your web browser is suitable exclusively for GET requests that do not demand specific headers or authentication.

GET /hello

The first flow is a basic “Hello World” example, where we are using an HTTP In node to create an HTTP API endpoint GET /hello and a template node to set the msg.payload to an HTML file with a title and a heading to display the "Hello qibb".

The flow has two parts, one HTTP In node, creating a GET request API endpoint, and another flow, which consists of an inject node, HTTP Request node, and a debug node. The URL is set directly in the inject node using JSONata expression as explained above.

GET /hello-query

Query Parameters

HTTP query parameters are essential components of a URL used for enhancing the functionality and flexibility of web requests. These parameters are appended to a URL following a question mark (?) and are expressed as key-value pairs, separated by ampersands (&).

They allow clients to convey specific instructions and requirements to web servers, facilitating tasks such as data filtering, sorting, pagination, and configuration settings.

The /hello-query flow is taking advantage of using query parameters to dynamically update the greeting set in the HTML template node. The template node is using a mustache template to set the greeting to Hello {{req.query.firstName}} {{req.query.lastName}}.

Normally the request query parameters are saved as msg.req.query.{queryName} where {queryName} is the name of your query parameter. If there are multiple query parameters, they are represented as a list of key/value pairs where the key is the query name and the value is the query value.

  • {{req.query.firstName}} is the Mustache way to refer to msg.req.query.firstName

  • {{req.query.lastName}} is the Mustache way to refer to msg.req.query.lastName

Please note that both the firstName and secondName are separated by an ampersend sign: &, so the request URL is https://{BaseURL}/hello-query?firstName=John&lastName=Doe.

HTTP Request Query Parameters

The output of the GET /hello-query?firstName=John&lastName=Doe call is an HTML file with the following format:

HTML
<html>
    <head>
        <title>qibb HTTP Nodes</title>
    </head>
    <body>
        <h1>Hello John Doe!</h1>
    </body>
</html>

Output Page

GET /hello-path/:name

Path Parameters

HTTP path parameters are components of a URL used to convey data or instructions to a web server as part of the URL's path rather than the query string. Path parameters are crucial for designing dynamic and RESTful APIs, allowing clients to specify resource identifiers or parameters directly in the URL. Unlike query parameters, they are considered a part of the URL's structure.

Path Parameters Notation

Path parameters are created in the HTTP In node by setting the path parameter, with a leading colon (:), e.g. in GET /hello-path/:name the name is a path parameter.

The path parameters are saved under msg.req.params.{pathParameter}, where the {pathParameter} is the path parameter

In the HTML template node, we have used {{req.params.name}} which like the query parameters is a Mustache reference to a path parameter called name.

If we send an HTTP request to GET /hello-path/John, the path parameter is “name": "John".

HTTP Request Path Params

The output would be similar to the query flow, but this time, we are only passing the first name and the `{{req.params.name}} will be replaced with the value of the path parameter name in the greeting: Hello {{req.params.name}}!

GET /hello-headers

This flow uses a very basic authentication mechanism relying on a static API Key. The switch node assesses whether the API key is provided in the request's X-API-Key header. If it is, the node proceeds to compare the header value with the predefined static key. A match leads to the flow being directed to the Success JSON template node, otherwise to the Error JSON template node.

HTTP Request Headers

It's important to note that all parsed header parameters are stored in lowercase, allowing for case-insensitive checks only.

If the API key does not match, the HTTP status code is manually overwritten to 401 (Unauthorized) and the API endpoint returns a JSON object containing an "Error" status and a description of the encountered issue.

In case of matching API key, the API endpoint returns another JSON object with status and information about the user-agent and the x-api-key used for the call.

Both the user-agent and the X-API-Key used for the request are set directly in the HTTP Request node, and the Return parameter is set to a parsed JSON object.

Passing Headers to the HTTP Request Call

User Agent

A User-Agent is a text string sent by a web browser or client in an HTTP request, conveying information about the client's application, version, and operating system to the web server. This helps servers provide compatible responses.

So the output JSON object would be of the type:

JSON
{
   "status":"Success",
   "headers":{
      "user-agent":"qibb",
      "x-api-key":"b73432c0-5fdf-4967-8677-8a3d036c88a5"
   }
}

In case the API Key doesn’t match or is not passed with the call the returned status code would be 401 (Unauthorized) and the response would be the following JSON object:

JSON
{
   "status":"Error",
   "description":"Please make sure that you have provided the correct API-Key in the HTTP request headers!"
}

Static API Key

The downside of using static API keys is their vulnerability to unauthorized access if exposed or compromised, as they remain constant and do not offer strong security. Key rotation can be cumbersome, and they lack fine-grained access control.

To enhance API security, it's often recommended to use more advanced authentication methods such as OAuth, JWT tokens, or API tokens with short lifetimes, which can mitigate these issues and provide better protection against unauthorized access, but they are out-of-scope from this tutorial.

HEAD Request

HEAD Request

A HEAD request is an HTTP method used to retrieve the headers of a resource without fetching the resource's body. It is employed to retrieve metadata about a resource, such as its content type, content length, and modification date, without actually downloading the content.

HEAD requests are commonly used to check if a resource exists, to obtain information about it, or to assess its status, such as checking if a webpage has been modified since a certain date. They are useful for conserving bandwidth and reducing unnecessary data transfer when only header information is needed.

This flow uses the HEAD method to retrieve information about an mp4 video file including:

  • file size

  • file type

  • modification date

Method and URL

In this flow, the msg.method is set to HEAD, while the method in the HTTP Request node dialog window is set to - set by msg.method - and is set in the previous inject node, while the URL is set directly in the HTTP request node.

Setting the Method Dynamically

The function node retrieves information about the following headers:

  • Content-Length - contains the file size in bytes

  • Content-Type - provides information about the file type

  • Last-Modified - contains information when the file was modified for the last time

The function node also converts the bytes into KiB, MiB, GiB, etc. using the formatBytes function and returns a new object containing information about only the formatted size, file type, and modification date:

JS
function formatBytes(bytes) {
    // Converts bytes to KiB, MiB, GiB, etc.
    if (!bytes) return '0 Bytes'

    const k = 1024;
    const decimals = 2;
    const sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];

    // Gets the size index
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    // Returns the filesize in the respective size 
    return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`;
}

// Fetching the file size from the headers
const fileSizeInBytes = msg.headers["content-length"];
const fileType = msg.headers["content-type"];
const lastModified = msg.headers["last-modified"];

const fileSize = formatBytes(fileSizeInBytes);

// Assigning the payload to a JSON object containg the type of the file and the converted filesize
msg.payload = {
    type: fileType,
    size: fileSize,
    modificationDate: lastModified
};

return msg;

The resulting JSON object would be like this:

JSON
{
   "type":"video/mp4",
   "size":"20.65 MiB",
   "modificationDate":"Tue, 18 Apr 2023 20:26:33 GMT"
}
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.