4

The code is from the IPFS (Inter-planetary file-system) HTTP API JS implementation: https://github.com/ipfs/js-ipfs-api/blob/master/src/api/add.js

'use strict'

const Wreck = require('wreck')

module.exports = (send) => {
    return function add(files, opts, cb) {
        if (typeof(opts) === 'function' && cb === undefined) {
            cb = opts
            opts = {}
        }
        if (typeof files === 'string' && files.startsWith('http')) {
            return Wreck.request('GET', files, null, (err, res) => {
                if (err) return cb(err)

                send('add', null, opts, res, cb)
            })
        }

        return send('add', null, opts, files, cb)
    }
}

The function being described is the add() function, used to push data to IPFS.

I'll start by explaining what I do understand: the add() function takes three arguments – if there is no options object (the user omitted it) and it's been replaced by a function: the user is trying to implement a callback function instead – change the callback to opts; cb = opts.

Secondly, if the cited file is a text file && starts with http – it's obviously hosted remotely and we need to fetch it using Wreck.

All of this I understand, but why are we using the (send) => arrow function? Why do we use return function add...? What's the send('add', null, opts, res, cb) and return send('add', null, opts, res, cb) used for? How is the callback (cb) implemented? Help me understand what's happening here

apologetic
  • 43
  • 3
  • This is just a factory function, producing other functions and calling them internally. It's not longer necessary with modules, but some people still cling to the pattern. – ssube May 27 '16 at 15:35
  • @ssube: It's being used to do dependency injection (`send` being the dependency being injected). How would modules make it unnecessary? (Genuine question.) – T.J. Crowder May 27 '16 at 15:49

1 Answers1

2

The whole thing being exported is a function, which expects send as an argument; this lets the calling code do dependency injection by passing in the send function to use. It's expecting to be used something like this:

let addBuilder = require("add");
let add = addBuilder(senderFunction);
// This function ----^
// is `send` in the `add.js` file.
// It does the actual work of sending the command

// Then being used:
add(someFiles, someOptions, () => {
    // This is the add callback, which is `cb` in the `add.js` file
});

(Frequently, the first two statements above are written as a single statement, e.g. let add = require("add")(senderFunction);)

Basically, the whole thing is one big builder for something that uses a given send function, which is injected into it by calling the builder. That way, it can be tested by injecting a testing version of send, and used for real by injecting a real version of send; and/or various "real" versions of send can be used in different environments, transport mechanisms, etc.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875