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:

  • The function get_post/1 takes a PostId as an argument, constructs a URL, and sends a GET request to the API.
  • The httpc:request/4 function is used to send the GET request. The [] represents any headers or other options that may be needed, which is empty in this case.
  • The response body is converted to binary and printed to the console.

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:

  • The create_post/1 function sends a POST request with JSON data to the API.
  • The Headers specify that the content type is application/json.
  • The Body is created by converting the PostData (which is passed to the function) into a JSON string using the post_data_to_json/1 helper function.
  • The jsx:encode/1 function is used to encode an Erlang map as a JSON string. This requires the jsx library, which you can install from Erlang’s package manager.

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.

author-avatar

About Hammad

Hi, I am a senior web and mobile developer having 4+ years of experience in this field. I have built various websites using different frameworks and languages like Erlang, ROR, React, Nodejs, Angular, JavaScript, PHP, Laravel, Python, Django, CMS websites, etc. I also have a strong knowledge of the elixir, AWS as well. I also have an expert level of experience in mobile app technologies like Flutter, react native, and Swift. If you want to work with me send me a quick message so that we can discuss your tasks and work accordingly.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments