simple-graphql-client.ts 4.5 KB

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