npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

post-office

v0.3.2

Published

A toolkit which provides a strongly-typed message mapping to internal service calls.

Downloads

88

Readme

Post Office Logo

NPM Version NPM Downloads

A toolkit which provides a strongly-typed message mapping to internal service calls.

What's the point?

The idea behind post-office is to allow application developers to work with strongly-typed messages and focus on service-level implementation code. Post Office was inspired by the idea of Data Transfer Objects.

For example, consider a service to save a User. A current implementation with no service layer may look like this:

app.post('/users', function(req, res, next) {

  // validation logic...
  // sanitization logic

  // Begin "Service-ish Code"

  User
    .exists(req.body.email, function(err, exists) {
      if (err) {
        return next(err);
      }

      if (exists) {
        return next(new Error('User exists'));
      }

      User
        .create({
          name: req.body.name,
          email: req.body.email,
          address: req.body.address
        })
        .save(function(err, user) {
          if (err) {
            return next(err);
          }

          res.status(201).json({user:user});
        });
    });
});

There are a lot of reasons why this code is less than optimal. For one, this is far from unit-testable. Another is the mixing of different logics such as parsing, validation, and sanitization. Finally, any changes to what should be returned for a user need to be reimplemented on every method that returns a user. The issues quickly become apparent as the project grows in size.

Ideally, I should be able to break down my service code into a very simple collection of methods. This is where the idea of message-based design really shines. In message-based design, you write services that will accept a plain object, and will return some kind of plain object. This object will be verified to look a certain way before entering the service layer, and will be verified to look a certain way when leaving the service layer. Here is an example of the same scenario implemented by a user service with message-based design:

// Example User Service

exports.saveUser = function(msg) {
  return User
    .exists(msg.email)
    .then(function(exists) {
      if (exists) {
       throw new Error('User exists');
      }
    })
    .then(function() {
      return User.create({
        name: msg.name,
        email: msg.email,
        address: msg.address
      });
    })  
    .then(function(user) {
      return {user: user};
    });
};

As you can see: no more req, res, or next. Testing this code is much more straight forward. Errors are simple. We just worry about the business logic, and we let some magic do the rest (mapping, validation, error handling, etc). Post Office aims to be some magic. It is a toolkit that allows you to build "strongly-typed" messages (it's javascript so "strongly-typed" has a somewhat different meaning here) for your services.

Quick Example

var app = require('express')();
var postOffice = require('post-office');
var PropTypes = postOffice.PropTypes;

// 1. create a container

var c = postOffice.createContainer();

// 2. make request envelope

var saveUserEnv = postOffice.createEnvelope({
  name: PropTypes.string,
  email: PropTypes.string,
  favoriteNums: [PropTypes.int]
});

// 3. make response envelope

var saveUserResponseEnv = postOffice.createEnvelope({
  name: PropTypes.STRING,
  email: PropTypes.STRING,
  favoriteNums: [PropTypes.INT],
  updatedBy:PropTypes.INT
});

// 4. implement service code

var saveUser = function(msg) {
  // do some magic to save user

  return Promise.resolve({
    name: msg.name,
    email: msg.email,
    id: 1,
    updatedBy: 12345
  });
};

// 5. tie it together and build expressjs handler

app.post('/users', c(saveUserEnv, saveUser, saveUserResponseEnv).status(201).json());

/**
 * POST /users { "name": "Tyler", "email": "[email protected]", "favoriteNums": [22, "33"] }
 *
 * Response: { "name": "Tyler", "id": 1, "email": "[email protected]", "favoriteNums": [22, 33], "updatedBy": 12345 }
 */

Documentation

Learn more on the wiki.