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

graphql-schema-bindings

v1.0.0

Published

an opinionated graphql server format for combining schema and implementation

Downloads

22

Readme

GraphQL Schema Bindings

npm Build Status Coverage Status

GraphQL Schema Bindings is a flexible and scalable GraphQL schema generator that exposes common object oriented patterns to your GraphQL server.

GraphQL Schema Bindings uses decorators to define the necessary metadata to map your native types to GraphQL types.

Decorators make it easy to create GraphQL services. Let's start with a simple example. This example can get users from the GitHub REST API and represent them as GraphQL.

We'll define a simple user GraphQL query. The first step is to create our user class:

@type
class User {
  @context
  context;

  @field(ID)
  get id() {
    return this.data.id;
  }

  @field(String)
  get name() {
    return this.data.name;
  }

  constructor(data) {
    this.data = data;
  }
}

Now we can build a query that returns that user:

@type
class UserQuery {
  @field(User)
  async user(@arg(ID) id) {
    const url = id ? `/${id}` : "";
    const { data } = await axios.get(`https://api.github.com/users${url}`);
    return new User(data);
  }
}

And that's it. Run this sample yourself here: GitHub users sample

Understanding Decorators

Decorators to help describe your functions and arguments. They all have the format of @<some type> before a function in your code.

@type

Use @type to mark a class as an output type in the GraphQL schema. This indicates that a class represents data that will be either returned from GraphQL.

@type
class Resource {
    ...
}

@field

Exported types need to have fields that GraphQL can access. These fields indicate which values are available to the GraphQL response. In our previous example the fields were name and id.

@type
class Resource {
  @field(ID)
  id;
  @field(String)
  name;
}

Fields are automatically inherited from parent types.

@type
class BaseResource {
  // context can be bound to a field
  @context
  context;

  @field(ID)
  get id() {
    return this.data.id;
  }

  constructor(data) {
    this.data = data;
  }
}

@type
class Resource extends BaseResource {
  /**
   * The field return type can be wrapped in a
   * thunk to handle circular dependencies.
   */
  @field(() => Resource)
  parent() {
    return this.context.getParent(this.id);
  }

  /**
   * The return type can be an array of items.
   */
  @field([Resource])
  children() {
    return this.context.getChildren(this.id);
  }
}

The field decorator takes an argument for the type of field. The type can be one of the default supported types like String, ID, Int, or Float or it can be any object you define. The schema bindings library can automatically convert inputs to these types.

You can also define an array type in the field decorator like this:

@field([User])
@description('Get list of users.')
users() {
  return users;
}

@context

This decorator indicates that the field or argument is assigned the context for the GraphQL query. The context is a global object that is created for the query. The context can contain anything, but it usually contains helper methods and data models useful for resolving data from an underlying data source. These models and helper methods might use information specific to this request to help resolve data (such as user credentials).

@type
class User {
  // context may be bound to a field on the type
  @context
  context;
}

@type
class Query {
  // or it may be bound to an argument of a method
  @field(User)
  current_user(@context context) {
    return context.getCurrentUser();
  }
}

Important: the context is assigned by the GraphQL field resolver and not by JavaScript. This means that a context field is not guaranteed to be assigned when called from another function and that context bound arguments need to pass the context in when called from another function.

@type
class QueryModel {
  @context
  context;

  @field(String)
  get key() {
    return this.context.keyValue; // O.K.
  }
}

@type
class MyType {
  @context
  context;

  @field(String)
  key() {
    return this.context.model.key; // Error: cannot read keyValue of undefined
  }
}

new Server({
  schema: createSchema(QueryModel),
  context: { model: new QueryModel(), keyValue: "the-key" }
});

In the above example GraphQL cannot resolve MyType.key because it references QueryModel.key when QueryModel.context is undefined. GraphQL can resolve QueryModel.key directly because it (GraphQL) assigns the context during resolution of the key field.

To fix the above example we could use a context bound method argument.

@type
class MyType {
  @context
  context;

  @field(String)
  key() {
    return this.context.model.key(this.context); // O.K.
  }
}

@type
class QueryModel {
  @field(String)
  key(@context context) {
    return context.keyValue;
  }
}

@description

This decorator is used to describe a field.

@field(String)
@description('This is the name of the current user')
get name() {
  return this.data.name;
}

The description shows up in the GraphQL schema and can be seen in schema tools like the Playground in our sample applications. It looks like this:

The image description decorator

@deprecated

This decorator indicates that field is currently deprecated. This information appears in the GraphQL schema.

@arg

This decorator indicates that a field is an argument in the GraphQL. This is used for queries and mutations.

@field(User)
async user(@arg(ID) id) {

This will cause the field to be included in the GraphQL schema.

@input

This decorator indicates that a class is an input to a mutation.

@input
class NameInput {
  @field(String)
  @required
  name;
}

This will show up in the GraphQL schema as an input to a given mutation.

@required

This decorator indicates that the field is required in the GraphQL schema.

XKCD Example

The XKCD example is a great place to start with this project. It provides a simple schema that can query comics from XKCD. Take a look at the example at examples/xkcd.