Skip to content

Commit

Permalink
Merge pull request #518 from Shopify/update_shopify_api_client_calls
Browse files Browse the repository at this point in the history
Update remix package to use new GraphQL client format
  • Loading branch information
lizkenyon authored Jan 10, 2024
2 parents 40ebcc8 + d3e4b5e commit 1d1b030
Show file tree
Hide file tree
Showing 47 changed files with 505 additions and 138 deletions.
14 changes: 14 additions & 0 deletions .changeset/plenty-roses-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@shopify/shopify-app-session-storage-postgresql': patch
'@shopify/shopify-app-session-storage-dynamodb': patch
'@shopify/shopify-app-session-storage-mongodb': patch
'@shopify/shopify-app-session-storage-memory': patch
'@shopify/shopify-app-session-storage-prisma': patch
'@shopify/shopify-app-session-storage-sqlite': patch
'@shopify/shopify-app-session-storage-mysql': patch
'@shopify/shopify-app-session-storage-redis': patch
'@shopify/shopify-app-session-storage-kv': patch
'@shopify/shopify-app-session-storage': patch
---

Updated the dependency on `@shopify/shopify-api`
5 changes: 5 additions & 0 deletions .changeset/thin-feet-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/shopify-app-express': major
---

Updated `@shopify/shopify-api` to the latest major version. Please follow [the v9 migration guide](https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/migrating-to-v9.md) to update your app.
7 changes: 7 additions & 0 deletions .changeset/thirty-apples-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@shopify/shopify-app-remix': minor
---

Adding support for the new clients from `@shopify/admin-api-client` and `@shopify/storefront-api-client` that can leverage `@shopify/api-codegen-preset` to automatically type GraphQL operations using Codegen.

For more information on how to add types to your queries, see [the `@shopify/api-codegen-preset` documentation](https://github.com/Shopify/shopify-api-js/tree/main/packages/api-codegen-preset).
2 changes: 1 addition & 1 deletion packages/shopify-app-express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"Storefront API"
],
"dependencies": {
"@shopify/shopify-api": "^8.1.1",
"@shopify/shopify-api": "^9.0.1",
"@shopify/shopify-app-session-storage": "^2.0.2",
"@shopify/shopify-app-session-storage-memory": "^2.0.2",
"cookie-parser": "^1.4.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ function assertOAuthRequests(
expect({
method: 'POST',
url: `https://${TEST_SHOP}/admin/api/${LATEST_API_VERSION}/graphql.json`,
body: expect.stringContaining(query),
body: expect.objectContaining({query: expect.stringContaining(query)}),
}).toMatchMadeHttpRequest(),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ describe('webhook integration', () => {
expect({
method: 'POST',
url: `https://${TEST_SHOP}/admin/api/${LATEST_API_VERSION}/graphql.json`,
body: expect.stringContaining(query),
body: expect.objectContaining({
query: expect.stringContaining(query),
}),
}).toMatchMadeHttpRequest(),
);

Expand Down
13 changes: 11 additions & 2 deletions packages/shopify-app-express/src/__tests__/test-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ interface AssertHttpRequestParams {
export function mockShopifyResponse(body: MockBody, init?: MockParams) {
fetchMock.mockResponse(
typeof body === 'string' ? body : JSON.stringify(body),
init,
mockResponseInit(init),
);
}

Expand All @@ -84,13 +84,22 @@ export function mockShopifyResponses(
([body, init]) => {
const bodyString = typeof body === 'string' ? body : JSON.stringify(body);

return init ? [bodyString, init] : [bodyString, {}];
return [bodyString, mockResponseInit(init)];
},
);

fetchMock.mockResponses(...parsedResponses);
}

function mockResponseInit(init?: MockParams): MockParams {
const initObj = init ?? {};

return {
...initObj,
headers: {'Content-Type': 'application/json', ...initObj.headers},
};
}

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
Expand Down
4 changes: 2 additions & 2 deletions packages/shopify-app-express/src/auth/auth-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Request, Response} from 'express';
import {
BotActivityDetected,
CookieNotFound,
gdprTopics,
privacyTopics,
InvalidOAuthError,
Session,
Shopify,
Expand Down Expand Up @@ -83,7 +83,7 @@ async function registerWebhooks(
}

for (const response of responsesByTopic[topic]) {
if (!response.success && !gdprTopics.includes(topic)) {
if (!response.success && !privacyTopics.includes(topic)) {
const result: any = response.result;

if (result.errors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ describe('ensureInstalledOnShop', () => {
)}`,
];

mockShopifyResponse({});
mockShopifyResponse({
data: {},
extensions: {},
});
await shopify.config.sessionStorage.storeSession(session);

await request(app)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ describe('validateAuthenticatedSession', () => {
});

it('finds a session with the right cookie', async () => {
mockShopifyResponse({});
mockShopifyResponse({
data: {},
extensions: {},
});

const response = await request(app)
.get('/test/shop?shop=my-shop.myshopify.io')
Expand Down
50 changes: 25 additions & 25 deletions packages/shopify-app-remix/docs/generated/generated_docs_data.json

Large diffs are not rendered by default.

133 changes: 132 additions & 1 deletion packages/shopify-app-remix/docs/generated/generated_static_pages.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@
"language": "tsx"
}
]
}
},
"sectionCard": [
{
"url": "/docs/api/shopify-app-remix/guide-graphql-types",
"name": "Typing GraphQL operations",
"type": "tutorial"
}
]
},
{
"type": "Generic",
Expand Down Expand Up @@ -161,6 +168,130 @@
}
]
},
{
"id": "guide-graphql-types",
"title": "Typing GraphQL operations",
"description": "The GraphQL clients provided in this package can use [Codegen](https://the-guild.dev/graphql/codegen) to automatically parse and create types for your queries and mutations.\n\nBy installing a few packages in your app, you can use the `graphql-codegen` script, which will look for strings with the `#graphql` tag and extract types from them.\n\nIf your IDE supports it, you will also get syntax highlighting and auto-complete features when writing your queries.",
"sections": [
{
"type": "Markdown",
"anchorLink": "example",
"title": "See it in action",
"sectionContent": "\nIn this example, we use the `graphql-codegen` script to parse a query in the `/app/routes/new.tsx` file.\n\nNote how VSCode shows the types for both the return type of `response.json()`, and the `variables` option in the `graphql` function.\n\n<video style=\"width: 100%; height: auto;\" muted controls aria-label=\"A demonstration of a Remix app using GraphQL types\">\n <source src=\"/assets/client-libraries/graphql-types-demo.webm\" type=\"video/webm\">\n Your browser doesn't support this video.\n</video>\n "
},
{
"type": "Generic",
"anchorLink": "install",
"title": "Installing packages",
"sectionContent": "To use the `graphql-codegen` script, you will need to install a few packages in your app.\n\nThey will include the scripts to run, and the types that will be overridden by the results of parsing your operations.",
"codeblock": {
"title": "Installing packages",
"tabs": [
{
"title": "npm",
"language": "sh",
"code": "npm add --save-dev @shopify/api-codegen-preset\nnpm add @shopify/admin-api-client @shopify/storefront-api-client\n"
},
{
"title": "yarn",
"language": "sh",
"code": "yarn add --dev @shopify/api-codegen-preset\nyarn add @shopify/admin-api-client @shopify/storefront-api-client\n"
},
{
"title": "pnpm",
"language": "sh",
"code": "pnpm add --save-dev @shopify/api-codegen-preset\npnpm add @shopify/admin-api-client @shopify/storefront-api-client\n"
}
]
}
},
{
"type": "Generic",
"anchorLink": "configure",
"title": "Setting up .graphqlrc.ts",
"sectionContent": "Before you can parse operations, you'll need to create a `.graphqlrc.ts` file in your project, and configure it to use the `@shopify/api-codegen-preset`.\n\n> Caution: Parsing will not work on `.graphql` documents, because the preset can only apply types from JavaScript and TypeScript const strings.",
"codeblock": {
"title": "Codegen configuration example",
"tabs": [
{
"title": "/.graphqlrc.ts",
"language": "ts",
"code": "import {shopifyApiProject, ApiType} from '@shopify/api-codegen-preset';\n\nexport default {\n // For syntax highlighting / auto-complete when writing operations\n schema: 'https://shopify.dev/admin-graphql-direct-proxy/2023-10',\n documents: ['./app/**/*.{js,ts,jsx,tsx}'],\n projects: {\n // To produce variable / return types for Admin API operations\n default: shopifyApiProject({\n apiType: ApiType.Admin,\n apiVersion: '2023-10',\n documents: ['./app/**/*.{js,ts,jsx,tsx}'],\n outputDir: './app/types',\n }),\n },\n};\n"
}
]
},
"sectionCard": [
{
"url": "https://github.com/Shopify/shopify-api-js/tree/main/packages/api-codegen-preset#configuration",
"name": "Configuration options",
"subtitle": "Learn more about the available configurations.",
"type": "github"
}
]
},
{
"type": "Generic",
"anchorLink": "set-up-script",
"title": "Setting up the script",
"sectionContent": "To generate types, you'll need to add an entry for `graphql-codegen` in the `\"scripts\"` section of your `package.json` file.",
"codeblock": {
"title": "Setting up the script",
"tabs": [
{
"title": "/package.json",
"language": "json",
"code": "{\n \"scripts\": {\n \"graphql-codegen\": \"graphql-codegen\"\n }\n}\n"
}
]
}
},
{
"type": "Generic",
"anchorLink": "run",
"title": "Generating types",
"sectionContent": "When you run `graphql-codegen`, it will look in all your configured documents for strings marked with a `#graphql` tag.\n\nIDEs that support the `.graphqlrc.ts` file will provide syntax highlighting for your operations, as well as typing.\n\n> Tip: You can pass in a `--watch` flag to the script, which will update your types every time you save a file.",
"codeblock": {
"title": "Running graphql-codegen",
"tabs": [
{
"title": "npm",
"language": "sh",
"code": "npm run graphql-codegen\n"
},
{
"title": "yarn",
"language": "sh",
"code": "yarn graphql-codegen\n"
},
{
"title": "pnpm",
"language": "sh",
"code": "pnpm run graphql-codegen\n"
}
]
}
},
{
"type": "Resource",
"title": "Resources",
"anchorLink": "resources",
"resources": [
{
"name": "Admin API",
"url": "/docs/api/shopify-app-remix/apis/admin-api",
"type": "shopify",
"subtitle": "Make requests to the Admin API"
},
{
"name": "Storefront API",
"url": "/docs/api/shopify-app-remix/apis/storefront-api",
"type": "shopify",
"subtitle": "Make requests to the Storefront API"
}
]
}
]
},
{
"id": "shopify-app-remix",
"title": "Shopify App package for Remix",
Expand Down
15 changes: 11 additions & 4 deletions packages/shopify-app-remix/docs/staticPages/admin.doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const data: LandingTemplateSchema = {
anchorLink: 'auth',
title: 'Authenticating requests',
sectionContent:
"To authenticate admin requests you can call `authenticate.admin(request)` in a loader or an action." +
'To authenticate admin requests you can call `authenticate.admin(request)` in a loader or an action.' +
"\n\nIf there's a session for this user, then this loader will return null. If there's no session for the user, then the loader will throw the appropriate redirect Response." +
"\n\n> Tip: If you are authenticating more than one route, then we recommend using [Remix layout routes](https://remix.run/docs/en/1.18.1/file-conventions/routes-files#layout-routes) to automatically authenticate them.",
'\n\n> Tip: If you are authenticating more than one route, then we recommend using [Remix layout routes](https://remix.run/docs/en/1.18.1/file-conventions/routes-files#layout-routes) to automatically authenticate them.',
codeblock: {
title: 'Authenticating requests',
tabs: [
Expand All @@ -34,8 +34,8 @@ const data: LandingTemplateSchema = {
title: 'Headers',
sectionContent:
"The OAuth process can't happen inside the admin iframe, and this package is capable of detecting that scenario and properly redirecting using the [Remix `ErrorBoundary`](https://remix.run/docs/en/main/guides/errors) export to set the correct headers for App Bridge." +
"\n\nUse the abstractions provided by this package in your authenticated routes, to automatically set up the error and headers boundaries to redirect outside the iframe when needed." +
"\n\n> Tip: You can also add this to a [Remix layout](https://remix.run/docs/en/main/file-conventions/route-files-v2) if you want to authenticate more than one route, but make sure to call the Shopify boundary methods whenever you need to add your own exports.",
'\n\nUse the abstractions provided by this package in your authenticated routes, to automatically set up the error and headers boundaries to redirect outside the iframe when needed.' +
'\n\n> Tip: You can also add this to a [Remix layout](https://remix.run/docs/en/main/file-conventions/route-files-v2) if you want to authenticate more than one route, but make sure to call the Shopify boundary methods whenever you need to add your own exports.',
codeblock: {
title: 'Configure header boundaries',
tabs: [
Expand Down Expand Up @@ -81,6 +81,13 @@ const data: LandingTemplateSchema = {
},
],
},
sectionCard: [
{
url: '/docs/api/shopify-app-remix/guide-graphql-types',
name: 'Typing GraphQL operations',
type: 'tutorial',
},
],
},
{
type: 'Generic',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {shopifyApiProject, ApiType} from '@shopify/api-codegen-preset';

export default {
// For syntax highlighting / auto-complete when writing operations
schema: 'https://shopify.dev/admin-graphql-direct-proxy/2023-10',
documents: ['./app/**/*.{js,ts,jsx,tsx}'],
projects: {
// To produce variable / return types for Admin API operations
default: shopifyApiProject({
apiType: ApiType.Admin,
apiVersion: '2023-10',
documents: ['./app/**/*.{js,ts,jsx,tsx}'],
outputDir: './app/types',
}),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
npm add --save-dev @shopify/api-codegen-preset
npm add @shopify/admin-api-client @shopify/storefront-api-client
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pnpm add --save-dev @shopify/api-codegen-preset
pnpm add @shopify/admin-api-client @shopify/storefront-api-client
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
yarn add --dev @shopify/api-codegen-preset
yarn add @shopify/admin-api-client @shopify/storefront-api-client
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"scripts": {
"graphql-codegen": "graphql-codegen"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npm run graphql-codegen
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pnpm run graphql-codegen
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarn graphql-codegen
Loading

0 comments on commit 1d1b030

Please sign in to comment.