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

relay-composite-network-layer

v0.0.4

Published

A network layer for relay which can work with multiple underlying network layers

Downloads

6

Readme

RelayCompositeNetworkLayer

The RelayCompositeNetworkLayer is a Relay Network Layer which can be made of many different Network Layers each with their own schema. This is accomplished by merging multiple schemas into a single schema. Relay then generates appropriate queries using this schema while the RelayCompositeNetworkLayer splits and sends the queries by schema.

The main use case for this is allowing a local and server schema.

Installation

npm install relay-composite-network-layer

It has a peer dependency on react-relay (the version is pretty strict at the moment but probably could be loosened!).

Usage

The first step is merging the schema. You can add a build step or make it part of your update-schema script.

import {createCompositeSchema} from 'relay-composite-network-layer/lib/merge';

const {schema,config} = createCompositeSchema({
  // name / value pairs of schemas
  server: serverSchema,
  local: localSchema
}, {
  // names for the query and mutation type of the output schema
  // these can be the same names as your input schemas
  queryType: 'Query',
  mutationType: 'Mutation'
});

The outputs of schema and config need to be saved to json files for consumption. Configure the babelRelayPlugin to use the saved merged schema. With the schemas merged and Relay configured you should be able to write / parse queries which hit multiple schemas.

A full script example is at the end of the README.

The next step is to create the RelayCompositeNetworkLayer on the client.

import RelayCompositeNetworkLayer from 'relay-composite-network-layer';

const compositeNetworkLayer = new RelayCompositeNetworkLayer({
  // config is the output of the `createCompositeSchema` function
  ...config,
  // key / value pairs of schema
  // names need to match the call to `createCompositeSchema`
  layers: {
    server: new Relay.DefaultNetworkLayer('/graphql'),
    local: new RelayLocalSchema.NetworkLayer({schema: localSchema})
  }
});

Here we are creating a composite network layer which has two schemas. The server schema uses the default network layer and makes network requests to the /graphql endpoint. The local schema uses the RelayLocalSchema library to execute graphql-js on the client.

Finally inject the network layer into Relay.

Relay.injectNetworkLayer(compositeNetworkLayer);

That should be it!

Limitations

The main limitations are around merging.

You can only merge node interface objects. This means if you define User in multiple schemas each schema User needs an id field and needs to be able to be fetched from the node root query field. Other objects which appear in multiple schemas must be equivalent (same fields) or the merge will fail.

Enum's, Scalar's, and Input Object's also must be equivalent if they are found with the same name in multiple schemas.

Union's and Interface's, with the exception of the node interface, are not allowed to be in multiple schemas.

Fields on the Query, Mutation, and Subscription field are also merged. These names must be unique. For example most schemas have a viewer type but this field must only exist in one schema. Other schemas navigate to the viewer by querying node with the viewer id.

Some of these restrictions could be lifted -- I just haven't thought around the use cases!

Example

I'm going to use the example from the github issue for relay local data: https://github.com/facebook/relay/issues/114

We have the following query:

query {
  viewer {
    name,                     # server field
    drafts(first: 10) {       # client-only field
      edges { node { title } }
    }
  }
}

This means we have the following two schemas.

Server

type User : Node {
  id: ID!
  name: String
}

type Query {
  viewer: User
  node: Node
}

Local

type User : Node {
  id: ID!
  drafts: DraftConnection
}

type Draft : Node {
  id: ID!
  title: String
}

type DraftConnection {
  edges: [DraftEdge]
}

type DraftEdge {
  node: Draft
}

type Query {
  node: Node
}

The type User is defined in both schemas. Both schemas also have a query root type named Query but the names do not have to match. Only the server schema has the viewer field.

When merged we get a third schema.

Composite

type User : Node {
  id: ID!
  name: String
  drafts: DraftConnection
}

type Draft : Node {
  id: ID!
  title: String
}

type DraftConnection {
  edges: [DraftEdge]
}

type DraftEdge {
  node: Draft
}

type Query {
  viewer: User
  node: Node
}

This schema presents a unified view of the two schemas which Relay can use to generate queries.

Lets follow the execution of the query.

query {
  viewer {
    name,                     # server field
    drafts(first: 10) {       # client-only field
      edges { node { title } }
    }
  }
}

The composite network layer first splits the query by schema. This results in multiple queries with some being dependent on the result of others.

q1 server

query {
  viewer {
    id
    name
  }
}

This query is not dependent on anything.

q2 local

query {
  node(id: $id) {
    id
    __typename
    ... on User {
      drafts(first: 10) {
        edges { node { title } }
      }
    }
  }
}

This query is dependent on the viewer.id result from q1. It will be run sequentially following q1.

The queries are then executed.

q1

{
  data: {
    viewer: {
      id: 1,
      name: 'Huey'
    }
  }
}

q2

{
  data: {
    node: {
      id: 1,
      __typename: 'User',
      drafts: {
        edges: [{
          node: { title: 'Taste Javascript'},
          node: { title: 'Paint a self portrait'}
        }]
      }
    }
  }
}

Finally the results are merged and passed back to Relay.

{
  data: {
    viewer: {
      id: 1,
      __typename: 'User',
      name: 'Huey',
      drafts: {
        edges: [{
          node: { title: 'Taste Javascript'},
          node: { title: 'Paint a self portrait'}
        }]
      }
    }
  }
}

Relay cares not that part of the query has been local and part of it has been remote.

You could also add an author field to Draft and query back and forth between local and server:

query {
  viewer {                   # server field
    selectedDraft {          # local field
      author {               # server field
        selectedDraft {
          author {
            selectedDraft {
              author {
                name
              }
            }
          }
        }
      }
    }
  }
}

This will generate a bunch of sequential queries so be careful!

Mutations

Mutations are treated just like queries. As far as I know Relay only allows a single field on a mutation so no extra work is needed at the network layer for coordination. The mutation field schema is looked up and the mutation is sent to the proper schema network layer. The mutation payload is then just like a query and can come from multiple schemas.

mutation {
  addDraft(input: $input) {   # client field
    author {
      name                    # server field
      draftCount
    }
    edge {
      node {
        title
      }
    }
  }
}

Merge Script

Here is the full script:

import fs from 'fs';
import path from 'path';

import localSchema from '../data/local/schema.json';
import serverSchema from '../data/server/schema.json';

import {createCompositeSchema} from 'relay-composite-network-layer/lib/merge';

const {schema,config} = createCompositeSchema({
  server: serverSchema,
  local: localSchema
}, {
  queryType: 'Query',
  mutationType: 'Mutation'
});

fs.writeFileSync(
  path.join(__dirname, '../data/', 'schema.json'),
  JSON.stringify(schema, null, 2)
);

fs.writeFileSync(
  path.join(__dirname, '../data/', 'config.json'),
  JSON.stringify(config, null, 2)
);

TODO

  • chained mutation

    • AddTodo / DeleteDraft
  • remove graphql as a peer