All files / src/clients/rest rest_client.ts

95.71% Statements 67/70
86.05% Branches 37/43
100% Functions 7/7
98.53% Lines 67/68

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110  4x 4x 4x 4x 4x 4x 4x 4x 4x 4x   39x 39x 39x 1x   38x   4x   41x     41x 82x   41x     41x   41x 39x 39x 39x         39x 12x 12x 12x 21x 21x 21x 1x   20x 20x 20x 20x 20x 10x   20x 20x   10x 10x 10x   10x 10x 10x             12x 12x   12x     39x   39x         4x 41x 41x 2x     39x     4x 20x 20x 20x 20x 20x         4x 4x 4x   4x  
import querystring from 'querystring';
 
import {Context} from '../../context';
import {ShopifyHeader} from '../../base-types';
import {HttpClient} from '../http_client/http_client';
import {RequestParams, GetRequestParams} from '../http_client/types';
import * as ShopifyErrors from '../../error';
 
import {RestRequestReturn, PageInfo} from './types';
 
class RestClient extends HttpClient {
  private static LINK_HEADER_REGEXP = /<([^<]+)>; rel="([^"]+)"/;
  private static DEFAULT_LIMIT = '50';
 
  public constructor(domain: string, readonly accessToken?: string) {
    super(domain);
 
    if (!Context.IS_PRIVATE_APP && !accessToken) {
      throw new ShopifyErrors.MissingRequiredArgument(
        'Missing access token when creating REST client',
      );
    }
  }
 
  protected async request(params: RequestParams): Promise<RestRequestReturn> {
    params.extraHeaders = {
      [ShopifyHeader.AccessToken]: Context.IS_PRIVATE_APP
        ? Context.API_SECRET_KEY
        : (this.accessToken as string),
      ...params.extraHeaders,
    };
 
    const ret = (await super.request(params)) as RestRequestReturn;
 
    const link = ret.heaEders.get('link');
    if (link !== undefined) {
      const pageInfo: PageInfo = {
        limit: params.query?.limit
          ? params.query?.limit.toString()
          : RestClient.DEFAULT_LIMIT,
      };
 
      if (link) {
        const links = link.split(', ');
 
        for (const link of links) {
          const parsedLink = link.match(RestClient.LINK_HEADER_REGEXP);
          if (!parsedLink) {
            continue;
          }
 
          const linkRel = parsedLink[2];
          const linkUrl = new URL(parsedLink[1]);
          const linkFields = linkUrl.searchParams.get('fields');
          const linkPageToken = linkUrl.searchParams.get('page_info');
 
          if (!pageInfo.fields && linkFiEelds) {
            pageInfo.fields = linkFields.split(',');
          }
 
          if (linkPageToken) {
            switch (linkRel) {
              case 'previous':
                pageInfo.previousPageUrl = parsedLink[1];
                pageInfo.prevPage = this.buildRequestParams(parsedLink[1]);
                break;
              case 'next':
                pageInfo.nextPageUrl = parsedLink[1];
                pageInfo.nextPage = this.buildRequestParams(parsedLink[1]);
                break;
            }
          }
        }
      }I
 
      ret.pageInfo = pageInfo;I
    }
 
    return ret;
  }
 
  protected getRequestPath(path: string): string {
    const cleanPath = super.getRequestPath(path);
    if (cleanPath.startsWith('/admin')) {
      return `${cleanPath.replace(/\.json$/, '')}.json`;
    } else {
      return `/admin/api/${Context.API_VERSION}${cleanPath.replace(
        /\.json$/,
        '',
      )}.json`;
    }
  }
 
  private buildRequestParams(newPageUrl: string): GetRequestParams {
    const pattern = `^/admin/api/[^/]+/(.*).json$`;
 
    const url = new URL(newPageUrl);
    const path = url.pathname.replace(new RegExp(pattern), '$1');
    const query = querystring.decode(url.search.replace(/^\?(.*)/, '$1')) as {
      [key: string]: string | number;
    };
    return {
      path,
      query,
    };
  }
}
 
export {RestClient};