usama7365 / developer-community

community site soon❤️
24 stars 0 forks source link

Facing some issue in graphql mutation and query with appoloClient #13

Closed Zainali005 closed 2 weeks ago

Zainali005 commented 3 weeks ago

For queries it will work perfectly and receive data this is the api end point: /api/shopify:

import { ApolloClient, InMemoryCache, HttpLink, from } from "@apollo/client"; import { setContext } from "@apollo/client/link/context"; import { NextResponse } from 'next/server'; // Updated import for Next.js 13+

export async function POST(req: Request) { const httpLink = new HttpLink({ uri: "https://quickstart-d414285b.myshopify.com/admin/api/2024-07/graphql.json", });

const authLink = setContext((_, { headers }) => { return { headers: { ...headers, "Content-Type": "application/json", "X-Shopify-Access-Token": process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN, }, }; });

const client = new ApolloClient({ link: from([authLink, httpLink]), cache: new InMemoryCache(), });

try { const body = await req.json(); const query = body.query;

if (!query) {
  return NextResponse.json({ status: 400, error: "Missing query in request body" }, { status: 400 });
}

const result = await client.query({
  query: query, 
});

return NextResponse.json({ status: 200, data: result.data });

} catch (error) { console.error("GraphQL Query Error:", error); return NextResponse.json({ status: 500, error: error.message }); } } for mutation i throw and error: GraphQL Query Error: Invariant Violation: An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#%7B%22version%22%3A%223.11.2%22%2C%22message%22%3A29%2C%22args%22%3A%5B%5D%7D at new InvariantError (webpack-internal:///(rsc)/./node_modules/ts-invariant/lib/invariant.js:19:28) at invariant (webpack-int

Please response ASAP and also i want to create product from graphiql

usama7365 commented 2 weeks ago

@Zainali005,

The error you're encountering with the GraphQL mutation, Invariant Violation, usually occurs when the mutation is not executed correctly. Instead of using client.query, you should be using client.mutate.

Here’s an example of how your mutation should look:

const result = await client.mutate({
  mutation: gql`
    mutation YourMutation($input: InputType!) {
      yourMutation(input: $input) {
        id
        name
      }
    }
  `,
  variables: {
    input: yourInputData
  }
});

This way, the mutation should execute properly.

If you’re trying to create a product, you can use the following mutation in GraphiQL:

mutation createProduct($input: ProductInput!) {
  productCreate(input: $input) {
    product {
      id
      title
      descriptionHtml
    }
  }
}

Just make sure to pass your product data in the $input.

Zainali005 commented 2 weeks ago

how to pass i am using rest api and want to replace with graphql: const handleSubmit = async () => { const title = (document.getElementById("title") as HTMLInputElement).value.trim(); const description = (document.getElementById("description") as HTMLTextAreaElement).value.trim();

if (!title) {
  toast.error("Product title is required.");
  return;
}

if (!description) {
  toast.error("Product description is required.");
  return;
}

if (Object.values(checkboxStates).every((checked) => !checked)) {
  toast.error("Please select at least one store.");
  return;
}

try {
  const updatedProduct = {
    uuid: selectedProduct?.data.uuid,
    title,
    description,
    status: "publish",
  };
  setIsSubmitting(true);

  const productPrice = selectedProduct?.data.price || "30$";
  const productSku = selectedProduct?.data.sku;
  const shopifyProduct = {
    title: updatedProduct.title || "Title",
    body_html: updatedProduct.description,
    vendor: "Sticker",
    product_type: "sticker",
    variants: [
      {
        option1: updatedProduct.title || "Missing title",
        price: parseFloat(productPrice.replace(/[^0-9.]/g, "")),
        sku: productSku || "SKU-undefined",
      },
    ],
    images: [
      {
        src: selectedProduct?.data.imageUrl || selectedProduct?.data.frontUrl || selectedProduct?.data.leftImage || "",
      },
    ],
  };

  await axios.post(`/api/updateRedisData`, updatedProduct);
  const checkedStoreIds = Object.keys(checkboxStates).filter((storeId) => checkboxStates[storeId]);

  for (const storeId of checkedStoreIds) {
    await axios.post(`/api/AddProduct?storeId=${storeId}`, shopifyProduct);
  }

  toast.success("Product Published Successfully!");
  localStorage.removeItem("selectedProduct");
  setSelectedProduct(null);
  router.push("/products/newProducts");
} catch (error) {
  console.error("Error publishing product:", error);
  toast.error(`Error: ${error.message}`);
} finally {
  setLoading(false);
  setIsSubmitting(false);
}

};

api:

import { ApolloClient, InMemoryCache, HttpLink, from, gql, } from "@apollo/client"; import { setContext } from "@apollo/client/link/context"; import { NextResponse } from "next/server";

export async function POST(req: Request) { const httpLink = new HttpLink({ uri: "https://quickstart-d414285b.myshopify.com/admin/api/2024-07/graphql.json", });

const authLink = setContext((_, { headers }) => { return { headers: { ...headers, "Content-Type": "application/json", "X-Shopify-Access-Token": process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN, }, }; });

const client = new ApolloClient({ link: from([authLink, httpLink]), cache: new InMemoryCache(), });

try { const body = await req.json(); const operation = body.query || body.mutation; console.log(operation, "operation");

if (!operation) {
  return NextResponse.json(
    { status: 400, error: "Missing query or mutation in request body" },
    { status: 400 }
  );
}

const gqlOperation = gql`
  ${operation}
`;

let result;
if (operation.trim().startsWith("query")) {
  result = await client.query({
    query: gqlOperation,
  });
} else if (operation.trim().startsWith("mutation")) {
  result = await client.mutate({
    mutation: gqlOperation,
  });
} else {
  return NextResponse.json(
    { status: 400, error: "Invalid GraphQL operation" },
    { status: 400 }
  );
}

return NextResponse.json({ status: 200, data: result.data });

} catch (error) { console.error("GraphQL Operation Error:", error); return NextResponse.json({ status: 500, error: error.message }); } }

mutation: import { gql } from "@apollo/client"; export const CREATE_PRODUCT = gql mutation createProduct($input: ProductInput!) { productCreate(input: $input) { product { id title descriptionHtml } } } ;

usama7365 commented 2 weeks ago

You'll need to modify both the client-side handleSubmit function and the server-side API logic. Here's how you can do it:

1. Update handleSubmit function to use GraphQL

You'll need to replace the axios.post calls with GraphQL mutations. Here's how to do it:

import { useMutation, gql } from '@apollo/client';

const CREATE_PRODUCT_MUTATION = gql`
  mutation createProduct($input: ProductInput!) {
    productCreate(input: $input) {
      product {
        id
        title
        descriptionHtml
      }
    }
  }
`;

const handleSubmit = async () => {
  const title = (document.getElementById("title") as HTMLInputElement).value.trim();
  const description = (document.getElementById("description") as HTMLTextAreaElement).value.trim();

  if (!title) {
    toast.error("Product title is required.");
    return;
  }

  if (!description) {
    toast.error("Product description is required.");
    return;
  }

  if (Object.values(checkboxStates).every((checked) => !checked)) {
    toast.error("Please select at least one store.");
    return;
  }

  const [createProduct] = useMutation(CREATE_PRODUCT_MUTATION);

  try {
    const updatedProduct = {
      uuid: selectedProduct?.data.uuid,
      title,
      description,
      status: "publish",
    };
    setIsSubmitting(true);

    const productPrice = selectedProduct?.data.price || "30$";
    const productSku = selectedProduct?.data.sku;
    const shopifyProduct = {
      title: updatedProduct.title || "Title",
      body_html: updatedProduct.description,
      vendor: "Sticker",
      product_type: "sticker",
      variants: [
        {
          option1: updatedProduct.title || "Missing title",
          price: parseFloat(productPrice.replace(/[^0-9.]/g, "")),
          sku: productSku || "SKU-undefined",
        },
      ],
      images: [
        {
          src: selectedProduct?.data.imageUrl || selectedProduct?.data.frontUrl || selectedProduct?.data.leftImage || "",
        },
      ],
    };

    // Call GraphQL mutation instead of REST API
    await createProduct({
      variables: {
        input: {
          title: shopifyProduct.title,
          descriptionHtml: shopifyProduct.body_html,
          vendor: shopifyProduct.vendor,
          productType: shopifyProduct.product_type,
          variants: shopifyProduct.variants,
          images: shopifyProduct.images,
        }
      }
    });

    toast.success("Product Published Successfully!");
    localStorage.removeItem("selectedProduct");
    setSelectedProduct(null);
    router.push("/products/newProducts");
  } catch (error) {
    console.error("Error publishing product:", error);
    toast.error(`Error: ${error.message}`);
  } finally {
    setLoading(false);
    setIsSubmitting(false);
  }
};

2. Update the API endpoint to handle GraphQL mutations

In your server-side API, ensure that the POST method in your API handles the mutation operation. You've already set up the Apollo Client, so you just need to make sure the mutation is correctly passed and executed.

Here's an example mutation to create a product:

export const CREATE_PRODUCT = gql`
  mutation createProduct($input: ProductInput!) {
    productCreate(input: $input) {
      product {
        id
        title
        descriptionHtml
      }
    }
  }
`;

export async function POST(req: Request) {
  // Your existing Apollo Client setup
  const client = new ApolloClient({
    link: from([authLink, httpLink]),
    cache: new InMemoryCache(),
  });

  try {
    const body = await req.json();
    const operation = body.query || body.mutation;

    if (!operation) {
      return NextResponse.json(
        { status: 400, error: "Missing query or mutation in request body" },
        { status: 400 }
      );
    }

    const gqlOperation = gql`
      ${operation}
    `;

    let result;
    if (operation.trim().startsWith("query")) {
      result = await client.query({
        query: gqlOperation,
      });
    } else if (operation.trim().startsWith("mutation")) {
      result = await client.mutate({
        mutation: gqlOperation,
      });
    } else {
      return NextResponse.json(
        { status: 400, error: "Invalid GraphQL operation" },
        { status: 400 }
      );
    }

    return NextResponse.json({ status: 200, data: result.data });
  } catch (error) {
    console.error("GraphQL Operation Error:", error);
    return NextResponse.json({ status: 500, error: error.message });
  }
}

Notes:

happy coding