Project generated via @wayfair-incubator oss-template

Overview

node-froid: NodeJS - Federated Relay Object Identification

Release Lint codecov Contributor Covenant license: MIT Maintainer

Table of Contents

About The Project

The problem

There isn't good support for the Relay's Object Identification spec in the Federated GraphQL ecosystem. This makes it difficult to support common patterns used to refetch objects from your graph to power things like cache TTLs and cache-miss hydration.

The solution

@wayfair/node-froid provides two key pieces of functionality:

  • id processing: a solution that can be used to run inline as part of a custom Data Source or as a completely separate subgraph (recommended) dedicated to service your object identification implementation .
  • schema generation: a schema generation script that reflects on all subgraphs in your federated graph and generates a valid relay object identification schema.
    • Can run in Federation v1 or v2 mode
    • Supports contracts!

Getting Started

To get a local copy up and running follow these simple steps.

Installation

This module is distributed via npm which is bundled with node and should be installed as one of your project's direct dependencies:

npm install @wayfair/node-froid

or

for installation via yarn

yarn add @wayfair/node-froid

This library has peerDependencies listings for graphql and graphql-relay.

Library API

handleFroidRequest

Parameter Name Required Description Type Default
request Yes The request object passed to the froid subgraph see specific properties
request.query Yes The query string for the request string
request.variables Yes The variables for the request Record<string, unknown>
options Configuration options available to handleFroidRequest see specific properties {}
options.encode A callback for encoding the object identify key values (string) => string (keyString) => keyString
options.decode A callback for decoding an object identifier's key values (string) => string (keyString) => keyString
options.cache Cache to use to avoid re-parsing query documents FroidCache

Returns Promise<object[]>: A promise representing the list of entity objects containing a relay-spec compliant id value.

generateFroidSchema

Parameter Name Required Description Type Default
subgraphSchemaMap Yes A mapping of subgraph names --> subgraph SDLs used to generate the froid schema Map<string, string>
froidSubgraphName Yes The name of the relay subgraph service string
options Optional configuration for schema generation see specific properties {}
options.contractTags A list of supported contract tags string[] []
options.federatedVersion The version of federation to generate schema for FederationVersion FederationVersion.V2
options.typeExceptions Types to exclude from id field generation string[] []

Returns DocumentNode[]: The froid schema

Usage

id Processing

Custom GraphQL Gateway Datasource

import {GraphQLDataSourceProcessOptions} from '@apollo/gateway';
import {GraphQLResponse} from 'apollo-server-types';
import {handleFroidRequest} from '@wayfair/node-froid';
import {Context} from './path/to/your/ContextType';

class FroidDataSource {
  process({
    request,
  }: Pick<
    GraphQLDataSourceProcessOptions<Context>,
    'request'
  >): Promise<GraphQLResponse> {
    return await handleFroidRequest(request);
  }
}

Custom GraphQL Gateway Datasource w/Encryption

// Datasource Implementation
import {GraphQLDataSourceProcessOptions} from '@apollo/gateway';
import {GraphQLResponse} from 'apollo-server-types';
import {
  DecodeCallback,
  EncodeCallback,
  handleFroidRequest,
} from '@wayfair/node-froid';
// You only really need this if you are using context
import {Context} from './path/to/your/ContextType';
// Used to determine which encoder to use
import {FeatureToggleManager} from './path/to/your/FeatureToggleManager';

// Interface we need to match properly encode key values
interface Encoder {
  encode: EncodeCallback;
  decode: DecodeCallback;
}

class FroidLDataSource {
  private encoder1: Encoder;
  private encoder2: Encoder;

  // Take two encoders to support live key rotation
  constructor(encoder1: Encoder, encoder2, Encoder) {
    this.encoder1 = encoder1;
    this.encoder2 = encoder2;
  }

  process({
    request,
  }: Pick<
    GraphQLDataSourceProcessOptions<Context>,
    'request'
  >): Promise<GraphQLResponse> {
    const encoder = FeatureToggleManager.useEncoder1()
      ? this.encoder1
      : this.encoder2;

    return await handleFroidRequest(request, {...encoder});
  }
}

// Sample Encoder
import crypto from 'crypto';
import {DecodeCallback, EncodeCallback} from '@wayfair/node-froid';

const ENCRYPTION_ALGORITHM = 'aes-256-cbc';

// Interface we need to match properly encode key values
interface Encoder {
  encode: EncodeCallback;
  decode: DecodeCallback;
}

type CreateEncoderArguments = {
  base64InitializationVector: string;
  base64EncryptionKey: string;
};

export class CustomEncoder implements Encoder {
  private iv: Buffer;
  private key: Buffer;

  constructor({
    base64InitializationVector,
    base64EncryptionKey,
  }: CreateEncoderArguments) {
    this.iv = Buffer.from(base64InitializationVector, 'base64');
    this.key = Buffer.from(base64EncryptionKey, 'base64');
  }

  public encode(value: string): string {
    const cipher = crypto.createCipheriv(
      ENCRYPTION_ALGORITHM,
      this.key,
      this.iv
    );
    const encryptedValue = cipher.update(value);
    const encryptedBuffer = Buffer.concat([encryptedValue, cipher.final()]);

    return encryptedBuffer.toString('base64');
  }

  public decode(value: string): object {
    const decipher = crypto.createDecipheriv(
      ENCRYPTION_ALGORITHM,
      this.key,
      this.iv
    );
    const decryptedValue = decipher.update(Buffer.from(value, 'base64'));
    const decryptedBuffer = Buffer.concat([decryptedValue, decipher.final()]);

    return decryptedBuffer.toString();
  }
}

Custom GraphQL Gateway Datasource w/Cache

import {GraphQLDataSourceProcessOptions} from '@apollo/gateway';
import {GraphQLResponse} from 'apollo-server-types';
import {handleRelayRequest} from '@wayfair/node-froid';
import {Context} from './path/to/your/ContextType';
import LRU from 'lru-cache';

const cache = new LRU({max: 500});

class RelayNodeGraphQLDataSource {
  process({
    request,
  }: Pick<
    GraphQLDataSourceProcessOptions<Context>,
    'request'
  >): Promise<GraphQLResponse> {
    return await handleRelayRequest(request, {
      cache,
    });
  }
}

Subgraph w/Express Server

import express from 'express';
import bodyParser from 'body-parser';
import {handleFroidRequest} from '@wayfair/node-froid';

const port = process.env.PORT || 5000;

const app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

// No need to run a full GraphQL server.
// Avoid the additional overhead and manage the route directly instead!
app.post('/graphql', async (req, res) => {
  const result = await handleFroidRequest(req.body);
  res.send(result);
});

app.listen(port, () => {
  console.log(`Froid subgraph listening on port ${port}`);
});

Schema Generation

Basic Script

import fs from 'fs';
import {print} from 'graphql';
import {generateFroidSchema} from '@wayfair/node-froid';
// You have to provide this. Apollo's public API should provide the ability to extract out subgraph SDL
import {getFederatedSchemas} from './getFederatedSchemas';

const froidSubgraphName = 'froid-service';
const variant = 'current';

// Map<string, string> where the key is the subgraph name, and the value is the SDL schema
const subgraphSchemaMap = getFederatedSchemas(variant);

const schemaAst = generateFroidSchema(subgraphSchemaMap, froidSubgraphName);

// persist results to a file to use with rover publish
fs.writeFileSync('schema.graphql', print(schemaAst));

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated. For detailed contributing guidelines, please see CONTRIBUTING.md

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Project Link: https://github.com/wayfair-incubator/node-froid

Acknowledgements

This template was adapted from https://github.com/othneildrew/Best-README-Template.

Comments
  • test: enhance test to showcase array support

    test: enhance test to showcase array support

    Description

    • test: enhance test to showcase array support

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [x] Other (please describe) - enhanced test

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 1
  • Update CHANGELOG.md

    Update CHANGELOG.md

    Description

    Update CHANGELOG.md

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [x] Documentation
    • [ ] Other (please describe)

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 1
  • feat: sort keys to ensure deterministic ids

    feat: sort keys to ensure deterministic ids

    Description

    • feat: sort keys to ensure deterministic ids

    Type of Change

    • [x] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [ ] Other (please describe)

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 1
  • feat!: @key selection logic

    feat!: @key selection logic

    Description

    • BREAKING CHANGE: To simplify the output schema, @key selection now picks the first directive where fields doesn't specify a nested complex key.
    • Fix: When entities are specified in a nested complex key field, they were generated as non-entity types in the froid schema.
    • Fix: Non-resolvable entity references in Federation 2 are not processed during froid schema generation. i.e. @key directives with resolvable set to true will be ignored to prevent extending entity references

    Type of Change

    • [x] Bug Fix
    • [ ] New Feature
    • [x] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [ ] Other (please describe)

    Checklist

    • [x] I have read the contributing guidelines
    • [ ] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by sMorm 1
  • feat: support custom enum key fields

    feat: support custom enum key fields

    Description

    • Enums used as key fields were generated as custom scalars, instead of enums when defined in the Froid subgraph
    • Removes logic to apply all contract directives to non-native field return types (scalars, enums). Since contract supergraph composition merges all contract directives together, they aren't needed when used in the froid subgraph.

    Type of Change

    • [x] Bug Fix
    • [x] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [ ] Other (please describe)

    Checklist

    • [x] I have read the contributing guidelines
    • [ ] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by sMorm 1
  • feat: bump version to 1.0.1

    feat: bump version to 1.0.1

    Description

    • feat: bump version to 1.0.1

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [x] Other (please describe) - release prep

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 1
  • build: add code coverage integration

    build: add code coverage integration

    Description

    • build: add code coverage integration

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [x] Other (please describe) - code coverage

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 1
  • Cleanup Distributed files

    Cleanup Distributed files

    Problem Statement

    When a release is made we should remove any non-essential files from the release and primarily just release what is in the dist folder plus LICENSE and README.

    Proposed Solution

    Solution can be as simple as adding the file patterns you want to include to the package.json file: https://docs.npmjs.com/cli/v8/configuring-npm/package-json#files

    Or more complex with build code like the graphql and graphql-relay libraries use:: (to note the LICENSE is included from the Top level folder so that it is released with the code)

    https://github.com/graphql/graphql-js/blob/main/resources/build-npm.ts https://github.com/graphql/graphql-relay-js/blob/main/resources/build.js

    Additional Context

    Screenshot comparing contents of graphql-relay to wayfair/node-froid image

    enhancement good first issue 
    opened by draco2003 1
  • Update actions/stale action to v6

    Update actions/stale action to v6

    Mend Renovate

    This PR contains the following updates:

    | Package | Type | Update | Change | |---|---|---|---| | actions/stale | action | major | v5 -> v6 |


    Release Notes

    actions/stale

    v6

    Compare Source


    Configuration

    πŸ“… Schedule: Branch creation - "before 3am every weekday" (UTC), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    β™» Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

    πŸ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, click this checkbox.

    This PR has been generated by Mend Renovate. View repository job log here.

    renovate/actions/stale 
    opened by renovate[bot] 1
  • infra: fix prettier scripts

    infra: fix prettier scripts

    Description

    • infra: fix prettier scripts

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [x] Other (please describe) - prettier configuration updates

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 0
  • build: only publish required files

    build: only publish required files

    Description

    Fixes #4

    • build: only publish required files

    Type of Change

    • [ ] Bug Fix
    • [ ] New Feature
    • [ ] Breaking Change
    • [ ] Refactor
    • [ ] Documentation
    • [x] Other (please describe) - improve build process

    Checklist

    • [x] I have read the contributing guidelines
    • [x] Existing issues have been referenced (where applicable)
    • [x] I have verified this change is not present in other open pull requests
    • [x] Functionality is documented
    • [x] All code style checks pass
    • [x] New code contribution is covered by automated tests
    • [x] All new and existing tests pass
    opened by mjfaga 0
  • chore(deps): update actions/stale action to v7

    chore(deps): update actions/stale action to v7

    Mend Renovate

    This PR contains the following updates:

    | Package | Type | Update | Change | |---|---|---|---| | actions/stale | action | major | v6 -> v7 |


    Release Notes

    actions/stale

    v7

    Compare Source


    Configuration

    πŸ“… Schedule: Branch creation - "before 3am every weekday" (UTC), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    β™» Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

    πŸ”• Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    renovate/actions/stale 
    opened by renovate[bot] 1
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    Open

    These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

    Detected dependencies

    github-actions
    .github/workflows/release.yml
    • actions/checkout v3
    • actions/setup-node v3
    • JS-DevTools/npm-publish v1
    .github/workflows/stale.yml
    • actions/stale v6
    .github/workflows/validate.yml
    • actions/checkout v3
    • actions/setup-node v3
    • actions/checkout v3
    • actions/setup-node v3
    • actions/checkout v3
    • actions/setup-node v3
    • codecov/codecov-action v3
    • actions/checkout v3
    • actions/setup-node v3
    • actions/checkout v3
    • suzuki-shunsuke/github-action-renovate-config-validator v0.1.2

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 1
Releases(v2.0.1)
  • v2.0.1(Dec 22, 2022)

  • v2.0.0(Nov 28, 2022)

    Breaking

    • @key directive selection in schema generation now picks the first directive where @key fields do not specify a nested complex key.

    Fix

    • Fix applied to when entities are specified in a nested complex key field, they were generated as non-entity types in the Froid schema.
    • Fix issue where non-resolvable entity references in Federation 2 were processed during Froid schema generation
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Oct 11, 2022)

  • v1.0.0(Oct 4, 2022)

  • v0.2.0(Oct 2, 2022)

    Breaking

    • Updated handleFroidRequest.options.decode API from string -> object to string -> string to remove inconsistency across the encode/decode APIs. Now all JSON parsing happens in the core implementation.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Oct 1, 2022)

  • v0.1.0(Oct 1, 2022)

    • Add initial library API:
      • handleFroidRequest: Handles both id generation as well as node field parsing of Object Identification requests in Federation.
      • generateFroidSchema: Generates schema for the Froid subgraph, complete with Federation 1 & 2 support, as well as Apollo contracts!
    Source code(tar.gz)
    Source code(zip)
Owner
Wayfair Tech – Incubator
Furnishing the future of technology with Wayfair.
Wayfair Tech – Incubator
Contains html file showcasing Earthquake related data generated in the form of VR model, ArcGIS API with real-time earthquake feed and video of simulation of earthquake generated in blender

Module-EADGI-Project-All about Earthquakes Introduction Contains html file showcasing Earthquake related data generated in the form of VR model, ArcGI

Abhishek Rawat 2 Jun 9, 2022
Automatically construct and visualize Graphs generated from your Node.js project

cyclops is a minimalist developer tool that can be used to generate directed graphs from your Node.js project. It can automatically detect circular de

Antoine Coulon 74 Jan 5, 2023
Automatically construct, traverse and visualize graphs generated from your Node.js project

skott is a minimalist developer tool that can be used to efficiently generate directed graphs from your JavaScript/Node.js project. It can automatical

Antoine Coulon 57 Dec 21, 2022
πŸ₯° Mini world simulator is a terminal application made in JavaScript to control the world that is being generated.

Mini-world "Simulator" Mini world simulator is a terminal application made in JavaScript to control the world that is being generated. It has no other

AdriΓ‘n 2 Mar 14, 2022
Automatically generated documentation for the Valorant API endpoints the client uses internally.

Valorant API Docs To read documentation and get started, see Docs This is a project designed to automatically document Valorant endpoints based on a J

Techdoodle 223 Dec 25, 2022
Browser Extension to deliver AI-generated alt-text for the Visually Impaired.

GenAlt - Generated Image Descriptions for BVI The Blind and Visually Impaired (BVI) rely on alt-text, image descriptions, to experience the trillions

Anish 11 Sep 10, 2022
Example auto-generated OpenAPI client library and an accompanying example Angular app.

To utilize this demo Head into petstore_frontend\petes_pets Run npm install Go to frontend_client_lib\out Run npm install Head back into petstore_fron

Alan Gross 1 Jan 21, 2022
Central service used for management of CodeSupport user generated content.

CodeSupport API About This repository contains the code for the CodeSupport API. The project is written in TypeScript using the NestJS framework with

CodeSupport 2 Oct 14, 2022
GitHub Action that posts the report in a comment on a GitHub Pull Request from coverage data generated by nyc (istanbul)

GitHub Action: Report NYC coverage GitHub Action that posts the report in a comment on a GitHub Pull Request from coverage data generated by nyc (ista

Sid 16 Nov 23, 2022
Obsidian plugin: Type text shortcuts that expand into javascript generated text.

Obsidian Plugin - Text Expander JS (open beta) This Obsidian plugin allows the user to type text shortcuts that are replaced by (or "expanded into") j

Jon Heard 79 Dec 27, 2022
Generated TypeScript interfaces for Aptos Move.

Aptos Framework TypeScript SDK Generated TypeScript interfaces for Aptos Move. This contains types for: AptosFramework MoveNursery MoveStdlib Releases

Aptosis 7 Aug 25, 2022
Happy Birthday is a web-based party live background generated by CANVAS powered by JavaScript. This show a lot of random colorize particles in the background.

Happy BirthDay JS Happy Birthday is a web-based party live background generated by CANVAS powered by JavaScript. This show a lot of random colorize pa

Max Base 9 Oct 29, 2022
Get dynamically generated your github contributor stats on your READMEs!

GitHub Readme Contributor Stats Get dynamically generated your github contributor stats on your READMEs! Features GitHub Contributor Stats Card Themes

Taehyun Hwang 20 Dec 11, 2022
100% type-safe query builder for node-postgres :: Generated types, call any function, tree-shakable, implicit type casts, and more

⚠️ This library is currently in alpha. Contributors wanted! tusken Postgres client from a galaxy far, far away. your database is the source-of-truth f

alloc 54 Dec 29, 2022
Easiest 1-click way to install and use Stable Diffusion on your own computer. Provides a browser UI for generating images from text prompts and images. Just enter your text prompt, and see the generated image.

Stable Diffusion UI Easiest way to install and use Stable Diffusion on your own computer. No dependencies or technical knowledge required. 1-click ins

null 3.5k Dec 30, 2022
Simple NextJS Project Template to write less boilerplate code when starting a new Next JS Project

Simple NextJS Project Template to write less boilerplate code when starting a new Next JS Project

Juan David Ramirez Mendoza 1 Feb 12, 2022
Discord.js bot starter template, Slash Commands only (Raymond forced me to make a bot template)

boat-template Raymond forced me to make a bot template This template is meant is just for stupidness ig Getting Started Rename the config.example.ts t

Drxckzyz tha idiot 3 Jan 5, 2022
Github follower notifier via telegram bot

⚑ GitHub Follower Notifier ?? ⚑ Vars: ?? FEED: Go Here to get yours. DATABASE: Go HERE to create one. After creating Instance: Go to your Instance Go

Gautam Kumar 14 Nov 25, 2021