Custom fetch implementation for responses compressed with MessagePack::RackMiddleware

After the previous post, I have received some messages on how to use the responses passed through the custom middleware. So if you are not one of the guys using that middleware, this post is not for you. If you are, you’re in luck, keep reading.

The easiest approach, if you don’t have a lot of requests going to the compressed API, as some have suggested is to manually add the header to the request and uncompress it when you receive a response. But this can soon get tiring for multiple requests and needs a better way to handle this, especially since it’s so easy.

We can create a custom fetch that makes sure that this custom header is included in the request and parse the response if it is compressed. It has the same API as the native fetch, so it’s easy to get used to.

Depending on what browsers you target, you might not need bluebird, request-promise and whatwg-fetch. This is from a code from a nodejs app which does require the latter two.

import 'whatwg-fetch';
import Promise = require('bluebird');
import _ = require('lodash');
import msgpack = require('msgpack-lite');
import request = require('request-promise');

function nativeFetchJson(url: string, options: any = null): Promise<any> {
  return fetch(url, options).then(response => response.json());
}

export default function fetchJson(url: string, options: any = null): Promise<any> {
  const compressionEnabled = _.get(options, 'compressionEnabled');
  delete options.compressionEnabled;
  if (!compressionEnabled) { return nativeFetchJson(url, options); }
  return request.get(url,
    _.defaultsDeep({}, options, {
      headers: { 'x-messagepack-compression': true },
      resolveWithFullResponse: true,
      encoding: null
    }),
  ).then((response) => {
    if (response.headers['x-messagepack-compression'] !== 'true') { return JSON.parse(response.body); }
    return msgpack.decode(response.body);
  });
}

declare function fetch(url: string): Promise<any>;
declare function fetch(url: string, options: any): Promise<any>;

Comment below if you want me to do a version without all of the dependencies and I’ll give it a shot.

Published 28 Dec 2018

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter