Building a REST API with Ballerina's HTTP Listener and Resource Functions
Learn how to declare an http:Listener, attach a service, and define resource functions to handle REST endpoints, plus how to enable HTTP/2 and avoid common pitfalls.
08 Jul 2026, 09:23 UTC

Quick answer: expose a REST endpoint
To make a Ballerina program act as a REST server, you create an http:Listener bound to a port, attach a service to that listener, and write resource functions that match HTTP methods and paths. The listener handles the network I/O, the service groups related resources, and each resource function returns the response body (or a status code) for its matched request.
How the listener and service work
The following minimal example defines a listener on port 9090, a service at the base path /hello, and a GET resource that returns a plain‑text greeting.
import ballerina/http;
listener http:Listener ep = new(9090);
service /hello on ep {
resource function get sayHello returns string {
return "Hello, Ballerina!";
}
}
When the program runs, Ballerina creates a listener strand that accepts TCP connections, parses incoming HTTP/1.1 requests by default, and dispatches them to the first resource whose path and method match the request. The service declaration attaches the listener to a base path; all resources inside the service are resolved relative to that base.
Enabling HTTP/2
Ballerina’s listener uses HTTP/1.1 unless you explicitly turn on HTTP/2. Add the http2 attribute with a value of true when constructing the listener.
listener http:Listener ep = new(9090, {
http2: true
});
With HTTP/2 enabled, the same service code works unchanged; the listener will negotiate HTTP/2 with clients that support it, while still falling back to HTTP/1.1 for older clients.
Limits and common mistakes
- Missing
servicekeyword or misplaced listener. If you declare the listener but do not wrap resources in aserviceblock, Ballerina treats the resources as ordinary functions and never registers them with the listener, resulting in a silent service that does not respond. - Overlapping resource paths. Resource matching follows declaration order. A resource defined earlier with a broader pattern (e.g.,
/users/{id}) will shadow a later resource with a more specific pattern (e.g.,/users/admin) if the earlier pattern can also match the request. To avoid shadowing, order resources from most specific to most general, or use distinct base paths. - Blocking calls inside resource functions. Ballerina runs each request on a strand from a worker pool. A long‑running blocking operation (such as a synchronous file read or a blocking database call) ties up that strand, reducing concurrency and potentially exhausting the pool. Off‑load blocking work to a separate worker (
workerpool) or use non‑blocking I/O APIs. - Incorrect return types. A resource function must return a type that Ballerina can convert to an HTTP response (e.g.,
string,byte[],json, or a customhttp:Response). Returning an incompatible type or omitting a return statement causes a runtime error when the resource is invoked. - Listener version compatibility. The
listener http:Listener ep = new(port);syntax shown requires Ballerina 0.970.0 or later. Earlier releases used theendpointkeyword and a different configuration shape. Check your Ballerina version withbal versionbefore copying the snippet.
Practical verification steps
- Save the example code to a file named
hello.bal. - Build the program:
bal build hello.bal. - Run the executable:
bal run hello.bal. - From another terminal, test the endpoint:
curl -s http://localhost:9090/hello. You should see the textHello, Ballerina!printed. - To confirm HTTP/2, rebuild with the
http2: truelistener attribute, restart, and use a client that speaks HTTP/2 (e.g.,curl --http2 -s http://localhost:9090/hello). The response should be identical, indicating the listener accepted the HTTP/2 connection.
If the service does not respond, check the console output for error messages during startup; they often point to missing service blocks, port conflicts, or version incompatibilities.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.