In this article, we are going to cover the HTTP services support in the Ballerina programming language (Swan Lake release). We will be looking at the basics of creating an HTTP service, and then see how the Ballerina language provides a convenient abstraction for defining complex operations as well.
Anatomy of an HTTP Service
A Ballerina service’s structure and its semantics are defined by the type of the service, i.e. the type of listener attached. Let’s take a look at how a basic HTTP service is structured in Ballerina.
- Service name: The service name represents the base path of the HTTP service. This is an optional value, where if it’s kept empty, the base path defaults to the value “/”.
- Listener object: Provides an instance of http:Listener to bind to a specific host/port.
- Resource: A resource represents a specific subpath that can be accessed in relation to the service base path.
- Accessor: The HTTP method used to access the resource. These can be any HTTP method: e.g. “get”, “put”, “post”, “delete”. Only a single accessor can be associated with a single resource. If there is a requirement of supporting multiple HTTP methods to a single resource, we can define distinct service resources with the same name and different accessors. The special accessor “default” can be used in order to dispatch all the requests with the resource path, regardless of the HTTP method.
- Name: The name represents the path of the resource in relation to the service base path. This can be provided hierarchical values as well, e.g. “foo/bar”. In this case, the final path to this resource would be “/base/foo/bar”. The special name “.” is used to represent the service itself in a resource. Thus, requests which are directly sent to the base path will be dispatched to this resource.
- Return type: This is an optional return type, which can be of type anydata or http:Response. An anydata return value would be returned with an HTTP status code 200 OK.
The full source code for the above hello service is shown below.
The execution of the service and its invocation is shown below.
Hierarchical resources in HTTP services are defined by providing the hierarchical path of the resource as the resource name. The path segments are separated using “/”. The following example shows how the path “/base/foo/bar” is represented in an HTTP service resource.
Resource path segments can be defined with parameters as well, in a similar way we define function parameters. This is done with the syntax [<type> <name>] in the path segment. The parameter type must be one of the types: int, string, float, boolean, decimal. Using this functionality, path parameters for the HTTP resource can be defined. Example usage of this is shown below.
There can be multiple resource path segment parameters, and they can be mixed and located anywhere with general path segments.
A resource path rest parameter can be used in order to represent zero or more path segments. An example of this is shown below.
This functionality can also be generally used in a situation where we want to dispatch all requests coming to a certain base path and its subpaths. This can be accomplished by having a [string… paths] resource path rest parameter. An example of this scenario is shown below.
In a resource function, the query parameters are represented using the resource function parameters. The parameter type must be one of the types: int, string, float, boolean, decimal. The name of the parameter represents the query parameter name. An example of this functionality is shown below.
Payload Data Binding
The HTTP service resource payloads can be directly data bound to the resource function parameters. In order to distinguish between query parameters and resource payload parameters, the parameters which represent the resource payload are annotated with @http:Payload. The supported parameter types are string, json, xml, byte, record types, and record array types.
Extended Request/Response Access
The service resources have the functionality of manually handling request and response data without binding them to resource parameters or the return value. This is done by optionally taking in http:Caller and http:Request typed parameters, which represent the calling remote client and the current request information respectively.
The http:Caller contains functionality to interact with the remote client, such as responding back to the client using the respond remote method. The http:Request object contains operations to look up information regarding the current incoming HTTP request, such as the request payload, query/matrix parameters, cookies, and headers.
The following example demonstrates this functionality in action.
Using this approach, we can also execute additional logic even after the response is sent back to the client. For example, in the case of a network issue in responding back to the client, we can do custom operations for failure-recovery, or do extended logging operations.
The respond remote method also takes in an http:Response object if we need more finer control in the response, such as setting the status code or override the default content type. The below code snippet shows how we can send an HTTP 202 (Accepted) status code from our response.
Multipart Message Handling
As similarly used in the HTTP client API, multipart messages can be created in service resources by using the Multipurpose Internet Mail Extensions (MIME) standard. Using the http:Response object, we can provide MIME entity values to create single or multi-part HTTP messages.
A MIME entity in Ballerina is represented using the mime:Entity object. The following code shows how to set a text payload in the response using a mime Entity.
The code above explicitly creates the MIME entity and sets it in the HTTP response. The same operation happens if we use the setTextPayload method in the http:Response object. These functions are effectively helper functions to set the MIME entities in the HTTP response for often-used content types.
A multipart message can be created by setting the body parts in the mime:Entity object using the setBodyParts method. This method takes in an array of mime:Entity objects, and also optionally the content type of the enclosing entity, where the default is set to multipart/form-data. If required, we can override this with other multipart values such as multipart/mixed, multipart/alternative, and multipart/related.
The following example shows how a multipart/mixed message is created using plain text content and an image file as an attachment.
Here, the setContentDisposition method in the mime:Entity object is used to set the content disposition of the entity. This provides information on how the recipient should handle the data. For example, if it should be displayed inline, treated as form data, or downloaded as an attachment.
The HTTP listener can be configured to enable transport security in order to restrict to HTTPS clients for communication. This is done by providing an optional ListenerConfiguration instance when creating the http:Listener client and providing the secure socket configurations. The following example shows how an HTTPS service is configured.
In this article, we took a look at the HTTP services functionality available in the Ballerina programming language. It provides an easy-to-use abstraction in mapping the HTTP functionalities to services and resources. In this manner, the developer can mainly concentrate on the business logic, rather than spending time on boilerplate code for transport-specific functionality. For more in-depth information on the HTTP APIs, check out the Ballerina API documentation for the HTTP module.
Also, quick examples of Ballerina features can be found in Ballerina by Example.