Shopify App React and NodeJS tutorial - API_KEY not defined

tobrien
Tourist
5 1 1

Hi,

I am new to Shopify development and React (although I have developed for NodeJS Express before).

Following the steps in the 'Build a Shopify App with Node and React tutorial' (https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react/build-your-user-interface-with...), I have hit a snag.

At the point of setting the Shopify App Bridge, the instructions say to add a <Provider config={config}> tag. Having defined config previously as: { apiKey: API_KEY, shopOrigin: Cookies.get("shopOrigin"), forceRedirect: true }

The problem is, as I can see in the example code provided in the tutorial, API_KEY is not defined, and predictably I get the appropriate error when testing the app from the Store admin. Even if I define API_KEY as the SHOPIFY_API_KEY from process.env, I encounter a new error: apiKey must be provided.

I'm officially at a loss. Any help would be appreciated.

Capture_1.PNG

 

0 Likes
paulomarg
Shopify Staff
Shopify Staff
8 1 2

Hi @tobrien,

 

The API_KEY value here is expected to be set as an environment variable within your app. One way of doing that is to set the value as a webpack plugin (at compile time) in your next.config.js file like so:

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

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

 

You can find some more information on DefinePlugin in the webpack docs.

 

Hope this helps!

Paulo

0 Likes
tobrien
Tourist
5 1 1

Hi @paulomarg 

Thank you for your response. I did forget to mention I have included this in my next.config.js:

require("dotenv").config()

const withCSS = require('@zeit/next-css')
const webpack = require('webpack')

const apiKey = JSON.stringify(process.env.SHOPIFY_API_KEY)

module.exports = withCSS({
  webpack: (config) => {
    const env = { API_KEY: apiKey }
    config.plugins.push(new webpack.DefinePlugin(env))
    return config
  }
})
Am I missing something obvious (like a typo)? Is it something to do with how I am starting the application or the structure of my project?
I did have everything working as in the tutorial up until this point.
 
Thanks
Tom
0 Likes
paulomarg
Shopify Staff
Shopify Staff
8 1 2

Hi again!

 

This looks OK to me, the demo project is set up so API_KEY should be set at that point. It could indeed be some other issue as you said.

 

The first thing I'd suggest is to make sure that your API key is set in your .env file, and to check that the value is being set at this point when you recompile your project.

0 Likes
tobrien
Tourist
5 1 1

For anyone else that encounters this, a restart of ngrok seemed to do the trick. Although I'm sure I had done that before posting, this also resolved the issue when I subsequently encountered the error.

Of course first check that next.config.js is set up properly as described.

samsuzuki
Tourist
4 0 1

I have the same issue 'AppBridgeError: APP::ERROR::INVALID_CONFIG: apiKey must be provided'.

I cannot solve this, by restarting ngrok, nodejs-server. 

Any solutions?

0 Likes
paulomarg
Shopify Staff
Shopify Staff
8 1 2

Hi @samsuzuki,

Can you please provide a bit more detail on the error you're seeing, like when does it happen, and the code that triggers it?

Also, just to check all the boxes, make sure your API key is set in your .env file and is being properly loaded when your server starts.

Thank you!

0 Likes
samsuzuki
Tourist
4 0 1

@paulomarg Thank you for your reply. Sorry for my lack of information.

I'm new as a React/ Node.js developer( usually I am a iOS app developer).

And I was doing this tutorial . It works fine halfway.

But, at this part(#Add Shopify Bridge), my code does not work fine. Before 'Add Shopify Bridge' section, my code works fine.

When I open below URL(my ngrok with OAuth) after writing "Add Shopify Bridge" code with restarting web-server and ngrok, this error message appear.

https://24e3f0c517ea.ngrok.io/auth?shop=xn-ccka2ewcwdtfo276cihcb50i.myshopify.com

Error Message:  

Unhandled Runtime Error

AppBridgeError: APP::ERROR::INVALID_CONFIG: apiKey must be provided

Browser(Google Chrome) console error message:

AppbridgeError_googlechrome_console.png

My development enviroment

  • Node.js: v10.22.0
  • npm: 6.14.6
  • macOS: 10.15.5 (Catalina)
  • Google Chrome: 84.0.4147.105
  • Project Package(package.json) dependencies
"@shopify/app-bridge-react": "^1.26.2",
"@shopify/koa-shopify-auth": "^3.1.65",
"@shopify/polaris": "^5.2.0",
"@zeit/next-css": "^1.0.1",
"dotenv": "^8.2.0",
"isomorphic-fetch": "^2.2.1",
"js-cookie": "^2.2.1",
"koa": "^2.13.0",
"koa-session": "^6.0.0",
"next": "^9.5.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
 

My code is below.

/.env 

SHOPIFY_API_KEY='xxxxxxxx'
SHOPIFY_API_SECRET_KEY='xxxxxxx'

/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 session = require('koa-session');

dotenv.config();

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

const { SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY } = process.env;

app.prepare().then(() => {
    const server = new Koa();
    server.use(session({ secure: true, sameSite: 'none' }, server));
    server.keys = [SHOPIFY_API_SECRET_KEY];

    server.use(
        createShopifyAuth({
            apiKey: SHOPIFY_API_KEY,
            secret: SHOPIFY_API_SECRET_KEY,
            scopes: ['read_products'],
            afterAuth(ctx) {
                const { shop, accessToken} = ctx.session;
                ctx.cookies.set('shopOrigin', shop, {
                    httpOnly: false,
                    secure: true,
                    sameSite: 'none'
                  });
                ctx.redirect('/');
            },
        }),
    );

    server.use(verifyRequest());
    server.use(async (ctx) => {
        await handle(ctx.req, ctx.res);
        ctx.respond = false;
        ctx.res.statusCode = 200;
        return
    });

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

});

 

/page/_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 Cookies from 'js-cookie';

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

export default MyApp;

 

/page/index.js

 

import { EmptyState, Layout, Page, TextStyle } from '@shopify/polaris';
import { TitleBar } from '@shopify/app-bridge-react';

const img = 'https://cdn.shopify.com/s/files/1/0757/9955/files/empty-state.svg';

const Index = () => (
    <Page>
        <TitleBar
        title="Sample App"
        primaryAction={{
            content: 'Select products',
        }}
        />
        <Layout>
            <EmptyState
                heading="Discount your products temporarily"
                action={{
                    content: 'Select products',
                    onAction: () => console.log('clicked!'),
                }}
                image={img}
                >
                <p>Select products to change their price temporarily.</p>
            </EmptyState>
        </Layout>
    </Page>
);

export default Index;

 

 Other code: same as codes before 'Add Shopify Bridge' section

Thank you for your support.

0 Likes
samsuzuki
Tourist
4 0 1

@paulomarg  Also, "/next.config.js" is here. 

require("dotenv").config();
const withCSS = require('@zeit/next-css');
const webpack = require('webpack');

const apiKey = JSON.stringify(process.env.SHOPFIY_API_KEY);

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

  Thank you.

0 Likes
samsuzuki
Tourist
4 0 1

@paulomarg I solved! Sorry for bothering you.

The reason of the error is here. 

const apiKey = JSON.stringify(process.env.SHOPFIY_API_KEY);

" SHOPFIY" is typo.