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
AppsyncFunction Interface #24
Comments
So I posted this from the wrong GitHub account 😂 let me know what you think about this. I could try to create a PR if needed! |
Hey! I'm glad you like the project and thanks for the feedback. One of the design tenets with Functionless is to try and map AWS services directly into native TypeScript syntax, which is why I was trying to represent type Func = (id: string) => Person So, we would have to use an object to represent the args instead, like you're suggesting: new AppsyncFunction(
($context: $Context<Source>, args: { id: string }): Person | undefined => {
// blah
}) If we go this route, then we can simplify things even further by placing args back in the new AppsyncFunction(($context: $Context<Args, Source>) => {
const userId = $context.arguments.id;
}); This may be even better since it matches the underlying Appsync environment exactly 1:1. https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html. Would it sill make it easy to integrate with the graphql codegen plugin? RE: the bug when the argument name doesn't match the signature: ((_$context, userId) => { // notice the argument name has changed At the very least, we can fix this in the typescript plugin by allowing developers to name those args whatever they please and mapping them back to the signature's argument name. Thoughts? |
I really like the solution of including the arguments as an object in the context to match the VTL template. To make integration with graphql codegen easy what we need is to make the function accept an object with arguments as properties. It gives you TArgs, TResult, TSource for each resolver. I spent some time trying to come up with a generic type that transforms the type I'm not sure what I'm saying is very clear (I can share the repo where I tried this maybe if that's helpful) but to answer the question first solution would make it easy to integrate with graphql codegen. |
I'm always open to seeing a repo, so if you're ok sharing, please do. I'm also convinced of the first solution. Functionless should always uphold the tenet of complying 1;1 with the underlying VTL environment. I'll work on a PR for this. |
This will also fix #25 |
Still working on the PR, but this is what an this.updateName = new AppsyncFunction(
($context: $Context<{ id: string; name: string }>) =>
this.personTable.updateItem({
key: {
id: $util.dynamodb.toDynamoDB($context.arguments.id),
},
update: {
expression: "SET #name = :name",
expressionNames: {
"#name": "name",
},
expressionValues: {
":name": $util.dynamodb.toDynamoDB($context.arguments.name),
},
},
})
); I like how we can now infer the types instead of declaring them in Alternative with explicit type: this.updateName = new AppsyncFunction<{id: string, name: string}, Person>(
($context) =>
this.personTable.updateItem({
key: {
id: $util.dynamodb.toDynamoDB($context.arguments.id),
},
update: {
expression: "SET #name = :name",
expressionNames: {
"#name": "name",
},
expressionValues: {
":name": $util.dynamodb.toDynamoDB($context.arguments.name),
},
},
})
);
|
Since this is a breaking change, I propose we also rename
|
@sho-ai-main @mathisobadia - PR is open, would love your feedback. #27 |
@sam-goodwin I wrote some feedback on the PR, I think overall it's a great improvement and make everything more consistent with appsync terminology. |
I just tested this PR locally to add graphql codegen, you can check what this looks like here: you get lots of new AppsyncResolver<
MutationResolvers["addPerson"]["args"],
MutationResolvers["addPerson"]["result"],
MutationResolvers["addPerson"]["parent"]
> but I could create a wrapper now without issues and everything works well already! |
This is awesome!! Thanks for doing that. We should provide some documentation on how to do this in the readme and update the example to use it. Is it possible to add the wrapper class without taking a dependency on the graphql tools? Maybe that doesn't matter? |
@sam-goodwin I can open a pull request to do those changes if you want! I just tried to create the wrapper but can an error I don't totally understand when I try to deploy the stack (full code here ): The wrapper is type ResolverBase = {
args: ResolverArguments;
parent: unknown;
result: unknown;
};
class AppsyncResolverWrapper<
ResolverType extends ResolverBase
> extends AppsyncResolver<
ResolverType["args"],
ResolverType["result"],
ResolverType["parent"]
> {
constructor(
fn: ResolverFunction<
ResolverType["args"],
ResolverType["result"],
ResolverType["parent"]
>
) {
super(fn);
}
} And the error I get when deploying is
I still don't understand fully the code so I don't know where to look to fix this. Anyway I can still open the pull request with the previous version without a wrapper as that's working and the difference is not that big! let me know what you think. |
Ah, that's because the typescript plug-in is not transforming the function into its AST form. The compiler looks for the We will have to update this code to support classes that extend |
Opened an issue to track this and provided some more information #30 |
Also opened an issue to track the wrapper class specifically: #31 |
I love this project and I've been trying to use it in addition with graphql codegen to generate types automatically from the schema. While trying to do this I've had issues with the API for the AppsyncFunction class
The issue I see is that the name of the function parameter influences the result of the mapping template so if I use the code from the example app
This works
But this doesn't work because the name of the parameter is not the same as the name of the graphql query parameter
This means that no amount of code generation will help here as even if we successfully generate a type that looks like
(id: string) => ProcessedPerson | null
but don't use the right parameter name then you will not see a typescript error there.Ideally I think that the interface for this function could look something like
Then the arguments would be used with args.id so slightly less good looking but with destructuring the difference is small, but this has the benefit of better type safety as using args.userId would result in a typescript error.
As an added benefit this would make using functionless with graphql codegen typescript resolver plugin much easier
The text was updated successfully, but these errors were encountered: