graphql-client.ts 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. *
  6. * Adapted from https://github.com/prisma/graphql-request, Copyright (c) 2017 Graphcool, MIT
  7. */
  8. import { RuntimeContext } from '../mol-task';
  9. import { AssetManager, Asset } from './assets';
  10. type Variables = { [key: string]: any }
  11. interface GraphQLError {
  12. message: string
  13. locations: { line: number, column: number }[]
  14. path: string[]
  15. }
  16. interface GraphQLResponse {
  17. data?: any
  18. errors?: GraphQLError[]
  19. extensions?: any
  20. status: number
  21. [key: string]: any
  22. }
  23. interface GraphQLRequestContext {
  24. query: string
  25. variables?: Variables
  26. }
  27. export class ClientError extends Error {
  28. response: GraphQLResponse;
  29. request: GraphQLRequestContext;
  30. constructor(response: GraphQLResponse, request: GraphQLRequestContext) {
  31. const message = `${ClientError.extractMessage(response)}: ${JSON.stringify({ response, request })}`;
  32. super(message);
  33. this.response = response;
  34. this.request = request;
  35. // this is needed as Safari doesn't support .captureStackTrace
  36. if (typeof Error.captureStackTrace === 'function') {
  37. Error.captureStackTrace(this, ClientError);
  38. }
  39. }
  40. private static extractMessage(response: GraphQLResponse): string {
  41. return response.errors ? response.errors[0].message : `GraphQL Error (Code: ${response.status})`;
  42. }
  43. }
  44. export class GraphQLClient {
  45. constructor(private url: string, private assetManager: AssetManager) { }
  46. async request(ctx: RuntimeContext, query: string, variables?: Variables): Promise<Asset.Wrapper<'json'>> {
  47. const body = JSON.stringify({ query, variables }, null, 2);
  48. const url = Asset.getUrlAsset(this.assetManager, this.url, body);
  49. const result = await this.assetManager.resolve(url, 'json').runInContext(ctx);
  50. if (!result.data.errors && result.data.data) {
  51. return {
  52. data: result.data.data,
  53. dispose: result.dispose
  54. };
  55. } else {
  56. const errorResult = typeof result.data === 'string' ? { error: result.data } : result.data;
  57. throw new ClientError({ ...errorResult }, { query, variables });
  58. }
  59. }
  60. }