Back to integration tutorials
This tutorial helps you understand the basics of how Ballerina can be used to do client calls and develop RESTful APIs.
In this tutorial, you will develop a service that allows a user to retrieve a list of doctors based on the doctor's specialization (category). The information about the doctors is retrieved from a separate microservice.
To implement this use case, you will develop a REST service with a single resource using Visual Studio Code with the Ballerina Swan Lake extension and then run the service. The resource will receive the user request, retrieve details from the backend service, and respond to the user request with the relevant doctor details.
- REST API
- HTTP client
Develop the application
Step 1: Set up the workspace
Step 2: Develop the service
Follow the instructions given in this section to develop the service.
Create a new Ballerina project using the
balcommand and open it in VS Code.
$ bal new sending-a-message-to-a-service
Remove the generated content in the
main.balfile and open the diagram view in VS Code.
Generate a record type corresponding to the payload from the backend service by providing a sample of the expected JSON payload.
The payload from the backend service will be an array of JSON objects, where each JSON object will be similar to the following.
The generated record type will be as follows.
Note: While it is possible to work with the JSON payload directly, using record types offers several advantages including enhanced type safety, data validation, and better tooling experience (e.g., completion).
Note: When the fields of the JSON objects are expected to be exactly those specified in the sample payload, the generated records can be updated to be closed records, which would indicate that no other fields are allowed or expected.
Define the HTTP service (REST API) that has the resource that accepts user requests, retrieves relevant details from the backend service, and responds to the request.
Open the Ballerina HTTP API Designer in VS Code
/healthcareas the service path (or the context) of the service, which is attached to the listener listening on port
Define an HTTP resource that allows the
GEToperation on the resource path
/doctorsand accepts the
categorypath parameter (corresponding to the specialization). Use
http:InternalServerErroras the response types.
The generated service will be as follows.
The generated code will be as follows.
Implement the logic to retrieve and respond with relevant details.
log:printInfostatement logs information about the request.
The call to the backend is done using a remote method call expression (using
->), which distinguishes network calls from normal method calls. Client data binding is used to directly try and bind the JSON response on success to the expected array of records.
ischeck to decide the response based on the response to the backend call. If the backend call was successful and the response payload was an array of
Doctorrecords (as expected), then directly return the array from the resource.
If the backend call fails, send an
http:NotFoundresponse if the client call failed with a
4xxstatus code or send an
http:InternalServerErrorresponse for other failures.
You have successfully developed the required service.
The sequence diagram view for the implemented resource method is the following.
Step 3: Build and run the service
Note: Alternatively, you can run this service by navigating to the project root and using the
sending-a-message-to-a-service$ bal run Compiling source integration_tutorials/sending_a_message_to_a_service:0.1.0 Running executable
Step 4: Try out the use case
Let's test the use case by sending a request to the service.
Start the backend service
Download the JAR file for the backend service, and execute the following command to start the service:
$ bal run hospitalservice.jar
Send a request
Use the Try it feature to send a request to the service. Specify
surgery as the path parameter.
Verify the response
You will see the response message from the backend with a list of details of the available doctors.
Now, check the terminal in which you ran the Ballerina service. You should see a log similar to the following.
time = 2023-08-15T13:01:34.022+05:30 level = INFO module = integration_tutorials/sending_a_message_to_a_service message = "Retrieving information" specialization = "surgery"
Step 5: Write tests for the use case
Let's test the use case by writing a test case that sends a request to the service and validates the payload for a successful request. Testing is enabled by the Ballerina test framework.
queryDoctorEPinitialization in the source code to use a separate function that can be mocked.
http:Clientobject to send requests to the healthcare service.
Define a variable with mock payload from the backend service. This variable will be used to mock the payload from the backend and to verify the received payload
Mock the backend service by mocking the
http:Clientobject and the
getresource method. Then, mock the
initializeHttpClientfunction, using the
@test:Mockannotation, to return the mock HTTP client.
@test:Configannotation to indicate that a function is a test function. Implement the test to send a request to the service and test for value equality between the retrieved payload and the expected payload using the
Run the tests.
Alternatively, you can run all the tests in a package by navigating to the project root and using the
sending-a-message-to-a-service$ bal test Compiling source integration_tutorials/sending_a_message_to_a_service:0.1.0 Running Tests sending_a_message_to_a_service time = 2023-08-17T09:01:23.758+05:30 level = INFO module = integration_tutorials/sending_a_message_to_a_service message = "Retrieving information" specialization = "surgery" 1 passing 0 failing 0 skipped
You have now developed and tested a simple Ballerina REST service, which receives a request, logs a message, sends a request to a backend service, and responds to the original request with the response from the backend service.
Check out the complete implementation on GitHub.