Site icon FSIBLOG

How to Make a Simple REST Call in Erlang

How to Make a Simple REST Call in Erlang

How to Make a Simple REST Call in Erlang

In the world of software development, interacting with REST APIs is a routine task, especially when building distributed systems and microservices. Erlang, a language known for its scalability and concurrency, can also be used to make RESTful calls despite not having built-in support for HTTP requests. Fortunately, Erlang’s httpc module, part of the inets library, provides a powerful way to interact with web services over HTTP.

Prerequisites

Before diving into the coding example, make sure you have Erlang installed and ready to use. You will also need access to the inets application, which is included by default in most Erlang distributions.

To start using the HTTP client (httpc), you’ll first need to ensure that the inets application is started.

application:start(inets).

This line of code starts the necessary HTTP client service for making HTTP requests.

Making a Simple GET Request

The most common use of REST APIs is to retrieve data from an endpoint. In this example, we’ll make a simple GET request to a public API that provides placeholder data for testing purposes: JSONPlaceholder.

GET Request:

-module(rest_example).
-export([get_post/1]).

get_post(PostId) ->
    % Ensure the inets application is started
    application:start(inets),

    % Define the API URL with dynamic post ID
    URL = "https://jsonplaceholder.typicode.com/posts/" ++ integer_to_list(PostId),

    % Make the GET request
    {ok, Response} = httpc:request(get, {URL, []}, [], []),

    % Handle the response
    case Response of
        {ok, {{_, 200, _}, _Headers, Body}} ->
            % Convert body from list to binary format
            Body = list_to_binary(Body),

            % Print the body to console
            io:format("Response Body: ~s~n", [Body]);
        
        {ok, {{_, StatusCode, _}, _Headers, _Body}} when StatusCode /= 200 ->
            io:format("Error: Received non-200 status code ~p~n", [StatusCode]);
        
        _Error ->
            io:format("Error: Something went wrong~n")
    end.

Explanation:

Making a POST Request

While GET requests are used to retrieve data, POST requests are used to send data to a server. In this example, we will make a POST request to send a new post to the JSONPlaceholder API.

POST Request:

-module(rest_example).
-export([create_post/1]).

create_post(PostData) ->
    % Ensure the inets application is started
    application:start(inets),

    % Define the API URL
    URL = "https://jsonplaceholder.typicode.com/posts",

    % Set headers to indicate we are sending JSON data
    Headers = [{"Content-Type", "application/json"}],

    % Convert PostData to JSON format
    Body = post_data_to_json(PostData),

    % Make the POST request
    {ok, Response} = httpc:request(post, {URL, Headers, "application/json", Body}, [], []),

    % Handle the response
    case Response of
        {ok, {{_, 201, _}, _Headers, Body}} ->
            io:format("Post Created Successfully: ~s~n", [list_to_binary(Body)]);
        
        {ok, {{_, StatusCode, _}, _Headers, _Body}} when StatusCode /= 201 ->
            io:format("Error: Received non-201 status code ~p~n", [StatusCode]);
        
        _Error ->
            io:format("Error: Something went wrong~n")
    end.

post_data_to_json({Title, Body, UserId}) ->
    % Create a JSON string for the post data
    PostData = #{title => Title, body => Body, userId => UserId},
    % Convert the Erlang map to a JSON string
    jsx:encode(PostData).

Explanation:

You would call the create_post/1 function with a tuple like {Title, Body, UserId} to create a new post.

Example call:

rest_example:create_post({"New Post", "This is a new post content", 1}).

Parsing JSON Responses

When working with REST APIs, the data returned is often in JSON format. Erlang does not have built-in support for JSON, but there are external libraries like jsx or jiffy to handle this.

In the code above, we use jsx:encode/1 to encode Erlang data into JSON when making the POST request. To parse the JSON response received from a GET request, you can use jsx:decode/1.

Parsing JSON Response:

{ok, {{_, 200, _}, _Headers, Body}} ->
    Body = list_to_binary(Body),
    {ok, ParsedJson} = jsx:decode(Body),
    io:format("Parsed JSON: ~p~n", [ParsedJson]);

This will decode the JSON response body into an Erlang term (such as a list or map). You can then process the data as needed.

Handling Timeouts and Errors

When dealing with HTTP requests, it’s important to account for timeouts and handle errors appropriately. The httpc:request/4 function allows you to specify a timeout value.

Adding Timeout:

{ok, Response} = httpc:request(get, {URL, []}, [{timeout, 5000}], []),

This sets a 5-second timeout for the request. If the request doesn’t complete in that time, it will return an error.

Additionally, you should always handle errors using try-catch blocks to prevent crashes:

try
    {ok, Response} = httpc:request(get, {URL, []}, [], [])
catch
    error:Reason -> io:format("Error: ~p~n", [Reason])
end.

Conclusion

In this article, we have walked through the process of making both GET and POST REST calls in Erlang using the httpc module from the inets application. We also covered how to handle JSON data using external libraries like jsx, how to set timeouts, and how to gracefully handle errors.

By now, you should have a solid understanding of how to interact with REST APIs in Erlang and how to use this knowledge in your own projects. Whether you’re retrieving data from external services or sending data to a server, Erlang can handle RESTful communication efficiently.

Exit mobile version