sid88in / serverless-appsync-plugin

serverless plugin for appsync
MIT License
951 stars 188 forks source link

combine mapping templates #77

Open honkskillet opened 6 years ago

honkskillet commented 6 years ago

Enhancement: The idea would be to optionally have just a single mapping template file for a given query/mutation. Ofter the response template is just a single line forwarding the response value anyways. Cuts down on clutter in the file tree.

sid88in commented 6 years ago

Can you please explain with an example!

honkskillet commented 6 years ago

Sure, say for a query addPost, i currently have two files

{ ## addPost-request-mapping-template.txt
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "addPost",
        "arguments":  $util.toJson($context.arguments)
    }
}

and

 ## addPost-response-mapping-template.txt
util.toJson($context.result)

All the response mapping templates in my project look like this. They just pass the rsults straight through. It would be better if I could have...

## addPost-mapping-templates.txt
{ request:{ 
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "addPost",
        "arguments":  $util.toJson($context.arguments)
    }
},
reponse:  util.toJson($context.result)
}

or something similar

lucallero commented 5 years ago

It seems that request/response fields are restricted to be a file path to be read. Have tried a file reference variable but it didn't work. For example:

mappingTemplates:
      # Customer
      - dataSource: Dynamo_customer
        type: Mutation 
        field: createCustomer
        request: ${file(customer-templates.vtl):create}
        response: ${file(customer-templates.vtl):response}
      - dataSource: Dynamo_customer 
        type: Mutation 
        field: deleteCustomer
        request: ${file(customer-templates.vtl):delete}
        response: ${file(customer-templates.vtl):response}
bboure commented 5 years ago

@honkskillet I see you are using Lambda (at least in this example). I just have another approach for that. Basically I just have 2 Lambda templates: one for requests and one for responses. Since all lambdas use the same templates, I just reuse the same one for all resolvers.

I see you have "field": "addPost" in your request template. Not sure why you need it? Usually, the called lambda function should already give you that info, unless you have the same lambda for all resolvers? In fact, I already contacted AWS concerning that. I think that the context parameter of the lambda should give the graphQl path it resolves for out of the box.

bboure commented 5 years ago

@honkskillet Would something like this be what you are looking for?

- dataSource: mySource
  type: Query
  field: field
  templates: "myTemplates.vtl"
## BEGIN REQUEST
{ ## addPost-request-mapping-template.txt
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "addPost",
        "arguments":  $util.toJson($context.arguments)
    }
}
## END REQUEST

## BEGIN RESPONSE
$util.toJson($context.result)
## END RESPONSE

Then the plugin would extract both templates and use accordingly.

This is an idea we could consider I guess

cameroncf commented 5 years ago

One alternate way to handle this is to keep "common responses" apart form the type specific request templates.

- dataSource: myDSN
  type: Query
  field: getFoo
  request: foo/Query.getFoo.vtl
  response: common/One.response.vtl
- dataSource: myDSN
  type: Query
  field: getBar
  request: bar/Query.getBar.vtl
  response: common/One.response.vtl
- dataSource: myDSN
  type: Query
  field: listBar
  request: bar/Query.listBar.vtl
  response: common/Many.response.vtl

I keep a common set of response templates for "One" item, and another for "Many" items. Between these two I find that it solves 99% of my situations without any repetition.