4

I'm currently learning functional programming in JavaScript. I use ramda as a helper library to write helpers such as asyncPipe:

import { pipeWith, then } from 'ramda';

export const asyncPipe = pipeWith(then);

To log the user in I have to make an unauthenticated fetch request with a static url:

export const postRequest = route =>
  asyncPipe([
    body =>
        fetch(route, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
        }),
    getJSON,
]);

Now, since the url is static, I can curry this function and use it in a pipe like this:

export const login = asyncPipe([
    postRequest(ROUTE_LOGIN),
    prop('token'),
    setToken,
]); // Will get called with the correct body

So far so good. But now I have to make a request with a dynamic URL, and body and it needs to be authenticated, so I need headers. I'm struggling to write this code so that it is pipeable.

Here is what I tried:

export const postRequestWithAuth = route => body =>
  asyncPipe([
    getToken,
    token =>
        fetch(route, {
            method: 'POST',
            headers: { Authorization: `Token ${token}`, 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
        }),
    getJSON,
]);

But I can't figure out how you would use this with pipe or compose (async, of course) because the way I wrote it you would have to do:

postRequestWithAuth(ROUTE_HOUSES + uuid)(body)() whereas the last call is just to activate the asyncPipe. As you can see this is very messy and hard to pipe. How would you solve this in a functional way?

J. Hesters
  • 13,117
  • 31
  • 133
  • 249

1 Answers1

2

Here is a way to write your desired code, though it's not ramda.

import { pipe, fork, get } from 'rubico'

// expects the object { body: {...}, uuid: 'string' }
export const postRequestWithAuth = route => pipe([
  fork({
    method: () => 'POST',
    headers: pipe([
      get('uuid'),
      getToken,
      token => ({
        Authorization: `Token ${token}`,
        'Content-Type': 'application/json',
      }),
    ]),
    body: pipe([
      get('body'),
      JSON.stringify,
    ]),
  }),
  payload => fetch(route, payload),
  getJSON,
])

postRequestWithAuth('/myRoute')({
  uuid: 'ffda7b1c-fc6b-4949-98c4-e5cb86675f5f',
  body: { hello: 'world' },
})

I created rubico to express complex async situations like yours.

richytong
  • 2,387
  • 1
  • 10
  • 21
  • Why remove all the explanation, and the disclosure that `rubico` is your own library? – Bergi May 26 '20 at 21:45
  • rubico is no longer my own library – richytong May 26 '20 at 21:46
  • 1
    Moving it to an organisation is a good idea, but why remove the link instead of updating it? Also, you've started the library and still are the only contributor so far, you should take the credit. – Bergi May 26 '20 at 21:51
  • welllll now that you put it that way, i'll edit the post to put the new link! also i took out some explanation because I thought I sounded cringe – richytong May 26 '20 at 21:52