Aws-mobile-appsync-sdk-js: Adding custom headers

Created on 3 Jun 2018  路  6Comments  路  Source: awslabs/aws-mobile-appsync-sdk-js

Hi,

I am looking for the way to add a custom header in all the request sent to AppSync. I was able to do it with the Amplify library but since I need some the advanced functionnalities from aws-appsync-sdk, I am trying to do it with the appsync-sdk as well.

I didn't find any documentation on this topic. Is there a way to do it?

For example, I tried to add request option when creating the AWSAppSyncClient without any success:

const appSyncClient = new AWSAppSyncClient({
  url: config.amplify_config.aws_appsync_graphqlEndpoint,
  request: async (operation) => {
    const user = await Auth.currentUserInfo();
    logger.debug("AWSAppSyncClient request:", user);
    operation.setContext({
      headers: {
        'amt-custom-username': user.username
      }
    });
  },
  region: config.amplify_config.aws_appsync_region,
  auth: {
    type: AUTH_TYPE.AWS_IAM,
    credentials: () => Auth.currentCredentials(),
  },
});

Most helpful comment

Hi @OlivierPT

Try this sample code here

In order to read the custom header on your request mapping template use this $context.request.headers.your_header_name

I used this on the previous sample

{
    "version": "2017-02-28",
    "payload": {
        "id": "${context.arguments.id}",
        "title": "$context.request.headers.hi"
    }
}

Let me know how it goes

All 6 comments

Hi @OlivierPT

Try this sample code here

In order to read the custom header on your request mapping template use this $context.request.headers.your_header_name

I used this on the previous sample

{
    "version": "2017-02-28",
    "payload": {
        "id": "${context.arguments.id}",
        "title": "$context.request.headers.hi"
    }
}

Let me know how it goes

Hi @elorzafe ,

Thanks, it works! :)

Is this method not working after access-control-expose-headers was there (set to x-amzn-RequestId,x-amzn-ErrorType,x-amz-user-agent,x-amzn-ErrorMessage,Date,x-amz-schema-version)? I cannot seem to set the custom http headers now. Below are code in angular.

EDIT: Looks like I mistyped headers as header.

import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
import { HttpLinkModule, HttpLink } from 'apollo-angular-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { NgModule } from '@angular/core';
import { createAppSyncLink, AUTH_TYPE } from 'aws-appsync';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';

import { HelloService } from './hello.service';

export function createApollo(httpLink: HttpLink, hello: HelloService) {
  const url = 'https://xxxxxxxxxxxxxxxxxxxxxxxxxx.appsync-api.us-east-1.amazonaws.com/graphql';
  const link = createAppSyncLink({
    url,
    region: 'us-east-1',
    auth: {
      type: AUTH_TYPE.API_KEY,
      apiKey: 'da2-xxxxxxxxxxxxxxxxxxxxxxxxxx'
    },
    complexObjectsCredentials: null,
    resultsFetcherLink: ApolloLink.from([
      setContext(async (request, previousContext) => {
        const context = {
          header: {
            ...previousContext.headers,
            ticket: await hello.say('world').toPromise()
          }
        };
        console.log(context);
        return context;
      }),
      createHttpLink({ uri: url })
    ]),
  });

  return { cache: new InMemoryCache(), link };
}

@NgModule({
  exports: [ApolloModule, HttpLinkModule],
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink, HelloService],
    },
  ],
})
export class GraphQLModule { }

@elorzafe you are an absolute legend. Copied your sample into my project and used $context.request.headers.your_header_name in my request mapping to get my custom header. Worked first time!

In my case I am accessing a graphql api through a lambda and using IAM credentials. Here is my code to setup the AWSAppSyncClient if anyone is interested.

const AWS = require('aws-sdk');
const AWSAppSyncClient = require('aws-appsync').default;
const { createAppSyncLink } = require('aws-appsync');
require('es6-promise').polyfill();
require('isomorphic-fetch');
const { ApolloLink } = require('apollo-link');
const { createHttpLink } = require('apollo-link-http');
const { setContext } = require('apollo-link-context');

const buildApiClient = (connection, customHeaders) => {
  const { URL, REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN } = connection;

  AWS.config.update({
    region: REGION,
    credentials: new AWS.Credentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN),
  });
  const { credentials } = AWS.config;

  const AppSyncConfig = {
    url: URL,
    region: REGION,
    auth: {
      type: 'AWS_IAM',
      credentials,
    },
    disableOffline: true,
  };

  const appsyncClient = new AWSAppSyncClient(AppSyncConfig, {
    defaultOptions: {
      query: {
        fetchPolicy: 'network-only',
        errorPolicy: 'all',
      },
    },
    link: createAppSyncLink({
      ...AppSyncConfig,
      resultsFetcherLink: ApolloLink.from([
        setContext((request, previousContext) => ({
          headers: {
            ...previousContext.headers,
            ...customHeaders,
          },
        })),
        createHttpLink({
          uri: AppSyncConfig.url,
        }),
      ]),
    }),
  });

  return appsyncClient;
};

module.exports = buildApiClient;

What about response headers?

I have resolver as HTTP URL which returns some headers as well. But those response headers are not coming in-appsync response? While I can access the response headers using $context.result.headers and it's working but how can i pass these as headers in appsync response.

I solved my problem with this

import React from 'react'

import AWSAppSyncClient, { createAppSyncLink } from 'aws-appsync'
import { ApolloProvider } from '@apollo/react-hooks'
import { ApolloLink, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'

import AppSyncConfig from '@components/aws-config'
import { get } from '@common/Lodash'

const apolloClient = props => {
  const token = sessionStorage.getItem('token')

  const AppSyncProps = {
    url: AppSyncConfig.graphqlEndpoint,
    region: AppSyncConfig.region,
    auth: {
      type: AppSyncConfig.authenticationType,
      apiKey: AppSyncConfig.apiKey,
    },
    disableOffline: true,
  }

  const apolloPartialProps = {
    link: createAppSyncLink({
      ...AppSyncProps,
      resultsFetcherLink: ApolloLink.from([
        setContext((request, previousContext) => ({
          headers: {
            ...previousContext.headers,
            'x-api-key': token,
          },
        })),
        createHttpLink({
          uri: AppSyncProps.url,
        }),
      ]),
    }),
  }

  return new AWSAppSyncClient(AppSyncProps, apolloPartialProps)
}

export const client = apolloClient()

export const GraphqlProvider = ({ children }) => (
  <ApolloProvider client={client}>{children}</ApolloProvider>
)


export default GraphqlProvider

Note @apollo/client and @apollo/react-hooks

Was this page helpful?
0 / 5 - 0 ratings