Hi, I'm Jonas Galvez, an engineer at STORED.

I'm Jonas Galvez, a JavaScript and Go engineer at STORED e-commerce.

I'm an eternal student of distributed systems and practitioner of minimalism.

I build and deploy my stuff with Vue, Nuxt, Go and Kubernetes nowadays. This is the scope of the articles published here.

I am driven by purpose and cultivate a stoic attitude towards life.

Isomorphic Fetch Notes

This article is also available in Brazilian portuguese.

After working on two Vue projects in a row, I am now working on my first server-side rendered, or, isomorphic, React project. Relearning React has been a blessing – I have now accumulated enough real world experience that I can exercise a more informed opinion when choosing React Native or sticking to Weex (Vue Native) down the road. It's also been challenging – we spent two weeks just reading articles and playing with a few different boilerplates – we knew we wanted to try server-side rendering for this application, just didn't know where to start.

We eventually settled on react-starter-kit. Once we were done playing with it, we removed it completely from our repository and started readding bit by bit, carefully researching and making sure we understood what was going on. Since we branched off it, it's gotten a few updates to the build system and an upgrade to Webpack v3 – so it's clear it's actively developed and a safe choice for anyone starting with this today.

We didn't do much beyond switching to Koa and restructuring where view components are kept. One of the things we did move away from was its fetch wrapper, supplied in the application context object. We wanted a universal interface to fetch that allowed us to use it on the client-side as well as for talking to multiple microservices on the backend.

After engaging in a brief refactoring battle with a colleague, we arrived at an implementation we're particularly happy with. We introduced a helpers/network module which provides a makeClient() function. We export its generated wrapper function through a localized client module wherever needed, so we have multiple files like this across our codebase:

import { makeClient, defaultHeaders } from 'helpers/network' import { MICROSERVICE_HOST } from 'constants/env' export default makeClient(MICROSERVICE_HOST, defaultHeaders)

Notice we import MICROSERVICE_HOST from constants/env. We have really adhered to eliminating magic strings, and having defaults set through constants fit right into the mindset.

As for the interface, we moved away from fetch's original API and supplied constants representing each HTTP method, to be used in a signature like (path, method, params). We compromised on forcing headers to be set at makeClient(), so further calls are simplified – and making JSON encoding of supplied POST data implicit. The returned wrapper also takes care of checking the response status code, and returning it along with the parsed JSON response. This enabled us to write API proxy methods like this:

import { GET, POST } from 'helpers/network' import client from './client' export default { someMethodWithGET: async (ctx, next) => { const res = await client('some/method/with/GET', GET) ctx.status = res.status ctx.body = res.data }, someMethodWithPOST: async (ctx, next) => { const res = await client('some/method/with/POST', POST, ctx.json) ctx.status = res.status ctx.body = res.data } }

Find the full source code on GitHub. Special thanks to my colleague Jan Cássio for refactoring this endlessly with me (and eventually convincing me a functional approach was better when my first attempt was a HTTPClient class).