AppBridge with CDN: host must be provided

Thomas47
Shopify Partner
54 0 11

Has anyone succesfully run the CDN-version of the AppBridge? I'm following the examples, but getting the error

APP::ERROR::INVALID_CONFIG: host must be provided

on the createApp(..) call. The problem is, host is not mentioned in the documentation (which is really fragmented / confusing IMHO) - adding it just fails with another exception.

0 Likes
LWalsh
New Member
1 0 0

Have the same issue. 

 

        var AppBridge = window['app-bridge'];
        var createApp = AppBridge.createApp;
        const app = createApp({
            apiKey: '{{api}}',
            shopOrigin: '{{host}}'
        });

 

APP::ERROR::INVALID_CONFIG: host must be provided

 

0 Likes
Thomas47
Shopify Partner
54 0 11

It is like those who wrote the docs forgot to verify that the examples actually work. 

I've created an issue on the shopify-app-bridge tracker on github.

FlorianP
Tourist
5 0 2

Hello,

I managed to solve this issue with the code below.

          function getP(n, url = window.location.href) {
              n = n.replace(/[\[\]]/g, '\\$&');
              var regex = new RegExp('[?&]' + n + '(=([^&#]*)|&|#|$)'),
                  res = regex.exec(url);
              if (!res) return null;
              if (!res[2]) return '';
              return decodeURIComponent(res[2].replace(/\+/g, ' '));
          }

          var AppBridge = window['app-bridge'];
          var createApp = AppBridge.default;
          var shopOrigin = getP('shopOrigin');
          var host = getP('host');

          var app = createApp({
              apiKey: '{{you api key}}',
              shopOrigin: shopOrigin,
              host: host,
              forceRedirect: true
          });

 

Hope it can help.

Regards

Thomas47
Shopify Partner
54 0 11

Looks promising, so that is the "host" value really - the myshopify domain, the shop custom domain, or the domain of the app itself?

0 Likes
FlorianP
Tourist
5 0 2

Hello,

Not sure that it is your question, but host seems to be the base64-encoded myshopify domain (example.myshopify.com => encodebase64(example.myshopify.com/admin)). 

As emphasized in my code, you can directly get it from the query string.

Regards

0 Likes
Thomas47
Shopify Partner
54 0 11

Thanks! So an example for others, the above resolves to

 

{
apiKey: "cead3d0dff76339abadd933378aa3bbc11a",
shopOrigin: "skjolbergs-nfc-shop.myshopify.com",
host: "c2tqb2xiZXJncy1uZmMtc2hvcC5teXNob3BpZnkuY29tL2FkbWlu"
}

 

where 'c2tqb2xiZXJncy1uZmMtc2hvcC5teXNob3BpZnkuY29tL2FkbWlu' is base64-encoded byte value of the String 'skjolbergs-nfc-shop.myshopify.com/admin'.

0 Likes
theantipioneer
Tourist
4 0 0

I don't get it, where is this code supposed to go ?

0 Likes
theantipioneer
Tourist
4 0 0

 

error shop admin.png

 

I get this error:

Has anyone been able to solve it? 

I followed the tutorial for node exactly but have been getting stuck, what am i doing wrong?

server.js

require("isomorphic-fetch");
const dotenv = require("dotenv");
const Koa = require("koa");
const next = require("next");
const { default: createShopifyAuth } = require("@shopify/koa-shopify-auth");
const { verifyRequest } = require("@shopify/koa-shopify-auth");
const { default: Shopify, ApiVersion } = require("@shopify/shopify-api");
const Router = require("koa-router");

dotenv.config();

Shopify.Context.initialize({
    API_KEY: process.env.SHOPIFY_API_KEY,
    API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
    SCOPES: process.env.SHOPIFY_API_SCOPES.split(","),
    HOST_NAME: process.env.SHOPIFY_APP_URL.replace(/https:\/\//, ""),
    API_VERSION: ApiVersion.April21,
    IS_EMBEDDED_APP: true,
    SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();

const ACTIVE_SHOPIFY_SHOPS = {};

app.prepare().then(() => {
    const server = new Koa();
    const router = new Router();
    server.keys = [Shopify.Context.API_SECRET_KEY];

    server.use(
        createShopifyAuth({
            afterAuth(ctx) {
                const { shop, scope } = ctx.state.shopify;
               
                ACTIVE_SHOPIFY_SHOPS[shop] = scope;

                ctx.redirect(`/`);
                ctx.redirect(`/?shop=${shop}`);
            },
        })
    );


    const handleRequest = async (ctx) => {
        await handle(ctx.req, ctx.res);
        ctx.respond = false;
        ctx.res.statusCode = 200;
    };

    router.get("/", async (ctx) => {
        const shop = ctx.query.shop;

        if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
            ctx.redirect(`/auth?shop=${shop}`);
        } else {
            await handleRequest(ctx);
        }
    });

    router.get("(/_next/static/.*)", handleRequest);
    router.get("/_next/webpack-hmr", handleRequest);
    router.get("(.*)", verifyRequest(), handleRequest);

    server.use(router.allowedMethods());
    server.use(router.routes());

    server.listen(port, () => {
        console.log(`> Ready on http://localhost:${port}`);
    });
});

.env

SHOPIFY_API_KEY=0000
SHOPIFY_API_SECRET=0000
SHOPIFY_API_SCOPES=read_products
SHOPIFY_APP_URL=https://daee3b7889af.ngrok.io

next.config.js

require("dotenv").config();
const webpack = require("webpack");

const apiKey = JSON.stringify(process.env.SHOPIFY_API_KEY);
const host = JSON.stringify(process.env.SHOPIFY_APP_URL);

module.exports = {
    webpack: (config) => {
        const env = { API_KEY: apiKey, HOST_URL: host };
        config.plugins.push(new webpack.DefinePlugin(env));
        return config;
    },
};

app.js

import App from "next/app";
import Head from "next/head";
import { AppProvider } from "@shopify/polaris";
import { Provider } from "@shopify/app-bridge-react";
import "@shopify/polaris/dist/styles.css";
import translations from "@shopify/polaris/locales/en.json";
import ClientRouter from "../components/ClientRouter";

class MyApp extends App {
    render() {
        const { Component, pageProps, shopOrigin, host } = this.props;
        const config = {
            apiKey: API_KEY,
            shopOrigin,
            host,
            forceRedirect: true,
        };
        return (
            <React.Fragment>
                <Head>
                    <title>Sample App</title>
                    <meta charSet="utf-8" />
                </Head>
                <Provider config={config}>
                    <ClientRouter />
                    <AppProvider i18n={translations}>
                        <Component {...pageProps} />
                    </AppProvider>
                </Provider>
            </React.Fragment>
        );
    }
}
MyApp.getInitialProps = async ({ ctx }) => {
    return {
        shopOrigin: ctx.query.shop, host: ctx.query.host 
    };
};

export default MyApp;

 

 

 

0 Likes
Thomas47
Shopify Partner
54 0 11

Into the createApp(..) method.

0 Likes