Skip to content

GraphQL Configuration Protocol #20

@asiandrummer

Description

@asiandrummer

GraphQL Configuration protocol

In a nutshell, the simplest format is:

export type GraphQLConfiguration = {
  schemaPath?: FilePath,  // may be .json or .graphql
  schemaUrl?: URL,
  schemaJS?: ModulePath | ModuleName,
  // If env is specified, use one of the app configs in here
  env?: GraphQLConfigurationEnvs

  // For multiple applications with overlapping files, bottom configuration options may be helpful
  includeDirs?: Array<DirPath>,
  excludeDirs?: Array<DirPath>,

  // If you have customized validation rules to run
  customValidationRules?: FilePath | Array<FilePath>,

  // If you'd like to specify any other configurations, we provide a reserved namespace for it
  extensions?: GraphQLConfigurationExtension
};

export type GraphQLConfigurationEnvs = {
  production: GraphQLConfiguration,
  development: GraphQLConfiguration,
  // but really just the below
  [envVarName: string]: GraphQLConfiguration
};

export type GraphQLConfigurationExtension = {
  [toolName: string]: any,
};

Note that I'd like to discourage the recursive pattern in using the EnvironmentalVariable - for example:

{
  "schemaPath": "...",
  "env": {
    "production": {
      "appProd": {
        // BEWARE OF THE BELOW PATTERN!
        "env": { ... }
      }
    }
  }
}

Now the reasoning for it: let's start with a most simple use case - one app/one schema.

Single-app/single-schema

Usually a single app requires a schema path/url and an env variable to facilitate the build and deployment:

export type GraphQLAppConfig = {
  schemaPath: FilePath,
  schemaUrl: URL,
  env: EnvironmentVariable
};

export type EnvironmentVariable = {
  [envVarName: string]: GraphQLAppConfig
};

Multiple-apps/isolated directories

For multiple apps with isolated directories, I like @wincent's idea about a common-default GraphQL configurations, but in spirit of keeping things simple at first, I'd like to propose an one-config-per-directory approach as our first draft. I think there's an edge case where we'd have multiple parent GraphQL configurations to consider:

./repo/.graphqlrc
./repo/appFamily/.graphqlrc
./repo/appFamily/app1/.graphqlrc

This can become a discussion of its own, which we can have separately ;)

Custom validation rules

You may want to run custom validation rules before building GraphQL apps/codegen/etc - customValidationRules is useful for that.

Reserved namespaces

@wincent made a suggestion to provide a way to include any other configurations if you desire. This namespace will contain an app/prod/organization/team-specific GraphQL configurations, and it will be treated as optional settings you'd like to use for your purpose.

{
  "schemaPath": "path/to/schema",
  "extensions": {
    "my-tool": {
      "here": "This is a tool-specific extension"
    }
  }
}

What is this repo, then?

I think this repo should serve two roles in a broader sense:

1. Maintain this protocol and become a town hall for discussions/improvements for this protocol.
2. Provide reference implementations of helper methods to lubricate adoption for this protocol.

An example of the reference implementation of the helper method: we mentioned a way to find this GraphQL configuration is to walk up a directory until it finds one. This basically can be implemented as such:

/**
 * (From `graphql-language-service` repo:
 * Finds a .graphqlrc configuration file, and returns null if not found.
 * If the file isn't present in the provided directory path, walk up the
 * directory tree until the file is found or it reaches the root directory.
 */
export function findGraphQLConfigDir(dirPath: string): ?string {
  let currentPath = path.resolve(dirPath);
  while (true) {
    const filePath = path.join(currentPath, '.graphqlrc');
    if (fs.existsSync(filePath)) {
      break;
    }
    if (isRootDir(currentPath)) {
      break;
    }
    currentPath = path.dirname(currentPath);
  }
  return !isRootDir(currentPath) ? currentPath : null;
}

function isRootDIr(path: string): boolean {
  return path.dirname(path) === path;
}

As there are several use cases, we can tackle each of them and present a way to use this configuration programmatically. I can begin by identifying/suggesting some of them below:

  • A generalized module bundler configurations, using GraphQL configurations
    • webpack, yeoman, babel, and etc...
  • How to include custom validation rules in your application
  • How to generate schema with provided schema path(s)
    • Sending introspection query to the endpoint
    • Parsing/building the schema using a local file path
    • Compiling GraphQLSchema object using schema definitions in .js
    • How to cache the schema
      • local files, indexedDB, and etc...

Action items

There are many things to do! But when we successfully deliver this, I believe we can get to the point where we have a shared GraphQL configuration that everyone agrees on, with commonly-used techniques and best practices to configure your GraphQL environment.

  • Write a draft for this protocol
  • Populate this repository with those helper methods
    • Discuss what the superset of those helper methods would be
    • Prioritize by the most impactful and common ones and implement them
    • Generalize existing implementations and move them here
  • Update other remaining documentations, including this repo's README
  • Suggest GraphQL configuration as a best-practice at graphql.org

Lastly, although we've begun this proposal and made a bunch of suggestions, I'd love to have a collaborative effort in pushing this forward. It'll be amazing to see us working together to improve and deliver this proposal to the GraphQL community.

Please post your thoughts/concerns/questions! Also if you'd like to be responsible for one of the actions items above, don't be hesitate to do so :D

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions