Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Ballerina GraphQL Schema Registry #4820

Closed
zetcco opened this issue Sep 19, 2023 · 0 comments · Fixed by xlibb/graphql-schema-registry#1
Closed

Proposal: Ballerina GraphQL Schema Registry #4820

zetcco opened this issue Sep 19, 2023 · 0 comments · Fixed by xlibb/graphql-schema-registry#1
Assignees
Labels
module/graphql Issues related to Ballerina GraphQL module Status/Active Proposals that are under review Team/PCM Protocol connector packages related issues Type/Proposal

Comments

@zetcco
Copy link

zetcco commented Sep 19, 2023

Summary

A Schema Registry in GraphQL is crucial for maintaining a centralized repository of schemas in a Federated GraphQL Service, enabling efficient schema versioning and validation. Even though there are already implemented solutions, there is a shortage of open-source projects addressing that. This project aims to fill that gap by developing a Schema Registry as a Service using Ballerina.

Goals

  • Create a Schema Registry using Ballerina as a Self-Hosted service.

Motivation

Federated GraphQL is needed over a Single large Schema to enable scalable, decentralized development and maintenance of microservices, allowing teams to work independently on their GraphQL schemas. The main three components of a Federated GraphQL service are,

  • Subgraphs
  • Router
  • Schema Registry

When Subgraphs evolve independently, It is crucial to have a centralized mechanism to validate and document the changes made to the Supergraph. That’s where the Schema Registry comes in, Schema Registry helps in,

  • Versioning the Supergraph over it’s evolution
  • Document what changes are made to the Supergraph
  • Compose a Supergraph out of Subgraphs
  • Perform checks on the when publishing a Subgraph to the Schema Registry
  • Perform rollbacks in case a breaking change occurs (This will be implemented in Future stages of the Schema Registry)

While there are solutions for creating Subgraphs and Router components, a critical missing piece in the ecosystem is an Open Source Schema Registry. Without a Schema Registry, managing schema changes and ensuring data consistency across federated GraphQL services becomes challenging, leading to potential compatibility issues.

This proposal aims to address this gap by introducing an Open Source Schema Registry using the Ballerina programming language. By implementing an Open Source Schema Registry, we will enhance the overall reliability and maintainability of Federated GraphQL architectures, fostering collaboration within the GraphQL community.

Description

The Schema Registry Service is provided as a Self-Hostable GraphQL service. And this will use the ‘Federation V2’ specification.
The client operations that will be provided are,

  • Perform Dry Runs to verify that the given Subgraph is valid to compose a Supergraph. Validations include,
    • Composition Checks - Checks whether the new Subgraph is compatible with other Subgraphs to compose a Supergraph.
    • Operation Checks - Compare Supergraph schema changes against historical operations to verify whether any of the changes has the potential to break any of the graph's active clients. Those changes are also known as ‘Diffs’ in this project. Operation Checks can be categorized into three categories, and they are,
      • Breaking Changes - Break Existing client operations (ex: Removing a field from a Type)
      • Dangerous Changes - Can cause unexpected behaviors in Clients (ex: Adding an Enum, Adding an input field to input types, Changing a Default value of a argument, Adding a Default value to a field)
      • Safe Changes - (ex: Addition of a type)
  • Publish Subgraph to the Schema Registry to compose a Supergraph
  • Get the Supergraph Schema as well as Supergraph API Schema
  • Get a registered Subgraph by the Name

Architecture

GraphQL Schema Registry

Versioning Strategy

Changes made to the supergraph can be categorized into three categories as per the Operation Check and that can also be used to format of the Version number of the Supergraph in the format of [Breaking].[Dangerous].[Safe]

Starting up the Schema Registry Service

Add the configurations of the Schema Registry to the Config.toml with the following,

port=<PORT>

After building and running the Service, it will be available on http://localhost:PORT

Access the service on http://localhost:8080/

Schema Registry Service - GraphQL API

Since this will be implemented as a GraphQL service, the GraphQL API for that will be as follows.

type Query {
    supergraph: Supergraph!

    subgraph(name: String!): Subgraph

    # Perform schema checks (Composition, Operation) on a provided schema without registering it to the Registry.
    dryRun(criteria: SubgraphInput!): Supergraph!
}

type Mutation {
    publishSubgraph(criteria: SubgraphInput!): Supergraph!
}

input SubgraphInput {
    schema: String!
    name: String!
    message: String
}

type Supergraph {
    subgraphs: [Subgraph!]!
    apiSchema: Stirng!
    schema: String!
    changelog: [SchemaSnapshot!]!
}

type Subgraph {
    id: ID!
    name: String!
    schema: String!
}

type SchemaSnapshot {
    hash: ID!
    date: String!
    message: String!
    schema: String!
    diff: [SchemaDiff!]!
}

type SchemaDiff {
    severity: DiffSeverity!,
    action: DiffAction,
    type: DiffType!,
    message: String!,
}

enum DiffType {
    TYPE,
    TYPE_KIND,
    FIELD,
    FIELD_DEPRECATION,
    FIELD_TYPE,
    ARGUMENT,
    ARGUMENT_TYPE,
    ARGUMENT_DEFAULT,
    INPUT_FIELD,
    INPUT_FIELD_DEFAULT,
    INPUT_FIELD_TYPE,
    ENUM,
    ENUM_DEPRECATION,
    INTERFACE_IMPLEMENTATION
}

enum DiffAction {
    ADDED,
    REMOVED,
    CHANGED	
}

enum DiffSeverity {
    BREAKING,
    DANGEROUS,
    SAFE
}

Validation Error Codes

In the API, dryRun query and the publishSubgraph mutation operations can return errors if either the Operation Checks or Composition Checks fail. So the Errors are categorized into two groups as Operation Check Errors and Composition Check Errors.
Error response format will be as follows,

{
  "errors": [
    {
      "message": "'type' Removed",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["type"],
      "extensions": {
	 "phase": "OPERATION"
        "code": "TYPE_REMOVED"
      }
    }
  ]
} 
  • message : Error Message
  • locations : Error location
  • path : Path to the field/type/argument where the error occurred
  • extensions
    • phase : Operation Check (Denoted OPERATION) or Composition Check (Denoted COMPOSITION)
    • code: Error Code

Initial implementations of the Schema Registry will detect following errors on the two error categories as follows,

Operation Check Errors (Breaking Changes)
Error Code Error Description
FIELD_REMOVED Removing an field from a Type
FIELD_TYPE_CHANGED Changing the type of a Field (ex: Change id field of a Type from Int! to String!)
ARG_ADDED Add a Non-Nullable argument to a Field
ARG_TYPE_CHANGED Change an argument type (from String to Int) or Add Non-Nullable to an existing argument (from String to String!)
TYPE_REMOVED Remove a Type
INPUT_ADDED Add a Non-Nullable field to an Input type
INPUT_TYPE_CHANGED Change an input field type (from String to Int) or Add Non-Nullable to an existing input type field (from String to String!)
ENUM_REMOVED Remove a value from an Enum Type

Please note that this does not cover all possible Breaking Changes or Dangerous Changes that can happen to a Schema. They will be added gradually over the Development. All the possible changes that can happen to a Schema is as follows,

Type Action Severity
Field Added Safe
Field Removed Breaking
Field Description Added Safe
Field Description Removed Safe
Field Description Changed Safe
Field Deprecation Added Safe
Field Deprecation Removed Dangerous
Field Deprecation Changed (i.e. Reason Change/Addition/Removal) Safe
Field Type Changed Breaking
Argument Added Required ? Breaking : Dangerous
Argument Removed Breaking
Argument Type Changed Required ? Breaking : Dangerous OR TypeChange ? Breaking : Dangerous
Argument Description Added Safe
Argument Description Removed Safe
Argument Description Changed Safe
Argument Default Value Added Dangerous
Argument Default Value Removed Dangerous
Argument Default Value Changed Dangerous
Type (Object, Enum, Interface) Added Safe
Type (Object, Enum, Interface) Removed Breaking
Type Kind Changed (ex: Change Object type to Scalar type, Change Interface type to Enum type, Change Object type to Interface type) Breaking
Type Description Added Safe
Type Description Changed Safe
Type Description Removed Safe
Input Field Added Required ? Breaking : Dangerous
Input Field Removed Breaking
Input Field Description Added Safe
Input Field Description Removed Safe
Input Field Description Changed Safe
Input Field Default Value Added Dangerous
Input Field Default Value Removed Dangerous
Input Field Default Value Changed Dangerous
Input Field Type Changed Required ? Breaking : Dangerous (String! to String is Dangerous) OR TypeChange ? Breaking : Dangerous (String to Int is Breaking)
Enum Added (Add a new enum value to Enum type) Dangerous
Enum Removed Breaking
Enum Description Added Safe
Enum Description Changed Safe
Enum Description Removed Safe
Enum Deprecation Added Safe
Enum Deprecation Removed Dangerous
Enum Deprecation Changed (i.e. Reason Change/Addition/Removal) Safe
Interface Implementation Added Dangerous (Clients might have not programmed defensively against this change)
Interface Implementation Removed Breaking
Union Member Removed Breaking
Union Member Added Dangerous
Directive Added Safe
Directive Removed Breaking
Directive Description Added Safe
Directive Description Changed Safe
Directive Description Removed Safe
Directive Argument Added Required ? Breaking : Dangerous
Directive Argument Removed Breaking
Directive Argument Description Added Safe
Directive Argument Description Removed Safe
Directive Argument Description Changed Safe
Directive Argument Default Value Added Dangerous
Directive Argument Default Value Removed Dangerous
Directive Argument Default Value Changed Dangerous
Directive Argument Type Changed Required ? Breaking : Dangerous (String! to String is Dangerous) OR TypeChange ? Breaking : Dangerous (String to Int is Breaking)
Query Type Changed Breaking
Mutation Type Changed Breaking
Subscription Type Changed Breaking
Composition Check Errors
Error Code Error Description
NO_QUERIES None of the composed subgraphs expose any query.
TYPE_KIND_MISMATCH A type has the same name in different subgraphs, but a different kind. (Ex: one definition is an Object type but another is an Interface.)
KEY_FIELDS_SELECT_INVALID_TYPE The fields argument of @key directive includes a field whose type is a list, interface, or union type. Fields of these types cannot be part of a @key
INVALID_FIELD_SHARING A field that is non-shareable in at least one subgraph is resolved by multiple subgraphs.

Please note that this does not cover all possible Errors that can happen when composing a Supergraph. They will be added gradually over the Development. All possible errors can be found on this.

Implementation

Technologies

Schema Registry will be exposed as a GraphQL service, written in Ballerina. Initially the Schema Registry will use a Java based GraphQL Parser to parse GraphQL schemas due to limited time available. Later on, the existing Ballerina GraphQL document parser can be improved to parse GraphQL SDL.

Datasource

Initially File Based data storage will be used to store the data of the Schema Registry and it will be made in a Datasource Agnostic manner, so later users can use any datasource that they prefer to store the data.

Implementation Steps

Schema Registry will take an Incremental Development approach where,

  1. Implement the Schema Registry so that a Single Subgraph can be composed into a Supergraph
  2. Improve the Schema Registry so that two unrelated Subgraphs (i.e. No Entities on Subgraphs) can be composed into a Supergraph
  3. Improve the Schema Registry so that two related Subgraphs (i.e. Subgraphs have Entities) can be composed into a Supergraph

Future Tasks

  • Integrate with Router monitoring to give more insight on Breaking Changes
  • Add UI to the Schema Registry to ease the management
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module/graphql Issues related to Ballerina GraphQL module Status/Active Proposals that are under review Team/PCM Protocol connector packages related issues Type/Proposal
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants