Curry-request, a browser/node fetch wrapper

Aug 17, 2021

I don’t remember what my first AJAX call looked like,
probably I was using a Jquery function.
When some years later I saw fetch for the first time I thought it was just another wrapper, but it wasn’t, and from there on that became the standard for making browser http request.

Why curry-request, story about modularization

Usually, in any application that has to deal with APIs, you’ll build a service (a.k.a. module) that exposes functions which will be consumed by the application’s business logic.
In this service you will probably pull the API’s configuration from a separate file/env-variables;
if you use fetch directly in the methods you expose you will soon note a lot of duplications (especially dealing with REST interfaces).
curry-request helps you cope with this issue and increase the terseness and maintainability of your code.

With one curried function you can configure the http-client,
the order in which parameters have been arranged increase DRYness.

This is what the service could look like:

import cr from "curry-request"
// we place the web api base url & the base headers
const apiRequest = cr("https://jsonplaceholder.typicode.com")({
  "Content-Type": "application/json",
  Accept: "application/json"
})

const get = apiRequest("GET")
const post = apiRequest("POST")
const put = apiRequest("PUT")
const del = apiRequest("PUT")

// get                                                                                                                                                                                                                                    
export const getTodosById = (id) => get("/todos/" + id)()()                                                                                                                                                                            
export const getTodos = get('/todos')()
                                                                                                                                                                                                                                          
// post                                                                                                                                                                                                                                   
export const postTodo = (payload) => post("/todos")(payload)()                                                                                                                                                                         
                                                                                                                                                                                                                                          
// post                                                                                                                                                                                                                                   
export const putTodo = (id, payload) => put("/todos/" + id)(payload)()                                                                                                                                                                           
                                                                                                                                                                                                                                          
// delete                                                                                                                                                                                                                                 
export const deleteTodosById = (id) => del("/todos/" + id)()();

Notice how getTodos is not wrapping the actual function call, in these cases we’re just passing the reference to the returned function in a pointless fashion,
you can get creative in composing the function with this pattern.

Take a look at the playground for a quick demonstration.

What about Axios

Axios is currently the most used library for organizing http client services in JS apps,
it has its roots in the http-module used in Angular, but it makes some opinionated choices in how it transforms requests and responses that are quite radical for my taste.
Similarly to axios, with curry-request there is pattern for creating instances, and for feeding the token once it is available. Also, interceptors can be implemented accessing the underlying fetch implementation.
The main difference is that curry-request returns a fetch-response.

Fetch implementation

The fetch implementation used by default is cross-fetch (node-fetch for node and a whatwg-fetch for browser), but it can be switched if you prefer something else;
it is one of the arguments that can be passed to configuration.


I published this module some months ago but actually we’ve been using it in production for quite some time now,
it has worked well for me both for browser and node apps, hopefully you might gain some benefits from it too!
For any problems/questions open an issue on github.