aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.41k stars 2.12k forks source link

@http endpoint with POST request graphql query returns MappingTemplate error #8586

Closed sky4git closed 3 years ago

sky4git commented 3 years ago

Before opening, please confirm:

JavaScript Framework

Next.js

Amplify APIs

GraphQL API

Amplify Categories

api

Environment information

``` # Put output below this line System: OS: Windows 10 10.0.19043 CPU: (8) x64 Intel(R) Core(TM) i5-1035G7 CPU @ 1.20GHz Memory: 1.57 GB / 7.60 GB Binaries: Node: 14.15.4 - C:\Program Files\nodejs\node.EXE npm: 7.19.0 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: 91.0.4472.101 Edge: Spartan (44.19041.1023.0), Chromium (91.0.864.67) Internet Explorer: 11.0.19041.1 npmPackages: @ampproject/toolbox-optimizer: undefined () @babel/cli: ^7.12.10 => 7.13.14 @babel/core: ^7.12.10 => undefined (7.13.14, ) @babel/plugin-transform-typescript: ^7.12.1 => 7.13.0 @babel/preset-env: ^7.12.11 => 7.13.12 @fortawesome/fontawesome-svg-core: ^1.2.32 => 1.2.35 @fortawesome/free-brands-svg-icons: ^5.15.1 => 5.15.3 @fortawesome/free-solid-svg-icons: ^5.15.1 => 5.15.3 @fortawesome/react-fontawesome: ^0.1.14 => 0.1.14 @material-ui/core: ^4.11.2 => 4.11.3 @material-ui/icons: ^4.11.2 => 4.11.2 @material-ui/lab: ^4.0.0-alpha.57 => 4.0.0-alpha.57 @material-ui/styles: ^4.11.2 => 4.11.3 @next/bundle-analyzer: ^10.2.3 => 10.2.3 @stripe/stripe-js: ^1.13.2 => 1.13.2 @types/node: ^14.14.20 => 14.14.37 @types/react: ^16.14.2 => 16.14.5 amphtml-validator: undefined () arg: undefined () async-retry: undefined () async-sema: undefined () aws-amplify: latest => 3.3.26 axios: ^0.21.1 => 0.21.1 bfj: undefined () braintree-web: ^3.70.0 => 3.76.0 cacache: undefined () cache-loader: undefined () ci-info: undefined () comment-json: undefined () compression: undefined () conf: undefined () content-type: undefined () cookie: undefined () cross-fetch: ^3.0.6 => 3.1.2 cross-fetch-polyfill: 0.0.0 css-loader: undefined () debug: undefined () devalue: undefined () escape-string-regexp: undefined () eslint-plugin-react-hooks: ^4.2.0 => 4.2.0 file-loader: undefined () find-cache-dir: undefined () find-up: undefined () fresh: undefined () gzip-size: undefined () http-proxy: undefined () ignore-loader: undefined () is-animated: undefined () is-docker: undefined () is-wsl: undefined () json5: undefined () jsonwebtoken: undefined () loader-utils: undefined () lodash.curry: undefined () lru-cache: undefined () nanoid: ^3.1.20 => undefined (3.1.22, ) neo-async: undefined () next: ^10.0.5 => 10.1.2 ora: undefined () postcss-flexbugs-fixes: undefined () postcss-loader: undefined () postcss-preset-env: undefined () postcss-scss: undefined () qrcode.react: ^1.0.1 => 1.0.1 react: ^16.13.1 => 16.14.0 (17.0.1) react-dom: ^16.13.1 => 16.14.0 react-google-recaptcha: ^2.1.0 => 2.1.0 recast: undefined () resolve-url-loader: undefined () sass: ^1.32.2 => 1.32.8 sass-loader: undefined () schema-utils: undefined () semver: undefined () send: undefined () source-map: undefined () string-hash: undefined () strip-ansi: undefined () terser: undefined () text-table: undefined () thread-loader: undefined () typescript: ^3.9.7 => 3.9.9 unistore: undefined () web-vitals: undefined () webpack: undefined () webpack-sources: undefined () zen-observable: ^0.8.15 => 0.8.15 (0.7.1) npmGlobalPackages: @aws-amplify/cli: 5.1.0 amplify-cli: 1.0.0 aws-cdk: 1.112.0 npm-check-updates: 9.1.0 npm: 7.19.0 sequelize-cli: 6.2.0 ```

Describe the bug

I have defined the GraphQL query in schema.json like the following:

type Query{
  getMyCustomData(myvar: String!): String
    @http(
      method: POST
      url: "https://XXXXXXXXXX.execute-api.ap-southeast-2.amazonaws.com/prod/someMethod"
   )
}

With the query I want to invoke/execute API Gateway endpoint with POST method and get some JSON response.

Above schema.graphql query generates a query definition in src/queries.ts like the following:

export const getMyCustomData = /* GraphQL */ `
  query getMyCustomData (
    $query: QueryGetMyCustomDataQueryInput
    $body: QueryGetMyCustomDataBodyInput
  ) {
    getMyCustomData (query: $query, body: $body)
  }
;

Now using this in function to run GraphQL Query. I have define it like the following:

let res = await API.graphql({
        query: getMyCustomData
        variables: {
          query: { myvar: "ap-southeast-2" },
          body: { myvar: "ap-southeast-2" },
        },
});

The ERROR: I always get response as error:

{
    "data": {
        "getMyCustomData": null
    },
    "errors": [
        {
            "path": [
                "getMyCustomData"
            ],
            "data": null,
            "errorType": "MappingTemplate",
            "errorInfo": null,
            "locations": [
                {
                    "line": 2,
                    "column": 3,
                    "sourceName": null
                }
            ],
            "message": "Template transformation yielded an empty response."
        }
    ]
}

Expected behavior

await API.graphql should return some response from API Gateway, instead it looks like AppSync is not understanding what data the API.graphql function is sending to it.

Reproduction steps

Check Describe the Bug section.

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

There is no documentation about GraphQL type Query with POST method usage with amplify js anywhere. If there is a working example somewhere, I am happy to look at it.

chrisbonifacio commented 3 years ago

I deleted my comment before about API.post because I totally forgot we had an @http directive and that's what you're using lol

Did you follow the docs here and try to do the same with Mutation? It seems Query is dedicated to handling GET requests where Mutation handles POST, PUT, and PATCH. I think the end result should be the same though.

https://docs.amplify.aws/cli/graphql-transformer/http#usage

Screen Shot 2021-07-14 at 1 41 16 PM
sky4git commented 3 years ago

Yes, I tried with Mutation too. It ends up with the same bug of MappingTemplate.

chrisbonifacio commented 3 years ago

What is the API Gateway response supposed to look like?

chrisbonifacio commented 3 years ago

Haven't been able to reproduce the issue but this setup worked for me.

Schema

type Mutation {
  addPost(title: String!, description: String!, views: Int): String
    @http(
      method: POST
      url: "https://xxxxxxxx.execute-api.us-east-2.amazonaws.com/dev/post"
    )
}

API Call

const res = await API.graphql(
  graphqlOperation(addPost, {
    body: {
      title: "Testing My API Gateway",
      description: 'this should return a string of "post added"',
      views: 1,
    },
  })
);

Lambda

exports.handler = async(event, ctx) => {
    console.log("EVENT\n" + JSON.stringify(event, null, 2))
    console.info("CONTEXT\n" + JSON.stringify(ctx, null, 2))

    const response = "post added"
    return response;
};

Response

Screen Shot 2021-07-15 at 11 44 16 AM
chrisbonifacio commented 3 years ago

whoops, did not mean to close. Was trying to make another comment lol

Was going to say the issue might be in the VTL file that was generated.

The path to the relevant file in your project should be similar to this 8586-graphql/amplify/backend/api/8586graphql/build/resolvers/Mutation.addPost.res.vtl

#if( $ctx.result.statusCode == 200 || $ctx.result.statusCode == 201 )
  #if( $ctx.result.headers.get("Content-Type").toLowerCase().contains("xml") )
$utils.xml.toJsonString($ctx.result.body)
  #else
$ctx.result.body
  #end
#else
$util.qr($util.appendError($ctx.result.body, $ctx.result.statusCode))
#end

Compare the above to your file and make sure that it's returning ctx.result.body

sky4git commented 3 years ago

When API Gateway resource/method has IAM authorisation on, in that case it gives "mapping template" error. Without IAM authorisation, it will work fine.

So in the case of, IAM authorisation required where should we need to pass the "Authorization" header.

chrisbonifacio commented 3 years ago

@sky4git I think your return value will have to be one of your models already authorized by IAM. Otherwise, I'm not sure that it's possible because of this line in the documentation for the @http directive.

https://docs.amplify.aws/cli/graphql-transformer/http/#generates

Note that @http transformer does not support calling other AWS services where Signature Version 4 signing process is required.

Here's some relevant documentation for the IAM authorization mode

https://aws.amazon.com/blogs/mobile/graphql-security-appsync-amplify/

sky4git commented 3 years ago

Yes. It doesn't seem to work for Authorised API gateway methods.
It would be good if we can apply the IAM policy from amplify-cli when we want to invoke API gateway method.

FireAndIceFrog commented 2 years ago

Hi! I am having a very simmilar problem with the appsync application, I have it pointing the a REST endpoint with no auth however im using custom resolvers instead of the http directive.

github-actions[bot] commented 1 year ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server amplify-help forum.