-
Notifications
You must be signed in to change notification settings - Fork 4k
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
[aws-appsync] code-first schema generation #9305
Comments
I'm a bit hesitant about this "code-first" approach. IMO a GraphQL schema file is code and I do not see the necessity to create a new CDK specific DSL for creating GraphQL schemas. In practice, you also want to use the schema to generate clients or model files (e.g. Amplify), add custom directives (see Amplify directives or custom directives in gqlgen), etc. Worse, the CDK code will likely use make use of files derived from the schema by external tools. E.g., a generator creates model files from the types in the schema. These model files could be used by frontend or backend files, which, in turn, are imported and deployed by the CDK (e.g. through The only advantage I see is "type-safety" when attaching resolvers to queries/mutations as it will become impossible to attach a resolver to a query/mutation that does not exist. But then again, there is still no type-safety within the VTL mapping templates (e.g. a template can still return a data structure that does not match the return type of the query/mutation) - the pre-defined MappingTemplates are limited to the most simple use cases. IMO, it feels wrong to create a new language on top of GraphQL, which already is specialized query language. That is just my 2 cents though. Either way, there is a lot to consider (external tooling, interoperability, extensibility) for this to be useful in practice. |
@asterikx Thanks for the feedback 😊 I definitely certain elements to graphql.
I totally agree with this! The current implementation of Mapping Templates is super limiting and at the end of the day, I end up writing a lot more VTL than I would like. @duarten is working on an RFC #175 to provide better infrastructure.
A lot of the motivation behind adding a We drew inspiration from other code-first libraries such as GraphQL Nexus. I think there are pros/cons to both approaches. But a
What if we just generated a file in
I'm not sure I understand this completely. Is the assumption that we would use an external library to generate the schema? We actually were going to generate schema in-memory. So the entirety of the schema generation would be done in house. |
Thanks for the explanation @BryanPan342!
I see. That definitely makes sense.
Yup, I just assumed this would be done by
No. I assumed that schema generation would be done in house. Suppose that I want to use the model files (types) generated by |
Ooo I see now. I think there still are work arounds for this even with the code-first approach. For example, I believe to start, you could just have an empty Overall, these are really great points that we will keep in mind during implementation but seem out of scope for the use case of a code-first approach. |
Hey @BryanPan342, Thanks for the awesome improvements! I wonder if you could provide more detailed examples leveraging these new features. |
That would solve the bootstrapping issue.
I think what you suggest is interleaving synth and build actions? I. e. first synth the stack that contains the AppSync API (which will output a
Yeah, it's hard to foresee all scenarios. It is probably best to just try it out and tackle the issues as they arise. I think it's important to keep developer experience in mind here. |
@asterikx Thanks for all the awesome feedback! Really helped me scope the issue 😊 Developer experience is very near and dear to me so discussions like these @andrestone currently working on the obejct type definition and basically the foundation of code-first schema. I'm thinking about putting more finer grain examples in issues found in the checklist. Wdyt? Here is a comment on object types. |
UPDATE Check out this repository to see how to generate SWAPI in a code-first approach. Note: Most of the CDK isn't merged in yet, but this is representative of what it looks like to make a large graphql api. |
Apologies if not directly relevant here... but I'm trying to get my head around best structure for appsync in CDK with multiple stacks (microservices).
I could imagine doing this fully code-first (even though messy and dependency 'fun') but wondered if there were already best practices or examples of this somewhere ? Thanks for the consideration |
So are you still asking about how to do this code first? or are you asking more in terms of a schema-first architecture. For code-first, you can define the schema outside of cdk! So if you really wanted to, you can essentially create your object types, enum types, interfaces etc. in separate folders representing each CDK stack, and then merge it together in an Here is an example: SWAPI. |
Thanks for the reply, maybe to try state my problem clearer... What would be best practices... When putting a single AppSync GraphqlApi in front of multiple I was thinking of something like: stack/appsync
construct/main.ts - where actual `new appsync.GraphqlApi()` lives
stack/micro_service_1
construct/appsync.ts - resources and schema obj for service 1
construct/schema.graphql - schema file for service 1
stack/micro_service_2
construct/appsync.ts - resources and schema obj for service 1
construct/schema.graphql - schema file for service 1 Note; I'm using I really like that CDK can do the leg works of converting I would like to minimize stack dependencies... I think I could do something like this In import * as service_1 from '../../micro_service_1/construct/appsync.ts`;
import * as service_2 from '../../micro_service_1/construct/appsync.ts`;
const schema = new Schema();
service_1.addToSchema(schema);
service_2.addToSchema(schema); But if those I note there is Thought that doesn't tick the box of the service still being able to Your thoughts are most appreciated |
I guess you should work with You could introduce some checks to prevent that from happening, but I think using outputs, dependency and conditions would be the "best practice" here. Take a look at this: https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CfnOutput.html Edit: To make it even clearer, the idea is to have the schema definition pieces as outputs from each microservice stack and stitch them together in another stack (the one that would update the schema in the api resource). |
Picking up on @ranguard's question
I have been trying to implement this approach but the
Is this a bug or intended? |
This is actually a really good question. So the code-first approach essentially creates an Now, for the code-first approach, the neat thing about the Here is an example of how you can take advantage of these types: example. If you want, you call also declare this schema outside of the scope of CDK and import it in and add to the Schema as you go. I believe that is also another workaround (note if you do it this way, I would recommend having CDK deploy the AppSync stack last). |
@BryanPan342..... Ahhh that makes more sense to me now. So I suppose the best way to handle this is to store a reference to the Schema and update it as you see fit across multiple stacks and just keep the appsync stack on its own and rerun a pipeline for it whenever there is a change to the Schema externally. Thanks also for the SWAPI example, I will take a proper look at that shortly 👍 |
@kfcobrien yup! thats how i would go about it :) Feel free to let me know your thoughts on how we can improve the experience. I think the next step is definitely improving the mapping templates so that the resolver can be easily added inline. But would love to hear your thoughts! |
@BryanPan342 I think a construct for the Schema that implements some Is it possible to replace the entire schema in appsync after it has been deployed from another stack? If so (or if not too big a feature request), you could pretty much decouple everything.
This way we need only touch the schema and graphql stacks only once and then keep the infrastructure required to add to them entirely in their own respective stacks. |
I've been doing a bit more reading and I think what I'm actually after is schema-stitching, or taking that further GraphQL federation support in AppSync would be even better - such that each service can be responsible for it's own content in a shared schema and then be stitched together by a gateway. Some mention of it in aws/aws-appsync-community but no timeline. With graphql-transform-federation it seems to be possible to hack something together now but an officially supported mechanism would go a long way. As my end points aren't public yet feels like might be worth running multiple GraphAPI end points for now and waiting for AppSync to catch up. |
@ranguard +1 here; I actually wrote a custom script to stitch the schema together as new microservices are added... I do feel CDK could help here until AppSync catches up (not sure what their timelines are). |
@chrisadriaensen just to clarify, this is for schema-first right? So like having separate |
Hi, I don't know if this is helpful but I have solved this in a slightly different way. Each of our microservices are in a separate nested stack. The nested stacks get composed into one stack for the backend. I create the API in the parent stack and pass down the API as a prop to the nested stacks. Then I can add queries, mutations and types into the common API reference. CDK builds the final schema during deployment. The problem I am finding is debugging schema issues using this code-first approach. I have to push the schema and watch it fail in Cloudformation, the errors in Cloudformation don't pinpoint where the schema is broken and its a pain to track down these schema errors. |
@hirenumradia hmm yeah I remember facing similar issues when I was originally building and testing the framework We do very high level testing to make sure each type is defined as per the GraphQL specs. But I'm sure there is a lot of room for improvement in terms of developer experience. Ideally there would be some testing mechanism that would happen during build time, but I haven't thought too deeply on how we can accomplish it and keep the package tight. |
@BryanPan342 Got ya. Do you know of any ways I could debug this easier? Its killing my productivity at the mo :( I'm having to comment out different parts of the Code-first schema to see what could be breaking it, then trying a deploy. Does AppSync log the schema in Cloudformation on failure? |
@hirenumradia the biggest thing that helped me debug my schema/resolver issues was enabling all of the logging in appsync. Checkout the docs here for information on enabling this and then you will get much clearer failure messages in cloudwatch. EDIT: on second reading this may not be helpful for your case since this is during CFN deployment and most of the issues I have experienced weren't because of invalid schema but because of mis-matching schema/resolver config. |
@hirenumradia what kind of issues are u running into? maybe we can write some tests for it if it is more of a graphql problem than deployment! |
Thanks @BryanPan342 @MrArnoldPalmer. 👍🏽 So we are at the start of setting up our infrastructure hence why these types of issues more likely to come up. Background Our setup has one Backend Stack that composes the various microservices. Each microservice is a Nested Stack that has any common infrastructure resources such as the API passed down to them. The types and the fields are composed within these Nested Stacks, specifically, I am creating these types and fields within a CDK construct so that each use case that we are developing is separated into a "cloud component". The issue When composing the schema, I was able to put together the schema that passed the static compilation steps of Typescript, however, the syntactical validation was failing when deploying the schema. I was previously generating a schema file that was "stitching together" multiple types and resolvers via a code generation module I wrote. I was able to see the schema before deploys and fix the issues. I moved onto this code-first approach for maintainability. These were the Cloudformation errors I was getting
Immediate Thoughts / Suggestions
If you would like to chat in more depth, I'm happy to jump on a quick call and I can show you. |
@BryanPan342 I feel like we are ready to close this one out and track bugs and features in separate smaller issues since we have an initial implementation released. Tell me if you'd prefer to hold it open though. Schema Validation here: #14022 |
@MrArnoldPalmer good idea! though I do quite enjoy having a place for discussions about the improvements of the code-first approach, I think we should probably keep it to the AppSync tracking issue |
|
Allow definition of the
schema
to happen within thecdk
stack. The generatedschema
would be directly inserted into the CloudFormation Template at runtime.Use Case
Currently there are only two ways to define schema: ,
inline
or with afile
.Inline
File
A
code-first
approach would allow for definition of the GraphQLschema
to happen inline alongsideresolvers
.Proposed Solution
Write the
schema
definition along with the resolvers inline.Implementation
Other
I will be using this issue as a way to track the smaller components of this feature request and as a point of discussion for implementation.
Visit this repository to see how to generate SWAPI in a code-first approach.
Features
This is a 🚀 Feature Request
The text was updated successfully, but these errors were encountered: