Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added middleware support #170

Merged
merged 3 commits into from
Jun 24, 2022

Conversation

avsokolov
Copy link
Contributor

Add the ability to provide simple client middleware for common request and response handling. It can be useful for logging, requests tracing, errors handling etc. when used singe client in a large app.

@avsokolov avsokolov changed the title added middleware support feat: added middleware support Jun 11, 2020
@vitorcamachoo
Copy link

Hi,
is this possible to add headers on request middleware ?

@suds-sky
Copy link

I am looking for a feature that exactly does this, is there a reason why it is not looked into for more than an year. It would be good to get this in unless there is an alternative solution available

@jasonkuhrt
Copy link
Member

New PRs welcome if this one has stalled

@suds-sky
Copy link

Thanks @jasonkuhrt, @avsokolov Do you want to rebase your branch from master so that we can get this reviewed and get it merged. If you don't find time then I am happy to create a new PR

@vrecan
Copy link

vrecan commented Mar 3, 2022

@suds-sky Anyway we could get this merged in? I wanted to send logs to APM (elastic) when we get errors and the only way to do that is to wrap graphql-request. This is going to be really fragile and I would love to do it as middleware instead.

import { GraphQLClient } from 'graphql-request/';
import * as Dom from 'graphql-request/types.dom';
import {
  GraphqlQuery,
  Variables,
  RequestDocument,
  GraphqlMutation,
  BatchRequestDocument,
} from 'graphql-request/types';
import { apm } from '@elastic/apm-rum';


// CustomGraphqQLClient is required because middleware is not supported as of writing this. There is a pr
// 
class CustomGraphQLClient {
  private client: GraphQLClient;

  constructor(private url: string, private options?: Dom.RequestInit) {
    this.client = new GraphQLClient(url, options);
  }
  request<T = any, V = Variables>(
    document: RequestDocument,
    variables?: V,
    requestHeaders?: Dom.RequestInit['headers']
  ): Promise<T> {
    return this.makeRequest(document, variables);
  }

  rawRequest<T = any, V = Variables>(
    query: string,
    variables?: V,
    requestHeaders?: Dom.RequestInit['headers']
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      this.rawRequest(query, variables, requestHeaders)
        .then(resolve)
        .catch((err: any) => {
          console.error(err);
          apm.captureError(err);
          return reject(err);
        });
    });
  }

  batchRequests<T extends any = any, V = Variables>(
    documents: BatchRequestDocument<V>[],
    requestHeaders?: Dom.RequestInit['headers']
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      this.batchRequests(documents, requestHeaders)
        .then(resolve)
        .catch((err: any) => {
          console.error(err);
          apm.captureError(err);
          return reject(err);
        });
    });
  }

  setHeaders(headers: Dom.RequestInit['headers']): GraphQLClient {
    return this.setHeaders(headers);
  }

  setHeader(key: string, value: string): GraphQLClient {
    return this.setHeader(key, value);
  }

  setEndpoint(value: string): GraphQLClient {
    return this.setEndpoint(value);
  }

  query<T = GraphqlQuery, V = Variables>(
    document: RequestDocument,
    variables?: V
  ): Promise<T> {
    return this.makeRequest<T, V>(document, variables);
  }

  mutation<T = GraphqlMutation, V = Variables>(
    document: RequestDocument,
    variables?: V
  ): Promise<T> {
    return this.makeRequest<T, V>(document, variables);
  }

  private makeRequest<T = GraphqlQuery, V = Variables>(
    document: RequestDocument,
    variables?: V
  ): Promise<T> {
    return new Promise((resolve, reject) => {
      this.client
        .request(document, variables)
        .then(resolve)
        .catch((err: any) => {
          console.error(err);
          apm.captureError(err);
          return reject(err);
        });
    });
  }
}

export const graphqlClient = new CustomGraphQLClient(
  import.meta.env.VITE_API_ENDPOINT,
  {
    credentials: 'include',
  }
) as unknown as GraphQLClient;

@jasonkuhrt
Copy link
Member

@suds-sky probably a new PR

@AshotN
Copy link

AshotN commented Jun 18, 2022

Was there something wrong with this PR that it never got merged?

@jasonkuhrt
Copy link
Member

@AshotN The author became unresponsive. I never looked closely at the PR.

@avsokolov
Copy link
Contributor Author

avsokolov commented Jun 18, 2022

Sorry, I forgot about the merge request. But anyway it's still actual for me.

@jasonkuhrt What should I do to actualize and merge it?

@jasonkuhrt
Copy link
Member

jasonkuhrt commented Jun 20, 2022

@avsokolov Thanks for checking in. I'll take a look some time next week hopefully now that I know you're still active.

Copy link
Member

@jasonkuhrt jasonkuhrt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some docs, otherwise LGTM

Copy link
Member

@jasonkuhrt jasonkuhrt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just one doc typo.

README.md Outdated Show resolved Hide resolved
@avsokolov
Copy link
Contributor Author

@jasonkuhrt I have rebased to the latest master and added docs. Please review it

Co-authored-by: Jason Kuhrt <jasonkuhrt@me.com>
@jasonkuhrt jasonkuhrt merged commit dec0319 into graffle-js:master Jun 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants