Fetching Data in ReasonML Pt. 1

Understanding the basics

Introduction

Most applications we build, need to interact with a server at some point. Fetching data from and sending data back to an endpoint is a common task we encounter when writing an app.
In this short tutorial we will learn how this can be accomplished in ReasonML.

  1. Understand how to encode/decode data

Fetching Data Example

For the following tutorial we will use an API endpoint served via http://localhost:3000/users. Our initial users structure is as follows:

{
"users": [
{
"id": 1,
"name": "User A"
},
{
"id": 2,
"name": "User B"
},
{
"id": 3,
"name": "User C"
}
]
}
type user = {
id: int,
name: string,
};
type state =
| NotAsked
| Loading
| Failure
| Success(list(user));
module Decode = {
let user = user =>
Json.Decode.{
id: field("id", int, user),
name: field("name", string, user),
};
};
module Decode = {
// ...
let users = json : list(user) => Json.Decode.list(user, json);
};
let url = "http://localhost:3000/users";
let fetchUsers = () =>
Js.Promise.(
Fetch.fetch(url)
|> then_(Fetch.Response.json)
|> then_(json =>
json |> Decode.users |> (users => Some(users) |> resolve)
)
|> catch(_err => resolve(None))
);
type option(‘a) = None | Some(‘a);
type action =
| LoadUsers
| LoadedUsers(list(user))
| LoadUsersFailed;
let component = ReasonReact.reducerComponent("FetchComponent");
let make = _children => {
...component,
initialState: () => NotAsked,
};
reducer: (action, _state) =>
switch (action) {
| LoadUsers =>
ReasonReact.UpdateWithSideEffects(
Loading,
(
self =>
Js.Promise.(
fetchUsers()
|> then_(result =>
switch (result) {
| Some(users) =>
resolve(self.send(LoadedUsers(users)))
| None => resolve(self.send(LoadUsersFailed))
}
)
|> ignore
)
),
)
| LoadedUsers(users) => ReasonReact.Update(Success(users))
| LoadUsersFailed => ReasonReact.Update(Failure)
},
| LoadUsers =>
ReasonReact.UpdateWithSideEffects(
Loading,
(
self =>
/* ... */
),
)
self =>
Js.Promise.(
fetchUsers()
|> then_(result =>
switch (result) {
| Some(users) => resolve(self.send(LoadedUsers(users)))
| None => resolve(self.send(LoadUsersFailed))
}
)
|> ignore
)
render: self =>
switch (self.state) {
| NotAsked =>
<div>
(str("Click to start load Users"))
<button onClick=(_event => self.send(LoadUsers))>
(str("Load Users"))
</button>
</div>
| Loading => <div> (str("Loading...")) </div>
| Failure => <div> (str("Something went wrong!")) </div>
| Success(users) =>
<div>
<h2> (str("Users")) </h2>
<ul>
(
users
|> List.map(user =>
<li key=(string_of_int(user.id))>
(str(user.name))
</li>
)
|> Array.of_list
|> ReasonReact.array
)
</ul>
</div>
},

Summary

We should have a basic understanding of how to fetch data via ReasonML now. In part 2 we will try to understand how we to create or update and delete data.

Links

bs-fetch

Focusing on quality. Software Development. Product Management.