simple-graphql-client.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { DocumentNode } from 'graphql';
  2. import { GraphQLClient } from 'graphql-request';
  3. import gql from 'graphql-tag';
  4. import { print } from 'graphql/language/printer';
  5. import { Curl } from 'node-libcurl';
  6. import { CreateAssets } from 'shared/generated-types';
  7. import { SUPER_ADMIN_USER_IDENTIFIER, SUPER_ADMIN_USER_PASSWORD } from 'shared/shared-constants';
  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(
  96. gql`
  97. mutation($username: String!, $password: String!) {
  98. login(username: $username, password: $password) {
  99. user {
  100. id
  101. identifier
  102. channelTokens
  103. }
  104. token
  105. }
  106. }
  107. `,
  108. {
  109. username,
  110. password,
  111. },
  112. );
  113. if (result && result.login) {
  114. this.setAuthToken(result.login.token);
  115. } else {
  116. console.error(result);
  117. }
  118. }
  119. async asSuperAdmin() {
  120. await this.asUserWithCredentials(SUPER_ADMIN_USER_IDENTIFIER, SUPER_ADMIN_USER_PASSWORD);
  121. }
  122. asAnonymousUser() {
  123. this.setAuthToken('');
  124. }
  125. private setHeaders() {
  126. this.client.setHeaders({
  127. Authorization: `Bearer ${this.authToken}`,
  128. [getConfig().channelTokenKey]: this.channelToken,
  129. });
  130. }
  131. }