Tell me about how to solve the problem of "406 Not Acceptable", when connecting the db

Hi, there!
When I copied and pasted the code in /web/index.js of the tutorial for the Shopify App, my browser(Chrome) showed the following screen as “406 Not Acceptable”.

In order to fix this error, what files should I fix and how should I fix them?

In addition, for this question, I add up two explanations.

1. My screen of the terminal

My terminal now shows the screen above.

2. Errors in /web/index.js

Now, I’m using VS Code to program the app. VS Code shows 12 errors in /web/index.js of the tutorial above after I copied and pasted the code based on the tutorial.

Thank you.

2 Likes

Same issue here

Just now, I posted the same question in the Japanese community.
If I get the solution there, I will bring it back here.

https://community.shopify.com/c/%E6%8A%80%E8%A1%93%E7%9A%84%E3%81%AAq-a/%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%A8api%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%82%92%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E8%A1%A8%E3%81%95%E3%82%8C%E3%82%8B406%E3%82%A8%E3%83%A9%E3%83%BC%E3%82%92%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%82%92%E6%95%99%E3%81%88%E3%81%A6%E3%81%8F/m-p/1709025#M5481

I had the same error because LATEST_API_VERSION wasn’t in my env path.

The boilerplate imports it from “@shopify/shopify-api”; but it comes from the env in the tutorial.

Change API_VERSION: process.env.LATEST_API_VERSION, to API_VERSION: LATEST_API_VERSION,

(with import { Shopify, LATEST_API_VERSION } from “@shopify/shopify-api”;).

1 Like

Hi, CommentCoder.
Thank you for your comment.

My browser still shows 406 Not Acceptable", even though Change API_VERSION: process.env.LATEST_API_VERSION, to API_VERSION: LATEST_API_VERSION, with import { Shopify, LATEST_API_VERSION } from “@shopify/shopify-api”;, like this.

In addition to that, when it comes to “my env path” and “the env in the tutorial”, .env file doesn’t exist in my app. How did you get the .env file?

Some env variables are in the .env file at the root of your project, others must be defined by Shopify directly and are only required in your config files if you deploy in another environment with Heroku or Docker.

Here is my index.js complete file:

// -check
import { join } from "path";
import fs from "fs";
import express from "express";
import cookieParser from "cookie-parser";
import { Shopify, LATEST_API_VERSION } from "@shopify/shopify-api";

import applyAuthMiddleware from "./middleware/auth.js";
import verifyRequest from "./middleware/verify-request.js";
import { setupGDPRWebHooks } from "./gdpr.js";
import productCreator from "./helpers/product-creator.js";
import { BillingInterval } from "./helpers/ensure-billing.js";
import { AppInstallations } from "./app_installations.js";

import applyQrCodeApiEndpoints from "./middleware/qr-code-api.js";
import { QrCodesDB } from "./backend/qr-codes-db.js";

const USE_ONLINE_TOKENS = false;
const TOP_LEVEL_OAUTH_COOKIE = "shopify_top_level_oauth";

const PORT = parseInt(process.env.BACKEND_PORT || process.env.PORT, 10);

// TODO: There should be provided by env vars
const DEV_INDEX_PATH = `${process.cwd()}/frontend/`;
const PROD_INDEX_PATH = `${process.cwd()}/frontend/dist/`;

// const DB_PATH = `${process.cwd()}/database.sqlite`;

// Shopify.Context.initialize({
//   API_KEY: process.env.SHOPIFY_API_KEY,
//   API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
//   SCOPES: process.env.SCOPES.split(","),
//   HOST_NAME: process.env.HOST.replace(/https?:\/\//, ""),
//   HOST_SCHEME: process.env.HOST.split("://")[0],
//   API_VERSION: LATEST_API_VERSION,
//   IS_EMBEDDED_APP: true,
//   // This should be replaced with your preferred storage strategy
//   SESSION_STORAGE: new Shopify.Session.SQLiteSessionStorage(DB_PATH),
// });

const dbFile = join(process.cwd(), "database.sqlite");
const sessionDb = new Shopify.Session.SQLiteSessionStorage(dbFile);

// Initialize SQLite DB
QrCodesDB.db = sessionDb.db;
QrCodesDB.init();

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: process.env.SCOPES.split(","),
  HOST_NAME: process.env.HOST.replace(/https?:\/\//, ""),
  HOST_SCHEME: process.env.HOST.split("://")[0],
  API_VERSION: LATEST_API_VERSION,
  IS_EMBEDDED_APP: true,
  SESSION_STORAGE: sessionDb,
});

Shopify.Webhooks.Registry.addHandler("APP_UNINSTALLED", {
  path: "/api/webhooks",
  webhookHandler: async (_topic, shop, _body) => {
    await AppInstallations.delete(shop);
  },
});

// The transactions with Shopify will always be marked as test transactions, unless NODE_ENV is production.
// See the ensureBilling helper to learn more about billing in this template.
const BILLING_SETTINGS = {
  required: false,
  // This is an example configuration that would do a one-time charge for $5 (only USD is currently supported)
  // chargeName: "My Shopify One-Time Charge",
  // amount: 5.0,
  // currencyCode: "USD",
  // interval: BillingInterval.OneTime,
};

// This sets up the mandatory GDPR webhooks. You’ll need to fill in the endpoint
// in the “GDPR mandatory webhooks” section in the “App setup” tab, and customize
// the code when you store customer data.
//
// More details can be found on shopify.dev:
// https://shopify.dev/apps/webhooks/configuration/mandatory-webhooks
setupGDPRWebHooks("/api/webhooks");

// export for test use only
export async function createServer(
  root = process.cwd(),
  isProd = process.env.NODE_ENV === "production",
  billingSettings = BILLING_SETTINGS
) {
  const app = express();
  app.set("top-level-oauth-cookie", TOP_LEVEL_OAUTH_COOKIE);
  app.set("use-online-tokens", USE_ONLINE_TOKENS);

  app.use(cookieParser(Shopify.Context.API_SECRET_KEY));

  applyAuthMiddleware(app, {
    billing: billingSettings,
  });

  // Do not call app.use(express.json()) before processing webhooks with
  // Shopify.Webhooks.Registry.process().
  // See https://github.com/Shopify/shopify-api-node/blob/main/docs/usage/webhooks.md#note-regarding-use-of-body-parsers
  // for more details.
  app.post("/api/webhooks", async (req, res) => {
    try {
      await Shopify.Webhooks.Registry.process(req, res);
      console.log(`Webhook processed, returned status code 200`);
    } catch (e) {
      console.log(`Failed to process webhook: ${e.message}`);
      if (!res.headersSent) {
        res.status(500).send(e.message);
      }
    }
  });

  // All endpoints after this point will require an active session
  app.use(
    "/api/*",
    verifyRequest(app, {
      billing: billingSettings,
    })
  );

  app.get("/api/products/list", async (req, res) => {
    const session = await Shopify.Utils.loadCurrentSession(
      req,
      res,
      app.get("use-online-tokens")
    );
    const { Product } = await import(
      `@shopify/shopify-api/dist/rest-resources/${Shopify.Context.API_VERSION}/index.js`
    );

    const allData = await Product.all({ session });
    res.status(200).send(allData);
  });

  app.get("/api/products/count", async (req, res) => {
    const session = await Shopify.Utils.loadCurrentSession(
      req,
      res,
      app.get("use-online-tokens")
    );
    const { Product } = await import(
      `@shopify/shopify-api/dist/rest-resources/${Shopify.Context.API_VERSION}/index.js`
    );

    const countData = await Product.count({ session });
    res.status(200).send(countData);
  });

  app.get("/api/products/create", async (req, res) => {
    const session = await Shopify.Utils.loadCurrentSession(
      req,
      res,
      app.get("use-online-tokens")
    );
    let status = 200;
    let error = null;

    try {
      await productCreator(session);
    } catch (e) {
      console.log(`Failed to process products/create: ${e.message}`);
      status = 500;
      error = e.message;
    }
    res.status(status).send({ success: status === 200, error });
  });

  // All endpoints after this point will have access to a request.body
  // attribute, as a result of the express.json() middleware
  app.use(express.json());
  applyQrCodeApiEndpoints(app);

  app.use((req, res, next) => {
    const shop = Shopify.Utils.sanitizeShop(req.query.shop);
    if (Shopify.Context.IS_EMBEDDED_APP && shop) {
      res.setHeader(
        "Content-Security-Policy",
        `frame-ancestors https://${encodeURIComponent(
          shop
        )} https://admin.shopify.com;`
      );
    } else {
      res.setHeader("Content-Security-Policy", `frame-ancestors 'none';`);
    }
    next();
  });

  if (isProd) {
    const compression = await import("compression").then(
      ({ default: fn }) => fn
    );
    const serveStatic = await import("serve-static").then(
      ({ default: fn }) => fn
    );
    app.use(compression());
    app.use(serveStatic(PROD_INDEX_PATH, { index: false }));
  }

  app.use("/*", async (req, res, next) => {
    const shop = Shopify.Utils.sanitizeShop(req.query.shop);
    if (!shop) {
      res.status(500);
      return res.send("No shop provided");
    }

    const appInstalled = await AppInstallations.includes(shop);

    if (shop && !appInstalled) {
      res.redirect(`/api/auth?shop=${encodeURIComponent(shop)}`);
    } else {
      const fs = await import("fs");
      const fallbackFile = join(
        isProd ? PROD_INDEX_PATH : DEV_INDEX_PATH,
        "index.html"
      );
      res
        .status(200)
        .set("Content-Type", "text/html")
        .send(fs.readFileSync(fallbackFile));
    }
  });

  return { app };
}

createServer().then(({ app }) => app.listen(PORT));

I hope it helps!

1 Like

Hi, CommentCoder.
Thank you for sharing your experience.

You said, “Some env variables are in the .env file at the root of your project”

I have a question about the “.env file” below.

When you create a new app by running “npm init @shopify/app@latest”, did you get the “.env file” at the root of your project? Or after creating a new app, did you set the “.env file” yourself?

Thanks.