Skip to content

Commit

Permalink
feat(supergraph): ability to configure subgraphs
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Mar 22, 2024
1 parent b48a77d commit 52f74e7
Show file tree
Hide file tree
Showing 7 changed files with 320 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .changeset/lemon-flies-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@graphql-mesh/supergraph": minor
"@graphql-mesh/types": patch
---

Ability to configure subgraphs
39 changes: 31 additions & 8 deletions packages/legacy/handlers/supergraph/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { process } from '@graphql-mesh/cross-helpers';
import { PredefinedProxyOptions, StoreProxy } from '@graphql-mesh/store';
import {
getInterpolatedHeadersFactory,
ResolverData,
stringInterpolator,
} from '@graphql-mesh/string-interpolation';
import {
Expand Down Expand Up @@ -81,6 +82,7 @@ export default class SupergraphHandler implements MeshHandler {
}

async getMeshSource({ fetchFn }: GetMeshSourcePayload): Promise<MeshSource> {
const subgraphConfigs = this.config.subgraphs || [];
this.fetchFn = fetchFn;
const supergraphSdl = await this.getSupergraphSdl();
const operationHeadersFactory =
Expand All @@ -89,17 +91,38 @@ export default class SupergraphHandler implements MeshHandler {
: undefined;
const schema = getStitchedSchemaFromSupergraphSdl({
supergraphSdl,
onExecutor: ({ endpoint }) => {
onExecutor: ({ subgraphName, endpoint }) => {
const subgraphConfiguration: YamlConfig.SubgraphConfiguration = subgraphConfigs.find(
subgraphConfig => subgraphConfig.name === subgraphName,
) || {
name: subgraphName,
};
return buildHTTPExecutor({
endpoint,
...(subgraphConfiguration as any),
fetch: fetchFn,
headers:
operationHeadersFactory &&
(execReq =>
operationHeadersFactory({
env: process.env,
context: execReq.context,
})),
headers(executorRequest) {
const subgraphConfiguration = subgraphConfigs.find(
subgraphConfig => subgraphConfig.name === subgraphName,
);
const headers = {};
const resolverData: ResolverData = {
root: executorRequest.rootValue,
env: process.env,
context: executorRequest.context,
info: executorRequest.info,
args: executorRequest.variables,
};
if (subgraphConfiguration?.operationHeaders) {
const headersFactory = getInterpolatedHeadersFactory(
subgraphConfiguration.operationHeaders,
);
Object.assign(headers, headersFactory(resolverData));
}
if (operationHeadersFactory) {
Object.assign(headers, operationHeadersFactory(resolverData));
}
},
} as HTTPExecutorOptions);
},
batch: this.config.batch == null ? true : this.config.batch,
Expand Down
70 changes: 70 additions & 0 deletions packages/legacy/handlers/supergraph/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,74 @@ type SupergraphHandler @md {
operationHeaders: Any

batch: Boolean

subgraphs: [SubgraphConfiguration!]
}

type SubgraphConfiguration {
"""
The name of the subgraph you want to configure
"""
name: String!

"""
A url or file path to your remote GraphQL endpoint.
If you provide a path to a code file(js or ts),
other options will be ignored and the schema exported from the file will be used directly.
"""
endpoint: String

"""
JSON object representing the Headers to add to the runtime of the API calls only for operation during runtime
"""
operationHeaders: JSON
"""
Use HTTP GET for Query operations
"""
useGETForQueries: Boolean
"""
HTTP method used for GraphQL operations
"""
method: GraphQLHandlerHTTPMethod
"""
Request Credentials if your environment supports it.
[See more](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)
@default "same-origin"
"""
credentials: RequestCredentials
"""
Path to a custom W3 Compatible WebSocket Implementation
"""
webSocketImpl: String
"""
Path to the introspection
You can separately give schema introspection or SDL
"""
source: String
"""
SSE - Server Sent Events
WS - New graphql-ws
LEGACY_WS - Legacy subscriptions-transport-ws
"""
subscriptionsProtocol: SubscriptionProtocol
"""
URL to your endpoint serving all subscription queries for this source
"""
subscriptionsEndpoint: String
"""
Retry attempts if fails
"""
retry: Int
"""
Timeout in milliseconds
"""
timeout: Int
"""
JSON object representing the `connectionParams` from a WebSocket connection to add to the runtime of the API calls only for operation during runtime.
More information about the WebSocket `connectionParams`:
- When using `subscriptionsProtocol=WS` (graphql-ws): https://github.com/enisdenjo/graphql-ws/blob/master/docs/interfaces/client.ClientOptions.md#connectionparams
- When using `subscriptionsProtocol=LEGACY_WS` (subscriptions-transport-ws): https://github.com/apollographql/subscriptions-transport-ws/blob/51270cc7dbaf09c7b9aa67368f1de58148c7d334/README.md#subscriptionclient
"""
connectionParams: JSON
}
76 changes: 76 additions & 0 deletions packages/legacy/types/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3177,10 +3177,86 @@
},
"batch": {
"type": "boolean"
},
"subgraphs": {
"type": "array",
"items": {
"$ref": "#/definitions/SubgraphConfiguration"
},
"additionalItems": false
}
},
"required": ["source"]
},
"SubgraphConfiguration": {
"additionalProperties": false,
"type": "object",
"title": "SubgraphConfiguration",
"properties": {
"name": {
"type": "string",
"description": "The name of the subgraph you want to configure"
},
"endpoint": {
"type": "string",
"description": "A url or file path to your remote GraphQL endpoint.\nIf you provide a path to a code file(js or ts),\nother options will be ignored and the schema exported from the file will be used directly."
},
"operationHeaders": {
"type": "object",
"properties": {},
"description": "JSON object representing the Headers to add to the runtime of the API calls only for operation during runtime"
},
"useGETForQueries": {
"type": "boolean",
"description": "Use HTTP GET for Query operations"
},
"method": {
"type": "string",
"enum": ["GET", "POST"],
"description": "HTTP method used for GraphQL operations (Allowed values: GET, POST)"
},
"credentials": {
"type": "string",
"enum": ["omit", "include"],
"description": "Request Credentials if your environment supports it.\n[See more](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)\n\n@default \"same-origin\" (Allowed values: omit, include)"
},
"webSocketImpl": {
"type": "string",
"description": "Path to a custom W3 Compatible WebSocket Implementation"
},
"source": {
"type": "string",
"description": "Path to the introspection\nYou can separately give schema introspection or SDL"
},
"subscriptionsProtocol": {
"type": "string",
"enum": ["SSE", "WS", "LEGACY_WS"],
"description": "SSE - Server Sent Events\nWS - New graphql-ws\nLEGACY_WS - Legacy subscriptions-transport-ws (Allowed values: SSE, WS, LEGACY_WS)"
},
"subscriptionsEndpoint": {
"type": "string",
"description": "URL to your endpoint serving all subscription queries for this source"
},
"retry": {
"type": "integer",
"description": "Retry attempts if fails"
},
"timeout": {
"type": "integer",
"description": "Timeout in milliseconds"
},
"batch": {
"type": "boolean",
"description": "Enable/Disable automatic query batching"
},
"connectionParams": {
"type": "object",
"properties": {},
"description": "JSON object representing the `connectionParams` from a WebSocket connection to add to the runtime of the API calls only for operation during runtime.\nMore information about the WebSocket `connectionParams`:\n - When using `subscriptionsProtocol=WS` (graphql-ws): https://github.com/enisdenjo/graphql-ws/blob/master/docs/interfaces/client.ClientOptions.md#connectionparams\n - When using `subscriptionsProtocol=LEGACY_WS` (subscriptions-transport-ws): https://github.com/apollographql/subscriptions-transport-ws/blob/51270cc7dbaf09c7b9aa67368f1de58148c7d334/README.md#subscriptionclient"
}
},
"required": ["name"]
},
"ThriftHandler": {
"additionalProperties": false,
"type": "object",
Expand Down
74 changes: 74 additions & 0 deletions packages/legacy/types/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,80 @@ export interface SupergraphHandler {
schemaHeaders?: any;
operationHeaders?: any;
batch?: boolean;
subgraphs?: SubgraphConfiguration[];
}
export interface SubgraphConfiguration {
/**
* The name of the subgraph you want to configure
*/
name: string;
/**
* A url or file path to your remote GraphQL endpoint.
* If you provide a path to a code file(js or ts),
* other options will be ignored and the schema exported from the file will be used directly.
*/
endpoint?: string;
/**
* JSON object representing the Headers to add to the runtime of the API calls only for operation during runtime
*/
operationHeaders?: {
[k: string]: any;
};
/**
* Use HTTP GET for Query operations
*/
useGETForQueries?: boolean;
/**
* HTTP method used for GraphQL operations (Allowed values: GET, POST)
*/
method?: 'GET' | 'POST';
/**
* Request Credentials if your environment supports it.
* [See more](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)
*
* @default "same-origin" (Allowed values: omit, include)
*/
credentials?: 'omit' | 'include';
/**
* Path to a custom W3 Compatible WebSocket Implementation
*/
webSocketImpl?: string;
/**
* Path to the introspection
* You can separately give schema introspection or SDL
*/
source?: string;
/**
* SSE - Server Sent Events
* WS - New graphql-ws
* LEGACY_WS - Legacy subscriptions-transport-ws (Allowed values: SSE, WS, LEGACY_WS)
*/
subscriptionsProtocol?: 'SSE' | 'WS' | 'LEGACY_WS';
/**
* URL to your endpoint serving all subscription queries for this source
*/
subscriptionsEndpoint?: string;
/**
* Retry attempts if fails
*/
retry?: number;
/**
* Timeout in milliseconds
*/
timeout?: number;
/**
* Enable/Disable automatic query batching
*/
batch?: boolean;
/**
* JSON object representing the `connectionParams` from a WebSocket connection to add to the runtime of the API calls only for operation during runtime.
* More information about the WebSocket `connectionParams`:
* - When using `subscriptionsProtocol=WS` (graphql-ws): https://github.com/enisdenjo/graphql-ws/blob/master/docs/interfaces/client.ClientOptions.md#connectionparams
* - When using `subscriptionsProtocol=LEGACY_WS` (subscriptions-transport-ws): https://github.com/apollographql/subscriptions-transport-ws/blob/51270cc7dbaf09c7b9aa67368f1de58148c7d334/README.md#subscriptionclient
*/
connectionParams?: {
[k: string]: any;
};
}
/**
* Handler for OData
Expand Down
28 changes: 27 additions & 1 deletion website/src/generated-markdown/SupergraphHandler.generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,30 @@ If you provide a path to a code file(js or ts),
other options will be ignored and the schema exported from the file will be used directly.
* `schemaHeaders` (type: `Any`)
* `operationHeaders` (type: `Any`)
* `batch` (type: `Boolean`)
* `batch` (type: `Boolean`)
* `subgraphs` (type: `Array of Object`, required):
* `name` (type: `String`, required) - The name of the subgraph you want to configure
* `endpoint` (type: `String`) - A url or file path to your remote GraphQL endpoint.
If you provide a path to a code file(js or ts),
other options will be ignored and the schema exported from the file will be used directly.
* `operationHeaders` (type: `JSON`) - JSON object representing the Headers to add to the runtime of the API calls only for operation during runtime
* `useGETForQueries` (type: `Boolean`) - Use HTTP GET for Query operations
* `method` (type: `String (GET | POST)`) - HTTP method used for GraphQL operations
* `credentials` (type: `String (omit | include)`) - Request Credentials if your environment supports it.
[See more](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials)

@default "same-origin"
* `webSocketImpl` (type: `String`) - Path to a custom W3 Compatible WebSocket Implementation
* `source` (type: `String`) - Path to the introspection
You can separately give schema introspection or SDL
* `subscriptionsProtocol` (type: `String (SSE | WS | LEGACY_WS)`) - SSE - Server Sent Events
WS - New graphql-ws
LEGACY_WS - Legacy subscriptions-transport-ws
* `subscriptionsEndpoint` (type: `String`) - URL to your endpoint serving all subscription queries for this source
* `retry` (type: `Int`) - Retry attempts if fails
* `timeout` (type: `Int`) - Timeout in milliseconds
* `batch` (type: `Boolean`) - Enable/Disable automatic query batching
* `connectionParams` (type: `JSON`) - JSON object representing the `connectionParams` from a WebSocket connection to add to the runtime of the API calls only for operation during runtime.
More information about the WebSocket `connectionParams`:
- When using `subscriptionsProtocol=WS` (graphql-ws): https://github.com/enisdenjo/graphql-ws/blob/master/docs/interfaces/client.ClientOptions.md#connectionparams
- When using `subscriptionsProtocol=LEGACY_WS` (subscriptions-transport-ws): https://github.com/apollographql/subscriptions-transport-ws/blob/51270cc7dbaf09c7b9aa67368f1de58148c7d334/README.md#subscriptionclient
36 changes: 36 additions & 0 deletions website/src/pages/docs/handlers/supergraph.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,42 @@ sources:
myTokenHeader: MY_TOKEN_VALUE
```
### Configuring subgraphs within the supergraph
You can also configure subgraphs within the supergraph by providing the subgraph name in order to
change the endpoint and headers for each subgraph.
```yaml
sources:
- name: Supergraph
handler:
supergraph:
source: http://some-source.com/supergraph.graphql
subgraphs:
accounts:
endpoint: http://localhost:9871/graphql
operationHeaders:
Authorization: "Bearer {context.headers['x-accounts-token']}"
reviews:
endpoint: http://localhost:9872/graphql
operationHeaders:
Authorization: "Bearer {context.headers['x-accounts-token']}"
products:
endpoint: http://localhost:9873/graphql
operationHeaders:
Authorization: "Bearer {context.headers['x-accounts-token']}"
inventory:
endpoint: http://localhost:9874/graphql
operationHeaders:
Authorization: "Bearer {context.headers['x-accounts-token']}"
```
### Config API Reference
import API from '../../../generated-markdown/SoapHandler.generated.md'
<API />
## Using Mesh to build the supergraph
You can provide the existing subgraphs within GraphQL Mesh, or you can use
Expand Down

0 comments on commit 52f74e7

Please sign in to comment.