-
Notifications
You must be signed in to change notification settings - Fork 13
Context differences between top-level and stitching resolvers #68
Comments
Yeah I see there's an issue with extraContext not being passed to the top-level resolvers. Internally, there's a context object like: const context = {
..extraContext,
YourNamespaceOne,
YourNamespaceTwo,
..
} but in mapResolvers regular resolvers get passed The resolvers should get passed something like: My concern with changing the stitching resolvers is that we're using the other contexts for our stitching resolvers. IMO it makes sense to have access to other contexts when stitching multiple data-sources together. If that behavior is changed, it should be a major release and ideally [for me] there would be an "escape hatch" to access other contexts. |
FWIW const extra = extraContext(req);
return sources.reduce((allContext, source) => {
const sourceContext =
typeof source.context === 'function'
? source.context(req)
: source.context;
return {
...allContext,
[source.namespace]: { ...extra, ...sourceContext },
};
}, {}); My thoughts on
|
This is a good question. Should we leave all data source contexts available in stitching? I don't have a strong opinion or use case either way — but we should probably decide on something to stick with and add documentation. |
I can reproduce this behavior with a gist. With latest GrAMPS 1.1.0, I do not see fields from I have a hard time following. Can we split this into two separate issues?
|
https://github.com/gramps-graphql/gramps/commits/master @jlengstorf I can confirm that the current npm version Not sure how this happened because the manual release happened after 3be3006 Currently published: const getContext = req => sources.reduce((allContext, source) => {
const sourceContext = typeof source.context === 'function' ? source.context(req) : source.context;
return _extends({}, allContext, {
[source.namespace]: sourceContext
});
}, extraContext(req)); Should be: const getContext = req => {
const extra = extraContext(req);
return sources.reduce((allContext, source) => {
const sourceContext = typeof source.context === 'function' ? source.context(req) : source.context;
return _extends({}, allContext, {
[source.namespace]: _extends({}, extra, sourceContext)
});
}, {});
}; |
@ecwyne I think the published release is missing #59 as well. Can't see it here: https://unpkg.com/@gramps/[email protected]/dist/lib/mapResolvers.js |
@jlengstorf @ecwyne @timrs2998 Extra Context My thoughts: unless we have a separate config option for stitching Data Source Context I can support an argument for either of the possible solutions:
Personally, I think I lean toward consistency across all contexts. An alternative to this would be to make it configurable via a simple either or option or via something like |
I like the consistency from option 2. However, there is no valid use case for non-stitching resolvers to have access to other contexts. How about a third option:
|
related: gramps-graphql/gramps#66
so I'm thinking the contexts should be setup to enable stitching other data-sources, but only for stitching resolvers |
@timrs2998 It seems to me the whole point of stitching is to extend another data source, so what you say makes total sense. So you're suggesting context be structured something like...: const topLevelContext = {
[dataSource.namespace]: dataSource.context
...extraContext
}
const stitchingContext = {
[dataSource.namespace]: dataSource.context
...otherDataSourceContextsKeyedByNamespace
...extraContext
} Is that correct? |
No, I'm thinking keys should be more explicit for const topLevelContext = {
[dataSource.namespace]: dataSource.context,
extraContext,
}
const stitchingContext = {
[dataSource.namespace]: dataSource.context,
extraContext,
externalContexts: otherDataSourceContextsKeyedByNamespace,
} |
I'm not sure what happened with 1.1.0 — sorry about that. I just manually released 1.1.1, which has the extra contexts: https://unpkg.com/@gramps/[email protected]/dist/gramps.js RE: stitching, I'm leaning toward @timrs2998 suggestion that we explicitly place external contexts under a property. We've got it so data sources only have their own context + extra context now, so it's like this:
Adding external data source contexts explicitly would look something like:
I think we can use |
@jlengstorf Thanks for the release. Will try to test and reach out if I have any other issues. Maybe in keeping with the fact that the context from other data sources is accessible only in stitching resolvers, we could call that key |
I'm alright with The final format would be: {
...[dataSource.namespace].context,
...extraContext,
stitching: allOtherDataSourceContexts,
} |
I actually started digging into this, and it turns out that the reason we didn't do this originally is because it's not possible. 😄 So, stitching is done when we bring all of the data sources together. This means that — during stitching — all data sources share the same context. That means that our context object during stitching should be something like this, assuming we have const context = {
DSOne: { /* ... */ },
DSTwo: { /* ... */ },
...extraContext,
}; Our stitching resolvers will need to use the correct namespaces. Ultimately, this is probably a good thing for clarity: stitching: {
linkTypeDefs: `
extend type Query {
test: String
}
`,
resolvers: () => ({
Query: {
test: (_, { id }, context) => context.DSOne.getStringValue(id),
},
}),
}, How it should work:Here’s a slight variation on @grxy's original example: const context = (_, __, ctx) => JSON.stringify(Object.keys(ctx));
/*
* For more information on the building GrAMPS data sources, see
* https://gramps.js.org/data-source/data-source-overview/
*/
export default {
// TODO: Rename the context to describe the data source.
namespace: 'StitchingTest',
context: {
test1: true,
test2: true,
},
typeDefs: `
type Query {
context: String
}
type Test {
context: String
}
`,
resolvers: {
Query: {
context,
},
},
stitching: {
linkTypeDefs: `
extend type Query {
test: Test
}
`,
resolvers: () => ({
Query: {
test: () => ({}),
},
Test: {
context,
},
}),
},
}; The extra context was missing, so I've tweaked the contexts so we end up with this: {
"data": {
"context": "[\"addedFromExtraContext\",\"test1\",\"test2\"]",
"test": {
"context": "[\"addedFromExtraContext\",\"StitchingTest\"]"
}
}
} I'm also working on an example to show data stitching actually happening inside of GrAMPS, because so far I haven't seen anyone actually using it. Will follow up once I have it working. |
Extra context is now included both _inside_ data source namespaced contexts and _at the top level_ to ensure it’s available for schema stitching. close #68
Extra context is now included both _inside_ data source namespaced contexts and _at the top level_ to ensure it’s available for schema stitching. close #68
Okay — I've got schema stitching working using the GrAMPS pattern. I've written up a walkthrough on how to do this, which I'll add to the docs shortly. Anyone have a few minutes to run through this and let me know if you hit any snags or need extra clarification along the way? Thanks! Part 1: Create a Data SourceTo get started, let's create our first data source using the GraphQL CLI # Use npx to run the command without having to install anything globally
npx graphql-cli create -b gramps-graphql/data-source-base data-source-stitchingtest
# Move into the folder that was just created
cd $_ In const getContext = (_, __, ctx) => Object.keys(ctx);
export default {
namespace: 'StitchingTest',
typeDefs: `
type Query {
getContext: [String]
getById(id: ID!): STX_Test
}
type STX_Test {
id: ID
value: String
}
`,
context: {
getValue: id => ({
id,
value: `from StitchingTest with ID “${id}”`,
}),
},
resolvers: {
Query: {
getContext,
getById: (_, { id }, ctx) => ctx.getValue(id),
},
},
}; This data source exposes two queries:
Let's test this out by running the data source: yarn dev At http://localhost:8080/playground, run the following query: {
getContext
getById(id: 3) {
value
}
} We should see the following return value: {
"data": {
"getContext": [
"getValue"
],
"getById": {
"value": "from StitchingTest with ID “3”"
}
}
} So far so good. Add Local Schema StitchingNext, let's add some schema stitching to the existing data source, just to make sure it's working the way we expected. In export default {
namespace: 'StitchingTest',
typeDefs: `...`,
context: { /* ... */ },
resolvers: { /* ... */ },
stitching: {
linkTypeDefs: `
extend type Query {
getStitchingContext: [String]
}
`,
resolvers: () => ({
Query: {
getStitchingContext: getContext,
},
}),
},
}; Restart the data source in your terminal ( {
getContext
+ getStitchingContext
getById(id: 3) {
value
}
} We should see the following return value: {
"data": {
"getContext": [
"getValue"
],
"getStitchingContext": [
"StitchingTest"
],
"getById": {
"value": "from StitchingTest with ID “3”"
}
}
}
Add a Second Data SourceNext, let's create a second data source so we can set up more realistic schema stitching. In your terminal, move into the same directory where your first data source was created, then run the following to create a second data source: # Use npx to run the command without having to install anything globally
npx graphql-cli create -b gramps-graphql/data-source-base data-source-stitchingtwo
# Move into the folder that was just created
cd $_ In export default {
namespace: 'StitchingTwo',
typeDefs: `
type Query {
getSomeValues(val: ID): ST2_Values
}
type ST2_Values {
foo: String
bar: String
bat: String
}
`,
context: {
getSomeValues: val => ({
foo: `Schema (val: ${val})`,
bar: `Stitching (val: ${val})`,
bat: `Rules (val: ${val})`,
}),
},
resolvers: {
Query: {
getSomeValues: (_, { val }, ctx) => ctx.getSomeValues(val),
},
},
}; This data source is pretty bare bones: it has a single query — To test it, let's fire up the new data source along with the original data source: yarn dev --data-source ../data-source-stitchingtest
Open http://localhost:8080/playground and update the query to call {
getContext
getStitchingContext
getById(id: 3) {
value
}
+ getSomeValues(val: 2) {
+ foo
+ bar
+ bat
+ }
} The output should be: {
"data": {
"getContext": [
"getValue"
],
"getStitchingContext": [
"StitchingTwo",
"StitchingTest"
],
"getById": {
"value": "from StitchingTest with ID “3”"
},
"getSomeValues": {
"foo": "Schema (val: 2)",
"bar": "Stitching (val: 2)",
"bat": "Rules (val: 2)"
}
}
} Use Schema Stitching to Combine the Two Data SourcesFinally, let's add export default {
namespace: 'StitchingTwo',
typeDefs: `...`,
context: { /* ... */ },
resolvers: { /* ... */ },
stitching: {
linkTypeDefs: `
extend type STX_Test {
stitched: ST2_Values
}
`,
resolvers: mergeInfo => ({
STX_Test: {
stitched: {
fragment: 'fragment StitchingTestField on STX_Test { id }',
resolve: ({ id }, args, context, info) =>
mergeInfo.delegate(
'query',
'getSomeValues',
{ val: id },
context,
info,
),
},
},
}),
},
}; First, we use Then, in Under the hood, this is done using With the stitching config in place, let's fire it up and test it. Run the following command to start a gateway with both data sources: yarn dev --data-source ../data-source-stitchingtest Then, open http://localhost:8080/playground and add the {
getContext
getStitchingContext
getById(id: 3) {
value
+ stitched {
+ foo
+ bar
+ bat
+ }
}
getSomeValues(val: 2) {
foo
bar
bat
}
} Once executed, we'll see the following: {
"data": {
"getContext": [
"getValue"
],
"getStitchingContext": [
"StitchingTwo",
"StitchingTest"
],
"getById": {
"value": "from StitchingTest with ID “3”",
"stitched": {
"foo": "Schema (val: 3)",
"bar": "Stitching (val: 3)",
"bat": "Rules (val: 3)"
}
},
"getSomeValues": {
"foo": "Schema (val: 2)",
"bar": "Stitching (val: 2)",
"bat": "Rules (val: 2)"
}
}
} And that's it! We now have one data source including data from a second data source as part of its own queries. |
I have the following test data source:
My GrAMPS config is as follows:
When I run the following query:
...I get the following output:
Is it intentional that the GraphQL context for stitching resolvers is different from the top-level resolvers in that the top-level resolvers merge the current data source context into the main context object and the stitching resolvers add the namespace context at
context.<namespace>
?Another thing to note is that extraContext only seems to add my req key for stitching resolvers and not top-level resolvers. Is this a known issue or by-design?
The text was updated successfully, but these errors were encountered: