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

partial-promise-proxy

v1.0.6

Published

Combines a partially defined object with a function that returns a promise of the rest of the partial object.

Downloads

15

Readme

partial-promise-proxy

npm version Build Status

Combines a partially defined object with a function that returns a promise of the rest of the partial object. Any properties defined in the initial partial object will be available immediately, while other properties will wait for the resolution of the promise. (credit goes to @brysgo for the idea)

Install

yarn add partial-promise-proxy

Or using npm

npm install --save partial-promise-proxy

Usage

function partialPromiseProxy(partialObject, partialFunc)

Arguments

  • partialObject: a javascript object that consists of the properties that should be available immediately
  • partialFunc: a function that returns a promise for the remaining properties of the object

Why would you ever want to do this?

When building out a GraphQL API that wraps a set of legacy services, its not uncommon to end up with a scenario that looks like this:

const Address = new GraphQLObjectType({
  name: "address",
  fields: {
    country: { type: GraphQLString },
    city: { type: GraphQLString },
    streetName: { type: GraphQLString },
    streetNumber: { type: GraphQLString }
  }
});

const Customer = new GraphQLObjectType({
  name: "customer",
  fields: {
    id: { type: new GraphQLNonNull(GraphQLID) },
    firstName: { type: GraphQLString },
    lastName: { type: GraphQLString },
    address: { 
      type: Address,
      resolve: (customer, _, context) => {
        const { legacyAddressService } = context;
        const { id } = customer;
        return legacyAddressService.getAddress(id);
      } 
    }
  },
});

const customerSchema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'query',
    fields: {
      GetCustomer: {
        type: Customer,
        resolve: (_, args, context) => {
          const { legacyCustomerService } = context;
          const { id } = args;
          return legacyCustomerService.getCustomer(id);
        }
      }
    }
  })
});

In this instance, there is a Customer type with a nested Address type, where the resolution of both rely on different back-end systems. When resolving a query against Customer and Address, GraphQL will execute the call to the legacyCustomerService, but wait on the response before calling the legacyAddressService. Both legacy services only require the customer id argument passed in to getCustomer on the root query, so why can't we call both without waiting?

Because GraphQL can handle resolvers that return either the value or a promise of the value, we can create a partial proxy to the requested type where some fields resolve to their values, while some resolve to a promise which GraphQL will wait for.

Changing the code above to use a partial-promise-proxy allows both legacy service calls to execute without waiting:

import { partialPromiseProxy } from "partial-promise-proxy";

const Address = new GraphQLObjectType({
  name: "address",
  fields: {
    country: { type: GraphQLString },
    city: { type: GraphQLString },
    streetName: { type: GraphQLString },
    streetNumber: { type: GraphQLString }
  }
});

const Customer = new GraphQLObjectType({
  name: "customer",
  fields: {
    id: { type: new GraphQLNonNull(GraphQLID) },
    firstName: { type: GraphQLString },
    lastName: { type: GraphQLString },
    address: { 
      type: Address,
      resolve: (customer, _, context) => {
        const { legacyAddressService } = context;
        const { id } = customer;
        return legacyAddressService.getAddress(id);
      } 
    }
  },
});

const customerSchema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'query',
    fields: {
      GetCustomer: {
        type: Customer,
        resolve: (_, args, context) => {
          const { legacyCustomerService } = context;
          const { id } = args;
          return partialPromiseProxy({ id }, () => legacyCustomerService.getCustomer(id)); // <-- wrap the promise in a partial proxy
        }
      }
    }
  })
});

Passing in { id } to the partialPromiseProxy creates a proxy object where id will be available immediately, while any other properties that are accessed will return a promise that GraphQL will wait to resolve.