apollo-serverapollo-federation

How can I add 2 buildService (upload and header) to apollo federation?


Is there any option to add both header and upload to buildService in apollo federation? I want my headers for authentication and upload for uploading file. buildService does not support return object.

const gateway = new ApolloGateway({
  buildService({ name, url }) {
    return new RemoteGraphQLDataSource({
      url,
      willSendRequest({ request, context }: { request: any; context: any }) {
        request?.http?.headers?.set(
          "authorization",
          context.auth ? context.auth : ""
        );
        request?.http?.session?.set(
          "session",
          context.session ? context.session : ""
        );
        request?.http?.sessionStore?.set(
          "sessionStore",
          context.sessionStore ? context.sessionStore : ""
        );
      },
    });
  },
});

how can I also add upload file to my buildService?


Solution

  • Found the solution, if you extend the FileUploadDataSource somehow works:

    import {
      ApolloGateway,
      GraphQLDataSourceProcessOptions,
    } from '@apollo/gateway';
    import { Fetcher } from '@apollo/utils.fetcher';
    import FileUploadDataSource from '@profusion/apollo-federation-upload';
    import { FileUploadDataSourceArgs } from '@profusion/apollo-federation-upload/build/FileUploadDataSource';
    import { GraphQLResponse } from 'apollo-server-types';
    
    class AuthenticationAndUpload extends FileUploadDataSource {
      constructor(config: FileUploadDataSourceArgs) {
        super(config);
        const nativeFetcher = this.fetcher;
        const newFetcher: Fetcher = (url, options) => {
          let plainHeaders: Record<string, string> = options?.headers || { '': '' };
          if (options?.headers?.raw) {
            const headers = options.headers as unknown as IterableIterator<
              [string, string]
            >;
            plainHeaders = Object.fromEntries<string>(headers) as Record<
              string,
              string
            >;
          }
          return nativeFetcher(url, { ...options, headers: plainHeaders });
        };
        this.fetcher = newFetcher;
      }
      willSendRequest({ request, context }: GraphQLDataSourceProcessOptions) {
        request?.http?.headers?.set(
          'authorization',
          context.request.headers?.authorization
            ? context.request.headers.authorization
            : ''
        );
      }
      didReceiveResponse({
        response,
        context,
      }: {
        response: GraphQLResponse;
        context: GraphQLDataSourceProcessOptions['context'];
      }) {
        return response;
      }
    }
    
    const gateway = new ApolloGateway({
      buildService({ url }) {
        return new AuthenticationAndUpload({ url });
      },
    });