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

apollo-idor

v1.0.3

Published

Apollo Server schema directive to create opaque ID values

Downloads

6

Readme

apollo-idor

Apollo Server schema directive to create opaque ID values.

Why

Using sequential integers as primary keys for database objects is a common pattern that makes database design simpler. It's a good practice to obfuscate these keys from users to help avoid security issues.

indirectDirectiveTransformer() makes the transformation from private values to public values transparent at the GraphQL layer. GraphQL clients see opaque strings for object IDs, while GraphQL resolvers see the private integers that are stored in the database. Opaque values are encoded with a type to ensure they can only be used to reference a specific type.

This strategy helps:

  • ID values for objects of different types are different strings even if the underlying database keys are the same
  • GraphQL clients cannot manipulate the opaque strings
  • per-user context settings can be used to create opaque values that are specific to a user

Usage

npm add apollo-idor
# typeDefs.graphql
directive @indirect(
  type: String
  scope: String = "PUBLIC"
  raw: Boolean = false
) on ARGUMENT_DEFINITION | FIELD_DEFINITION | INPUT_FIELD_DEFINITION

type Person {
  # Person.id will be returned as the opaque public ID value
  id: ID! @indirect(type: "Person")
}

type Mutation {
  updatePerson(
    # the `id` argument is provided by the client as the public ID, but the
    # `updatePerson` resolver will see the private database id.
    id: ID @indirect(type: "Person")
    name: String
    input: PersonInput
  ): Person
}

input PersonInput {
  # Any field that has an argument of type PersonInput will have that argument
  # transformed from the public id to the private id.
  id: ID! @indirect(type: "Person")
  name: String
}
// server.js
import indirectDirectiveTransformer from "apollo-idor";
import { ApolloServer } from "apollo-server";
import { makeExecutableSchema } from "graphql-tools";
import typeDefs from "./typeDefs";
import resolvers from "./resolvers";

let schema = makeExecutableSchema({ typeDefs, resolvers }));

// set a unique salt for ID transforms
const options = { salt: process.env.APP_KEY }
schema = indirectDirectiveTransformer("indirect", options)(schema)

const server = new ApolloServer({ schema });

Schema Directive API

The @indirect directive has three arguments:

  • type - when transforming to a public ID, this is embedded into the public ID; when transforming from a public ID an exception will be thrown if the embedded type does not match
  • scope - specifies how the scope argument for transformation is sourced. If not provided the scope will be public. It can be set to 'PUBLIC' to use the public scope, or 'CONTEXT' to read a value from the indirect property of the context object. It's recommended to provide a default value in the directive definition
  • raw - a boolean; if set to true the transformed value will be an instance of an idor value. This can be useful if a resolver's behaviour is driven by the type

The indirectDirectiveTransformer() function takes two arguments:

  • directiveName - the name of the directive (conventionally "indirect")
  • options - an object containing initialisation settings
    • scopeResolvers - object to extend the possible values for the directive scope argument
    • salt - passed to the idor constructor to initialise encryption salt; this should be a random string at least 16 bytes long which is treated as a secret by the application
    • other options are passed through to the idor constructor

indirectDirectiveTransformer() returns a function to use as a schema transformer. The returned function accepts a schema object (created using makeExecutableSchema()), and returns a new executable schema.