Unauthenticated storefrontobject
Allows interacting with the Storefront API when working outside of Shopify requests. This enables apps to integrate with 3rd party services and perform background tasks.
This function doesn't perform any validation and shouldn't rely on raw user input.
When using this function, consider the following:
Background tasks
Apps should ensure that the shop domain is authenticated when enqueueing jobs.
3rd party service requests
Apps must obtain the shop domain from the 3rd party service in a secure way.
Creates an unauthenticated Storefront context.
- Anchor to shopshopstringrequired
GetUnauthenticatedStorefrontContext
- shop
string
Promise<UnauthenticatedStorefrontContext>
(
shop: string,
) => Promise<UnauthenticatedStorefrontContext>
UnauthenticatedStorefrontContext
- session
The session for the given shop. This comes from the session storage which `shopifyApp` uses to store sessions in your database of choice. This will always be an offline session. You can use this to get shop specific data.
Session
- storefront
Method for interacting with the Shopify GraphQL Storefront API for the given store.
StorefrontContext
export interface UnauthenticatedStorefrontContext {
/**
* The session for the given shop.
*
* This comes from the session storage which `shopifyApp` uses to store sessions in your database of choice.
*
* This will always be an offline session. You can use this to get shop specific data.
*
* @example
* <caption>Using the offline session.</caption>
* <description>Get your app's shop-specific data using the returned offline `session` object.</description>
* ```ts
* // app/routes/**\/.ts
* import { LoaderFunctionArgs, json } from "react-router";
* import { unauthenticated } from "../shopify.server";
* import { getMyAppData } from "~/db/model.server";
*
* export const loader = async ({ request }: LoaderFunctionArgs) => {
* const shop = getShopFromExternalRequest(request);
* const { session } = await unauthenticated.storefront(shop);
* return (await getMyAppData({shop: session.shop}));
* };
* ```
*/
session: Session;
/**
* Method for interacting with the Shopify GraphQL Storefront API for the given store.
*
* @example
* <caption>Querying the GraphQL API.</caption>
* <description>Use `storefront.graphql` to make query / mutation requests.</description>
* ```ts
* // app/routes/**\/.ts
* import { json } from "react-router";
* import { authenticate } from "../shopify.server";
*
* export async function action({ request }: ActionFunctionArgs) {
* const shop = getShopFromExternalRequest(request);
* const { storefront } = await unauthenticated.storefront(shop);
*
* const response = await storefront.graphql(`{blogs(first: 10) { edges { node { id } } } }`);
*
* return (await response.json());
* }
* ```
*
* @example
* <caption>Handling GraphQL errors.</caption>
* <description>Catch `GraphqlQueryError` errors to see error messages from the API.</description>
* ```ts
* // /app/routes/**\/*.ts
* import { ActionFunctionArgs } from "react-router";
* import { authenticate } from "../shopify.server";
*
* export const action = async ({ request }: ActionFunctionArgs) => {
* const shop = getShopFromExternalRequest(request);
* const { storefront } = await unauthenticated.storefront(shop);
*
* try {
* const response = await storefront.graphql(
* `#graphql
* query incorrectQuery {
* products(first: 10) {
* nodes {
* not_a_field
* }
* }
* }`,
* );
*
* return ({ data: await response.json() });
* } catch (error) {
* if (error instanceof GraphqlQueryError) {
* // { errors: { graphQLErrors: [
* // { message: "Field 'not_a_field' doesn't exist on type 'Product'" }
* // ] } }
* return ({ errors: error.body?.errors }, { status: 500 });
* }
* return ({ message: "An error occurred" }, { status: 500 });
* }
* }
* ```
*
* ```ts
* // /app/shopify.server.ts
* import { shopifyApp } from "@shopify/shopify-app-react-router/server";
*
* const shopify = shopifyApp({
* // ...
* });
* export default shopify;
* export const unauthenticated = shopify.unauthenticated;
* ```
*/
storefront: StorefrontContext;
}
StorefrontContext
- graphql
Method for interacting with the Shopify Storefront GraphQL API If you're getting incorrect type hints in the Shopify template, follow [these instructions](https://github.com/Shopify/shopify-app-template-react-router/tree/main#incorrect-graphql-hints).
GraphQLClient<StorefrontOperations>
export interface StorefrontContext {
/**
* Method for interacting with the Shopify Storefront GraphQL API
*
* If you're getting incorrect type hints in the Shopify template, follow [these instructions](https://github.com/Shopify/shopify-app-template-react-router/tree/main#incorrect-graphql-hints).
*
* {@link https://shopify.dev/docs/api/storefront}
*
* @example
* <caption>Querying the GraphQL API.</caption>
* <description>Use `storefront.graphql` to make query / mutation requests.</description>
* ```ts
* // app/routes/**\/.ts
* import { json } from "react-router";
* import { authenticate } from "../shopify.server";
*
* export async function action({ request }: ActionFunctionArgs) {
* const { storefront } = await authenticate.public.appProxy(request);
*
* const response = await storefront.graphql(`{blogs(first: 10) { edges { node { id } } } }`);
*
* return (await response.json());
* }
* ```
*
* @example
* <caption>Handling GraphQL errors.</caption>
* <description>Catch `GraphqlQueryError` errors to see error messages from the API.</description>
* ```ts
* // /app/routes/**\/*.ts
* import { ActionFunctionArgs } from "react-router";
* import { authenticate } from "../shopify.server";
*
* export const action = async ({ request }: ActionFunctionArgs) => {
* const { storefront } = await authenticate.public.appProxy(request);
*
* try {
* const response = await storefront.graphql(
* `#graphql
* query incorrectQuery {
* products(first: 10) {
* nodes {
* not_a_field
* }
* }
* }`,
* );
*
* return ({ data: await response.json() });
* } catch (error) {
* if (error instanceof GraphqlQueryError) {
* // { errors: { graphQLErrors: [
* // { message: "Field 'not_a_field' doesn't exist on type 'Product'" }
* // ] } }
* return ({ errors: error.body?.errors }, { status: 500 });
* }
* return ({ message: "An error occurred" }, { status: 500 });
* }
* }
* ```
*
* ```ts
* // /app/shopify.server.ts
* import { shopifyApp } from "@shopify/shopify-app-react-router/server";
*
* const shopify = shopifyApp({
* // ...
* });
* export default shopify;
* export const authenticate = shopify.authenticate;
* ```
*/
graphql: GraphQLClient<StorefrontOperations>;
}
GraphQLClient
- query
Operation extends keyof Operations
- options
GraphQLQueryOptions<Operation, Operations>
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}, interface Promise<T> {}, Promise: PromiseConstructor, interface Promise<T> {
readonly [Symbol.toStringTag]: string;
}, interface Promise<T> {
/**
* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
* resolved value cannot be modified from the callback.
* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
* @returns A Promise for the completion of the callback.
*/
finally(onfinally?: (() => void) | undefined | null): Promise<T>;
}
<
Operation extends keyof Operations,
>(
query: Operation,
options?: GraphQLQueryOptions<Operation, Operations>,
) => Promise<GraphQLResponse<Operation, Operations>>
GraphQLQueryOptions
- apiVersion
The version of the API to use for the request.
ApiVersion
- headers
Additional headers to include in the request.
Record<string, any>
- signal
An optional AbortSignal to cancel the request.
AbortSignal
- tries
The total number of times to try the request if it fails.
number
- variables
The variables to pass to the operation.
ApiClientRequestOptions<Operation, Operations>["variables"]
export interface GraphQLQueryOptions<
Operation extends keyof Operations,
Operations extends AllOperations,
> {
/**
* The variables to pass to the operation.
*/
variables?: ApiClientRequestOptions<Operation, Operations>['variables'];
/**
* The version of the API to use for the request.
*/
apiVersion?: ApiVersion;
/**
* Additional headers to include in the request.
*/
headers?: Record<string, any>;
/**
* The total number of times to try the request if it fails.
*/
tries?: number;
/**
* An optional AbortSignal to cancel the request.
*/
signal?: AbortSignal;
}
Anchor to examplesExamples
Anchor to example-sessionsession
Anchor to example-using-the-offline-sessionUsing the offline session
Get your app's shop-specific data using the returned offline session
object.
Using the offline session
app/routes/**\/.ts
examples
Using the offline session
description
Get your app's shop-specific data using the returned offline `session` object.
app/routes/**\/.ts
import { LoaderFunctionArgs, json } from "react-router"; import { unauthenticated } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderFunctionArgs) => { const shop = getShopFromExternalRequest(request); const { session } = await unauthenticated.storefront(shop); return (await getMyAppData({shop: session.shop})); };
Anchor to example-storefrontstorefront
Anchor to example-querying-the-graphql-apiQuerying the GraphQL API
Use storefront.graphql
to make query / mutation requests.
Anchor to example-handling-graphql-errorsHandling GraphQL errors
Catch errors to see error messages from the API.
Querying the GraphQL API
app/routes/**\/.ts
examples
Querying the GraphQL API
description
Use `storefront.graphql` to make query / mutation requests.
app/routes/**\/.ts
import { json } from "react-router"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionFunctionArgs) { const shop = getShopFromExternalRequest(request); const { storefront } = await unauthenticated.storefront(shop); const response = await storefront.graphql(`{blogs(first: 10) { edges { node { id } } } }`); return (await response.json()); }
Handling GraphQL errors
description
Catch `GraphqlQueryError` errors to see error messages from the API.
/app/routes/**\/*.ts
import { ActionFunctionArgs } from "react-router"; import { authenticate } from "../shopify.server"; export const action = async ({ request }: ActionFunctionArgs) => { const shop = getShopFromExternalRequest(request); const { storefront } = await unauthenticated.storefront(shop); try { const response = await storefront.graphql( `#graphql query incorrectQuery { products(first: 10) { nodes { not_a_field } } }`, ); return ({ data: await response.json() }); } catch (error) { if (error instanceof GraphqlQueryError) { // { errors: { graphQLErrors: [ // { message: "Field 'not_a_field' doesn't exist on type 'Product'" } // ] } } return ({ errors: error.body?.errors }, { status: 500 }); } return ({ message: "An error occurred" }, { status: 500 }); } }
/app/shopify.server.ts
import { shopifyApp } from "@shopify/shopify-app-react-router/server"; const shopify = shopifyApp({ // ... }); export default shopify; export const unauthenticated = shopify.unauthenticated;