How to make API calls?

For our example, we have implemented a mock server which just returns the current time when we call the API. We need to define our request and response types to make an API call. Let's look at our types in src/Types.purs

data TimeReq = TimeReq
newtype TimeResp = TimeResp
  { code :: Int
  , status :: String
  , response :: String
  }

Here, our request type is just a constructor called TimeReq whereas our response type is TimeResp which is an object and the fields are:

  • code - HTTP Status code
  • status - Success or Failure
  • response - Our actual expected response

Understanding the instance:

If you notice, after the type declarations we have an instance defined. This is the instance which describes how our API call is implemented.

instance getTimeReq :: RestEndpoint TimeReq TimeResp where
  makeRequest _ headers = defaultMakeRequest_ GET "http://localhost:3000/time" headers
  decodeResponse body = defaultDecodeResponse body
  • Method: GET
  • URL: http://localhost:3000/time
  • Headers: headers

How about POST requests?

If we come a bit down, we can find another set of types defined:

data UpdateReq = UpdateReq String String
newtype UpdateRes = UpdateRes
  { code :: Int
  , status :: String
  , response :: Array String
  }

And its instance is defined as:

instance makeUpdateReq :: RestEndpoint UpdateReq UpdateRes where
  makeRequest reqBody headers = defaultMakeRequest POST "http://localhost:3000/update" headers reqBody
  decodeResponse body = defaultDecodeResponse body
  • Method: POST
  • URL: http://localhost:3000/update
  • Headers: headers
  • Request body: reqBody

So far we have only defined what should happen when we call the API, but we haven't performed the API call yet.

Let's look at how to do that for our first GET request. In src/Main.purs, if we look at addTodoFlow

resp <- callAPI (Headers []) TimeReq

We use a method provided by Presto which is callAPI that takes the required headers with the required body/data as its argument. In our case, as we don't have a body for the API, we will just pass the request type i.e. TimeReq. Following is how we handle the response.

case resp of
  Left err -> appFlow (MainScreenError (show err))
  Right (TimeResp {response: scc}) -> appFlow (MainScreenAddTodo str scc)

Currently, we are not concerned with errors so our focus is on the Right of the response.

Right (TimeResp {response: scc}) -> appFlow (MainScreenAddTodo str scc)

We match the response to our expected type that is TimeResp and our expected response value is the variable scc. So now we send the Todo item value and the response string to the screen with a different constructor and call the appFlow again.

POST Request with Headers

Similarly, for our other API call which is a POST request, the usage is defined in updateTodoFlow

updateTodoFlow str id = do
  resp <- callAPI (Headers [Header "Content-Type" "application/json"]) (UpdateReq str id)
  case resp of
    Left err -> appFlow (MainScreenError (show err))
    Right (UpdateRes {response: str}) -> appFlow (MainScreenUpdateTodo str)

In this request, we have two components:

  • Header: defined as Headers and an array of individual Header
  • Request body: defined as UpdateReq str id

What happens when we encounter an error from the API for some reason? We will discuss this in our next chapter.

results matching ""

    No results matching ""