Pass GraphQL Header from request to subsequent Axios Request

129 views Asked by At

I have an Angular application which is using Apollo Client for querying a GraphQL Server from a NestJS application. This NestJS application is executing a request through Axios to an external Backend.

How could be passed the client header set in all the GraphQL requests to the backend request through Axios?

Apollo Client GraphQL Request > NestJS Apollo Server GraphQL Resolver > Axios HTTP Request.

// Configure the Apollo Client with custom Authorization header
function createApollo() {
  const { api } = AngularConfigService.getConfig();

  const authLink = setContext((_, { headers }) => {
    return {
      headers: {
        ...headers,
        Authorization: `Bearer ${localStorage.getItem('jwt_token')}`,
      },
    };
  });

  return {
    link: authLink.concat(
      new HttpLink({ uri: `${api?.host}:${api?.port}/graphql` }),
    ),
    cache: new InMemoryCache({ addTypename: false }),
    defaultOptions: {
      // more content here ...
    } as DefaultOptions,
  };
}

@NgModule({
  imports: [],
  providers: [
    Apollo,
    { provide: APOLLO_OPTIONS, useFactory: createApollo, },
  ]
})

In the Angular application service I request from GraphQL server as following:

getUsers(args: GraphQL.QueryUsersArgs) {
   return this.graphQLDataService.query<GraphQL.UserDto[]>(usersQuery, args); // where usersQuery contains the GraphQL users query
}

I connect the request from the GraphQL Server to Axios through the following service method in the NestJS server:

getAllUsers(
  args: UsersArgsDto,
): Observable<DataResponse<UserDto[]>> {
  const queryParams = new URLSearchParams();

  this.getQueryFilterParams<UsersQueryFilterInput>(
    queryParams,
    args.queryFilters,
  );
  this.getPaginationParams(queryParams, args.pagination);
  this.getSortingParams(queryParams, args.sort);

  return this.httpService
    .get('/users', {
      ...this.globalConfig,
      params: queryParams,
    })
    .pipe(
      map((data) => data.data),
      validateObject(DataResponse<UsersDto[]>),
      catchError((err) => {
        throw err;
      }),
    );
}

I have access to the GraphQL request header through the context in the query or mutation, but I have not access in the Axios HTTP request linked to that.

Would be possible to pass to the HTTP context?

1

There are 1 answers

0
frankfullstack On BEST ANSWER

I finally got it working by using the following service:

@Injectable({ scope: Scope.REQUEST })
export class GraphQLContextService {
  constructor(@Inject(CONTEXT) context: GraphQLCustomExecutionContext) {}

  getContextRequestHeaders() {
    return this.context.req.headers;
  }
}

Then I can use in the required service:

constructor(private readonly gqlContextService: GraphQLContextService)

getAllUsers(
  args: UsersArgsDto,
): Observable<DataResponse<UserDto[]>> {
  const queryParams = new URLSearchParams();

  this.getQueryFilterParams<UsersQueryFilterInput>(
    queryParams,
    args.queryFilters,
  );
  this.getPaginationParams(queryParams, args.pagination);
  this.getSortingParams(queryParams, args.sort);

  return this.httpService
    .get('/users', {
      ...this.globalConfig,
      params: queryParams,
      // Here we can link the GraphQL Headers to the Axios request
      headers: this.gqlContextService.getContextRequestHeaders(); 
    })
    .pipe(
      map((data) => data.data),
      validateObject(DataResponse<UsersDto[]>),
      catchError((err) => {
        throw err;
      }),
    );
}