HTTP

HTTP is a common protocol to transfer data and files over the network. The XDK supports HTTP natively and offers two modules to make HTTP requests. This section will provide an introduction to both of them and will demonstrate how to use them to make GET and POST requests.

  1. General Information
    1. The HTTP Protocol
    2. The HTTP Request
    3. The Rest Paradigm
  2. API Overview
  3. Implementation
    1. Setup
    2. Setting up HTTP resources
    3. Setting up variable resource-signals
    4. Performing Requests
    5. Settings
      1. Headers
  4. Full Code Example

General Information

The HTTP Protocol

HTTP (HyperText Transfer Protocol) is a data transfer protocol that runs on top of the TCP/IP protocol stack (see Picture “HTTP in the OSI and TCP/IP stack”). It has become the standard protocol to deliver web pages, making it the foundation of data communication for the World Wide Web. Beyond that, as HTTP is not at all restricted to hypertext, it is commonly used to transfer any kind of structured data between applications. The standard port for HTTP is the port 80.

Image

This chapter will give a quick introduction on HTTP itself as well as the related REST paradigm. Readers who are already familiar with these topics or who are just looking for the Mita specific implementation details can safely skip to chapter 2.

Note: The XDK uses version 1.1 of the HTTP protocol (“HTTP/1.1”). The complete specification of this version is available in the form of an RFC document: https://tools.ietf.org/html/rfc2616.

The HTTP Request

HTTP defines how messages between two network endpoints should be structured in order to obtain an efficient and reliable data transfer. In every interaction, one network endpoint acts as the client and the other as the server. The client sends requests to a server whenever it needs a certain resource or wants to perform a certain operation that the server offers. The server listens for incoming requests and tries to serve them as they arrive. For every request, the server replies with a response. This guide will demonstrate how to use the XDK to send requests. The XDK will therefore act as an HTTP client.

Note: The presented modules also offer functionality to setup an HTTP server. This will, however, not be covered in this guide.

A HTTP request consists of two parts. The first part is called the HTTP header, which describes the type of request and contains meta data. The second part is called the payload, which is the actual data that should be transferred. While HTTP doesn’t specify the format or encoding of the payload (it may be HTML, JSON, XML or anything else), the header has to follow the specifications in order to be readable by the receiver. As HTTP is a text-based protocol, the header is a plain (ASCII) string. Its parts are separated by line breaks. Header and payload are separated by two line breaks. A simple request (without payload) could look as follows.

GET Request

GET /index.html HTTP/1.1
Host: www.bosch.de
Accept: text/html,application/json
Accept-Language: en-us
Accept-Encoding: gzip, deflate

The only required lines in this request are the first two, which specify the protocol version, the HTTP method (GET) and the requested resource (“www.bosch.de/index.html”). Lines 3 to 5 are called Headers and provide additional information in the form of key-value pairs. Succesful and unsuccesful responses can look as follows.

Succesful GET Response

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 03 Oct 2016 21:16:16 GMT
Last-Modified: Thu, 01 Sep 2016 10:15:00 GMT
Content-Length: 88
Content-Type: text/html
[HTML page]

Failed GET Response

HTTP/1.1 404 Not Found
Server: nginx
Date: Mon, 03 Oct 2016 21:16:16 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 234
[HTML error page]

The number in the first line of the response (after “HTTP/1.1”) is called the HTTP status code. It tells the client whether the request succeeded (2XX) or failed (4XX). The numeric code is followed by its corresponding textual message. A complete list of HTTP status codes and can be found on the HTTP Wikipedia Page or in section 6.1.1 and 10 of the RFC.

An important header line is the “Content-Type” header. It specifies the expected media type of which the client expects the requested resource to be. If a server can’t provide the resource in this format, it responds with an error.

The previous responses have been examples for a GET request, which is the most common HTTP method and is used to request (i.e. download) a resource. If a client wants to send (i.e. upload) data to the server, he can use the POST method. A POST request can look as follows.

POST Request

POST /create.php HTTP/1.1
Host: 192.168.1.2:80
Content-Type: text/plain
Transfer-Encoding: chunked
[encoded data to upload]

The “Transfer-Encoding” header defines the encoding of the attached payload. The server needs this information to be able to parse the payload correctly. HTTP supports different encoding types, most of them indicating the compression algorithm that was used on the payload. The most simple encoding is called “chunked”, which is an uncompressed encoding and is described as follows:

“The chunked encoding modifies the body of a message in order to transfer it as a series of chunks, each with its own size indicator…This allows dynamically produced content to be transferred along with the information necessary for the recipient to verify that it has received the full message. - RFC 2616.

The XDK modules presented in this guide use this as their default encoding for POST requests. For a reference of the available encodings, please refer to developer.mozilla.org or section 3.6 of the RFC 2616.

This guide will explain how to perform GET and POST requests in an XDK application. A complete list of all specified HTTP methods can be found at section 5.1.1. of the RFC.

The Rest Paradigm

Representational State Transfer (REST) is a paradigm that tries to define a uniform interface for web services to improve interoperability. REST-compliant (or “RESTful”) services usually only use the HTTP methods POST, GET, PUT and DELETE, as these methods are directly mappable to the four basic functions of persistent storage: create, read, update and delete (CRUD). They also follow a common URL scheme to access and manipulate resources. Response data is provided in XML, HTML, JSON or some other defined format.

URLPOSTGETPUTDELETE

http://api.example.com/collection/

Create new elementList all elementsReplace collectionDelete the collection
http://api.example.com/collection/element12-Retrieve elementUpdate elementDelete element

By definition, RESTful services may not store any kind of client context between requests. This means that each request has to provide all the information necessary to serve the request, and that the session state has to be handled by the client.

HTTP 1.1 was designed in compliance with the REST principles.

API Overview

Mita provides the possibility to create HTTP resources. If the configuration and implementation provided by the Mita implementation are insufficient for a certain purpose, it is recommended to make adapting changes in the generated C\-code.

The HTTP implementation in Mita is based on the ServalStack C Library, which is included in the XDK SDK. It contains modules for a range of application layer protocols that are used on embedded systems (as seen in the following picture).

Image

This section will demonstrate the Mita HTTP API. In Mita, HTTP is defined as a many resource. That means, multiple instances of this resource can exist, and each is given a unique name by the developer. All possible configuration items and signals for the HTTP resource are listed below. The use of the configuration items and signals will be explained in subsequent chapters.

connectivity many HttpRestClient {
    generator "org.eclipse.mita.platform.xdk110.connectivity.RestClientGenerator"
    validator "org.eclipse.mita.platform.xdk110.connectivity.RestClientValidator"

    /**
     * The underlying transport connectivity we use to send the data out. In the future we might also
     * support LoRa here.
     */
    required configuration-item transport : WLAN

    /**
     * The part of the endpoint URL common to all requests, e.g. "http://foobar.com/api/v1"
     */
    required configuration-item endpointBase : string

    /**
     * A custom header which is added to each HTTP request. Example:
     *   "X-Auth: MySecretToken\nX-Version: 1.0"
     */
    configuration-item headerContent : string

    signal resource(endpoint : string, contentType : string = "application/json", writeMethod : HttpMethod = HttpMethod.POST, readMethod : HttpMethod = HttpMethod.GET) : string

}

Implementation

Setup

HTTP requires a network connection to the destination server, to which the HTTP requests are sent. With the XDK, this network is usually established using Wi-Fi. The following code can be used to create a WLAN resource for use with HTTP:

NOTE: Between version 3.4 and 3.5 the syntax spelling has been corrected from authentification to authentication

setup wifi : WLAN {
  authentication = Personal(psk = "myPassword");
  ssid = "mySSID";
}

For a Wi-Fi configuration that goes beyond a simple WPA connection, please visit the Wi-Fi guide.

Setting up HTTP resources

All HTTP resources are generally set up with an endpointBase and a transport. The first configuration-item is a full URL, pointing to a desired endpoint base, such as http://www.my-backend.com:80. The configuration-item transport is the Wi-Fi resource, through which the HTTP messages are sent.

The following code can be used to create an HTTP resource:

setup googleRoot : HttpRestClient {
    transport = wifi;
    endpointBase = 'http://www.google.com:80';
    var root = resource('/');
}

Please note: The endpoint URL must be a fully qualified address, including the protocol (For HTTP, it should always be http://) and the port, as shown above.

Setting up variable resource-signals

In the above example, root is a variable of type resource. This variable is a so-called signal, an HTTP instance can have multiple resource signals. For example, given a backend-api located at www.my-server.com:8080/api, and the resources light and temperature, the following code would initialize an HTTP instance with the specified endpoints as resource-signals:

setup myServer : HttpRestClient {
    transport = wifi;
    endpointBase = 'http://www.my-server/api';
    var light = resource('/light');
  var temperature = resource('/temperature');
}

Every read/write operation on one of the signals will only send HTTP messages to either www.my-server/api/light or www.my-server/api/temperature.

So far, the resource-signals have been initialized with default settings (apart from the endpoint). They have the following optional parameters (and default values):

  • contentType, of type string. This defines the content-type header of the HTTP message. Per default, this is "application/json"
  • writeMethod, of type HttpMethod. This defines which HTTP Method (GET, POST, PUT, DELETE, UPDATE) is used when the signal is accessed using the write method. Per default, this is HttpMethod.POST.
  • readMethod, of type HttpMethod. This defines which HTTP Method (GET, POST, PUT, DELETE, UPDATE) is used when the signal is accessed using the read method. Per default, this is HttpMethod.GET.

The following code demonstrates how the optional parameters can be set:

setup myServer : HttpRestClient {
    transport = wifi;
    endpointBase = 'http://www.my-server/api';
    var light = resource('/light', 'text/plain', PUT, GET);
}

Performing Requests

Assuming that the following HTTP resource has been previously set up:

setup myServer : HttpRestClient {
    transport = wifi;
    endpointBase = 'http://www.my-server/api';
    var helloWorld = resource('/helloWorld');
}

Then the following code will send a POST request (the default write method for resource-signals) to www.my-server/api/helloWorld every 5 seconds, with a JSON payload.

every 5 seconds {
  myServer.light.write('{"hello": "world"}');
}

The input must always be a string.

Note: The .read() functionality for resource-signals is not yet implemented.

Settings

Headers

For an HTTP resource, additional headers can be set using the optional configuration-item headerContent. The code below is an example for setting the headers:

  • X-Auth: MySecretToken
  • X-Version: 1.0

For messages which are sent using the specifically setup HTTP resource:

setup myServer : HttpRestClient {
    transport = wifi;
    endpointBase = 'http://www.my-server/api';
  headerContent = 'X-Auth: MySecretToken\nX-Version: 1.0';
    var light = resource('/light');
}

All headers are inserted using a single string, where the headers are separated using the character \n. Keep in mind that every request on that particular HTTP resource will serialize those headers. As such, it is not recommended to use headers such as the Range header.

Currently, specific headers for individual HTTP requests are not implemented.

Full Code Example

package main;
import platforms.xdk110;

setup wifi : WLAN {
  authentication = Personal(psk = "myPassword");
  ssid = "mySSID";
}

setup server : HttpRestClient {
  transport = wifi;
  endpointBase = 'http://www.my-server/api';
  var root = resource('/', 'text/plain', POST);
}

every 5 seconds {
  server.root.write("myMessageToPost");
}