Skip to content

Commit

Permalink
refactor: request headers include x-nacelle-sdk-version (#385)
Browse files Browse the repository at this point in the history
* refactor: use static method to set request headers

* docs: add changeset
  • Loading branch information
NWRichmond committed May 1, 2023
1 parent 9cdc2e2 commit f3a05ca
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/kind-frogs-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@nacelle/storefront-sdk': patch
---

Adds an `x-nacelle-sdk-version` header to all requests. This improves tracing and observability in the event of a support request.
5 changes: 4 additions & 1 deletion packages/storefront-sdk/src/client/createClient.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { createClient } from '@urql/core';
import { StorefrontClient } from './index.js';
import { version as packageVersion } from '../../package.json';

vi.mock('@urql/core');

Expand All @@ -23,7 +24,9 @@ describe('`createClient`', () => {
url: storefrontEndpoint,
fetch: globalThis.fetch,
fetchOptions: {
headers: {}
headers: {
'x-nacelle-sdk-version': packageVersion
}
}
})
);
Expand Down
26 changes: 25 additions & 1 deletion packages/storefront-sdk/src/client/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import { StorefrontClient, retryExchange, retryStatusCodes } from './index.js';
import { NavigationDocument } from '../../__mocks__/gql/operations.js';
import getFetchPayload from '../../__mocks__/utils/getFetchPayload.js';
import NavigationResult from '../../__mocks__/gql/navigation.js';
import { errorMessages, X_NACELLE_PREVIEW_TOKEN } from '../utils/index.js';
import {
errorMessages,
X_NACELLE_SDK_VERSION,
X_NACELLE_PREVIEW_TOKEN
} from '../utils/index.js';
import type { StorefrontResponse } from './index.js';
import type {
NavigationGroup,
Expand Down Expand Up @@ -575,6 +579,26 @@ it('sets the expected header and query param when initialized with a `previewTok
expect(requestHeaders[X_NACELLE_PREVIEW_TOKEN]).toBe(myPreviewToken);
});

it("sends an 'x-nacelle-sdk-version' header", async () => {
mockedFetch.mockImplementationOnce(() =>
Promise.resolve(getFetchPayload({ data: NavigationResult }))
);
const variables = { filter: { groupId: 'abc' } };
await client.query({
query: NavigationDocument,
variables
});

const lastFetch = mockedFetch.mock.lastCall as mockRequestArgs;
const requestHeaders = lastFetch[1]?.headers as HeadersInit & {
[X_NACELLE_SDK_VERSION]?: string;
};

expect(requestHeaders[X_NACELLE_SDK_VERSION]).toMatch(
/\b\d{1,2}.\d{1,2}.\d{1,2}\b/ // three sequences of 1-2 digits separated by periods
);
});

it('`getConfig` retrieves config', () => {
const client = new StorefrontClient({
storefrontEndpoint,
Expand Down
77 changes: 53 additions & 24 deletions packages/storefront-sdk/src/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { createClient, fetchExchange } from '@urql/core';
import { retryExchange as urqlRetryExchange } from '@urql/exchange-retry';
import { persistedExchange as urqlPersistedExchange } from '@urql/exchange-persisted';
import { errorMessages, X_NACELLE_PREVIEW_TOKEN } from '../utils/index.js';
import {
errorMessages,
X_NACELLE_SDK_VERSION,
X_NACELLE_PREVIEW_TOKEN
} from '../utils/index.js';
import { version as packageVersion } from '../../package.json';
import type {
Client as UrqlClient,
TypedDocumentNode,
Expand Down Expand Up @@ -97,18 +102,13 @@ export class StorefrontClient {
throw new Error(errorMessages.missingEndpoint);
}

const storefrontEndpointUrl = new URL(params.storefrontEndpoint);
let headers = {};

if (params.previewToken) {
headers = { [X_NACELLE_PREVIEW_TOKEN]: params.previewToken };
storefrontEndpointUrl.searchParams.set('preview', 'true');
}

this.#config = {
exchanges: params.exchanges ?? defaultExchanges,
fetchClient: params.fetchClient ?? globalThis.fetch,
storefrontEndpoint: storefrontEndpointUrl.toString(),
storefrontEndpoint: StorefrontClient.getStorefrontEndpoint(
params.storefrontEndpoint,
params.previewToken
),
previewToken: params.previewToken,
locale: params.locale ?? 'en-US'
};
Expand All @@ -117,7 +117,7 @@ export class StorefrontClient {
url: this.#config.storefrontEndpoint,
fetch: this.#config.fetchClient,
fetchOptions: {
headers
headers: StorefrontClient.getHeaders(params.previewToken)
},
exchanges: this.#config.exchanges
});
Expand Down Expand Up @@ -155,24 +155,22 @@ export class StorefrontClient {
* ```
*/
setConfig(setConfigParams: SetConfigParams): SetConfigResponse {
const currentEndpoint = new URL(this.#config.storefrontEndpoint);

let headers = {};

if (setConfigParams.previewToken) {
this.#config.previewToken = setConfigParams.previewToken;
currentEndpoint.searchParams.set('preview', 'true');
headers = { [X_NACELLE_PREVIEW_TOKEN]: this.#config.previewToken };
} else {
this.#config.previewToken = undefined;
currentEndpoint.searchParams.delete('preview');
this.#config.storefrontEndpoint = StorefrontClient.getStorefrontEndpoint(
this.#config.storefrontEndpoint,
setConfigParams.previewToken
);

if (typeof setConfigParams.previewToken !== 'undefined') {
// set to `undefined` if `null` or empty string
this.#config.previewToken = setConfigParams.previewToken || undefined;
}

this.#config.storefrontEndpoint = currentEndpoint.toString();
this.#graphqlClient = createClient({
url: this.#config.storefrontEndpoint,
fetch: this.#config.fetchClient,
fetchOptions: { headers },
fetchOptions: {
headers: StorefrontClient.getHeaders(setConfigParams.previewToken)
},
exchanges: this.#config.exchanges
});

Expand Down Expand Up @@ -300,4 +298,35 @@ export class StorefrontClient {
})
.then(({ data, error }) => this.applyAfter('query', { data, error }));
}

private static getHeaders(
previewToken?: string | null
): Record<string, string> {
const headers: Record<string, string> = {
[X_NACELLE_SDK_VERSION]: packageVersion
};

if (previewToken) {
headers[X_NACELLE_PREVIEW_TOKEN] = previewToken;
}

return headers;
}

private static getStorefrontEndpoint(
endpoint: string,
previewToken?: string | null
): string {
const endpointUrl = new URL(endpoint);

if (previewToken) {
endpointUrl.searchParams.set('preview', 'true');
} else if (typeof previewToken !== 'undefined') {
// `previewToken` is `null`, an empty string,
// or some other falsey, non-`undefined` value
endpointUrl.searchParams.delete('preview');
}

return endpointUrl.toString();
}
}
1 change: 1 addition & 0 deletions packages/storefront-sdk/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const X_NACELLE_PREVIEW_TOKEN = 'x-nacelle-preview-token';
export const X_NACELLE_SDK_VERSION = 'x-nacelle-sdk-version';

6 comments on commit f3a05ca

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nacelle-next-starter – ./starters/next

nacelle-next-starter-git-main-nacelle.vercel.app
nacelle-next-starter-nacelle.vercel.app
nacelle-nextjs-starter.vercel.app

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nacelle-gatsby-starter – ./starters/gatsby

nacelle-gatsby-starter.vercel.app
nacelle-gatsby-starter-git-main-nacelle.vercel.app
nacelle-gatsby-starter-nacelle.vercel.app

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nacelle-gatsby-reference-store – ./reference-stores/gatsby

nacelle-gatsby-reference-store.vercel.app
nacelle-gatsby-reference-store-nacelle.vercel.app
nacelle-gatsby-reference-store-git-main-nacelle.vercel.app

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nacelle-nuxt-starter – ./starters/nuxt

nacelle-nuxt-starter-nacelle.vercel.app
nacelle-nuxt-starter.vercel.app
nacelle-nuxt-starter-git-main-nacelle.vercel.app

@vercel
Copy link

@vercel vercel bot commented on f3a05ca May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nacelle-next-reference-store – ./reference-stores/next

nacelle-next-reference-store-nacelle.vercel.app
nacelle-next-reference-store-git-main-nacelle.vercel.app
nacelle-next-reference-store.vercel.app

Please sign in to comment.