simple-graphql-client.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import { DocumentNode } from 'graphql';
  2. import { GraphQLClient } from 'graphql-request';
  3. import { print } from 'graphql/language/printer';
  4. import { Curl } from 'node-libcurl';
  5. import { AttemptLogin, AttemptLoginVariables, CreateAssets } from 'shared/generated-types';
  6. import {
  7. AUTH_TOKEN_KEY,
  8. SUPER_ADMIN_USER_IDENTIFIER,
  9. SUPER_ADMIN_USER_PASSWORD,
  10. } from 'shared/shared-constants';
  11. import { ATTEMPT_LOGIN } from '../../admin-ui/src/app/data/definitions/auth-definitions';
  12. import { CREATE_ASSETS } from '../../admin-ui/src/app/data/definitions/product-definitions';
  13. import { getConfig } from '../src/config/vendure-config';
  14. // tslint:disable:no-console
  15. /**
  16. * A minimalistic GraphQL client for populating and querying test data.
  17. */
  18. export class SimpleGraphQLClient {
  19. private client: GraphQLClient;
  20. private authToken: string;
  21. private channelToken: string;
  22. constructor(private apiUrl: string = '') {
  23. this.client = new GraphQLClient(apiUrl);
  24. }
  25. setAuthToken(token: string) {
  26. this.authToken = token;
  27. this.setHeaders();
  28. }
  29. setChannelToken(token: string) {
  30. this.channelToken = token;
  31. this.setHeaders();
  32. }
  33. /**
  34. * Performs both query and mutation operations.
  35. */
  36. query<T = any, V = Record<string, any>>(query: DocumentNode, variables?: V): Promise<T> {
  37. const queryString = print(query);
  38. return this.client.request(queryString, variables);
  39. }
  40. async queryStatus<T = any, V = Record<string, any>>(query: DocumentNode, variables?: V): Promise<number> {
  41. const queryString = print(query);
  42. const result = await this.client.rawRequest<T>(queryString, variables);
  43. return result.status;
  44. }
  45. /**
  46. * Uses curl to post a multipart/form-data request to create new assets. Due to differences between the Node and browser
  47. * environments, we cannot just use an existing library like apollo-upload-client.
  48. *
  49. * Upload spec: https://github.com/jaydenseric/graphql-multipart-request-spec
  50. * Discussion of issue: https://github.com/jaydenseric/apollo-upload-client/issues/32
  51. */
  52. uploadAssets(filePaths: string[]): Promise<CreateAssets> {
  53. return new Promise((resolve, reject) => {
  54. const curl = new Curl();
  55. const postData: any[] = [
  56. {
  57. name: 'operations',
  58. contents: JSON.stringify({
  59. operationName: 'CreateAssets',
  60. variables: {
  61. input: filePaths.map(() => ({ file: null })),
  62. },
  63. query: print(CREATE_ASSETS),
  64. }),
  65. },
  66. {
  67. name: 'map',
  68. contents:
  69. '{' +
  70. filePaths.map((filePath, i) => `"${i}":["variables.input.${i}.file"]`).join(',') +
  71. '}',
  72. },
  73. ...filePaths.map((filePath, i) => ({
  74. name: i.toString(),
  75. file: filePath,
  76. })),
  77. ];
  78. curl.setOpt(Curl.option.URL, this.apiUrl);
  79. curl.setOpt(Curl.option.VERBOSE, false);
  80. curl.setOpt(Curl.option.TIMEOUT_MS, 30000);
  81. curl.setOpt(Curl.option.HTTPPOST, postData);
  82. curl.setOpt(Curl.option.HTTPHEADER, [
  83. `Authorization: Bearer ${this.authToken}`,
  84. `${getConfig().channelTokenKey}: ${this.channelToken}`,
  85. ]);
  86. curl.perform();
  87. curl.on('end', (statusCode, body) => {
  88. curl.close();
  89. resolve(JSON.parse(body).data);
  90. });
  91. curl.on('error', err => {
  92. curl.close();
  93. console.log(err);
  94. reject(err);
  95. });
  96. });
  97. }
  98. async asUserWithCredentials(username: string, password: string) {
  99. const result = await this.client.rawRequest<AttemptLogin>(print(ATTEMPT_LOGIN), {
  100. username,
  101. password,
  102. } as AttemptLoginVariables);
  103. if (result.data && result.data.login) {
  104. this.setAuthToken(result.headers.get(AUTH_TOKEN_KEY));
  105. } else {
  106. console.error(result);
  107. }
  108. }
  109. async asSuperAdmin() {
  110. await this.asUserWithCredentials(SUPER_ADMIN_USER_IDENTIFIER, SUPER_ADMIN_USER_PASSWORD);
  111. }
  112. asAnonymousUser() {
  113. this.setAuthToken('');
  114. }
  115. private setHeaders() {
  116. this.client.setHeaders({
  117. Authorization: `Bearer ${this.authToken}`,
  118. [getConfig().channelTokenKey]: this.channelToken,
  119. });
  120. }
  121. }