@ianwremmel/tracks-interactor

Codify your business logic

Usage no npm install needed!

<script type="module">
  import ianwremmelTracksInteractor from 'https://cdn.skypack.dev/@ianwremmel/tracks-interactor';
</script>

README

tracks-interactor (@ianwremmel/tracks-interactor)

license standard-readme compliant npm (scoped) npm

Dependabot badge semantic-release

CircleCI

Codify your business logic

Inspired by the Interactor gem, this library provides a pattern for encapselating business logic into small, testable units.

Table of Contents

Install

npm install @ianwremmel/tracks-interactor

Define your interactor. You'll need to tell it about the shapes of the data it will accept and produce. Then, you'll need to define call, which does the interactor's work. call accepts a Context<T> and returns a Context<R>. (In the following example, T is AuthToken and R is Model<User>).

import {Interactor} from 'interactor';

type AuthToken = string;
type User = Model<User>;

class Authorize extends Interactor<AuthToken, User> {
    call() {
        const user = await User.findByToken(this.context.data);
        if (!user) {
            this.context.fail('could not find user for specified token');
        }
        return user;
    }
}

Then, use interact to invoke your Interactor (e.g., in an express route).

import {Authorize} from './interactors/authorize';
import {interact} from 'interactor';
import express from 'express';

const router = express.Router();

router.use(async (req, res, next) => {
    const context = await interact(
        Authorize,
        new Context(req.headers.authorization)
    );

    if (context.failure) {
        next(401);
    }
});

router.get('/account', (req, res) => {
    res.render('account');
});

Differences from the Interactor Gem

  • The gem invokes a given Interactor via its static call method. TypeScript doesn't make type arguments visible to static methods, so we use the bare method interact as a stand-in for Interactor.call().
  • after, before, and around don't exist. A previous version of this library included them, but having not used that portion of the library for over a year, they're continued maintencance didn't seem worth it.Î
  • Organizers don't exist. A previous version of this library included them, but having not used that portion of the library for over a year, they're continued maintencance didn't seem worth it.

Breaking Changes

  • A previous version of this package expected a services object to be passed to interact. You should just put your services on the context.

    Instead of

    interact(services, MyInteractor, {...args});
    

    do

    interact(MyInteractor, {services, ...args});
    

Maintainer

Ian Remmel

Contribute

PRs Welcome

License

MIT © Ian Remmel 2019 until at least now