Shopify插件开发入坑体验

前言

由于公司的需求开发Shopify的应用插件自己特地记录下。简单的介绍下Shopify,它是由托比亚斯·卢克创办的加拿大电子商务软件开发商,总部位于加拿大首都渥太华,其提供的服务软件Shopify是一个SaaS领域的购物车系统,适合跨境电商建立独立站,用户支付一定费用即可在其上利用各种主题/模板建立自己的网上商店。

开发插件官方推荐是用React的next.js服务端渲染框架以及node.js作为后端语言使用GraphQL开发。作为没接触过GraphQL的我赶紧补了一波知识。后来我一路跌跌撞撞终于现在是了解了一个大概。最终我还是使用node作为主入口程序,验证应用插件获取相关的access_token和商店地址。剩下的请求什么Shopify接口也没有用GraphQL而是使用ResfulApi让后端工作人员去操作了,然后我请求后端接口进行一系列操作。

注册获取开发前提要素

(1)创建Shopify开发者账号

如图在 https://developers.shopify.com/ 网站注册相关的账号。

Shopify创建开发者账号

(2)在相关partners的页面创建商店(以供后面开发应用使用)以及应用

Shopify Partners页面

(3)在创建应用的有自定义应用和公共应用如图:

Shopify创建应用

一般我们都是创建的公共应用,在创建应用的时候URL和相关的重定向URL都是必须写的因为我也没有注册域名啥的吧,所以此时是用了ngrok内网穿透,在官方的开发介绍中也是使用这个。在此我们填写的URL就要和使用ngrok暴露出去的地址对应了,不过使用node的koa框架有个专门的中间件也是官方使用的重定向地址都是域名后加上了shopify/auth 例如:URL:https://30aca829.ngrok.io, 重定向URL:https://30aca829.ngrok.io/shopify/auth/ (电脑重启重新暴露出去这个连个地址都是要重新填一遍,然后koa的中间件就会跳转到 https://30aca829.ngrok.io/shopify/auth/ 进行相关的验证操作。然后在后期我们没有用koa作为入口这个地址也是可以自己想怎么填就怎么填)。

(4)创建完成(拿取相关的密钥很重要!!很重要!!作为开发读取数据和请求官方api使用)

Shopify应用API秘钥

编写开发环境程序

(1)创建项目目录(sample-app),并使用npm初始化项目目录

npm init -y

(2)安装相关依赖

npm install --save react react-dom next

(3)因为是用next.js所以不熟悉的还得看看官方文档 nextjs.frontendx.cn/

创建文件pages并在下面新建index.js

const Index = () => (
  <div>
    <p>Sample app using React and Next.js</p>
  </div>
);

export default Index;

添加相关运行命令打开package.json文件添加

{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}

(4)运行开发环境

npm run dev

到这里应该是创建一个next.js项目然后接下来对接到Shopify

(5)使用ngrok暴露出去自己的3000端口因为next.js启动的默认是3000端口

ngrok http 3000

Shopify koa授权使用ngrok暴露端口

然后在自己创建的应用中设置中添加对应的url(得用https的)就在上面所说的填写url

(6)使用node的 koa来进行渲染页面操作

  • 创建env环境变量文件并写入在上面创建的应用的KEY
SHOPIFY_API_KEY='YOUR API KEY FROM SHOPIFY PARTNERS DASHBOARD'
SHOPIFY_API_SECRET_KEY='YOUR API SECRET KEY FROM SHOPIFY PARTNERS DASHBOARD'
  • 安装相关Shopify的验证koa中间件
npm install --save koa @shopify/koa-shopify-auth @shopify/koa-shopify-graphql-proxy dotenv koa-session isomorphic-fetch
  • 创建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();
// graphql的相关中间件
const { default: graphQLProxy } = require('@shopify/koa-shopify-graphql-proxy'); 
const { ApiVersion } = require('@shopify/koa-shopify-graphql-proxy');

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; // 环境变量里读取 api-key与api-secret-key
app.prepare().then(() => {
  const server = new Koa();
  server.use(session(server));
  server.keys = [SHOPIFY_API_SECRET_KEY];

  server.use(
    createShopifyAuth({
      apiKey: SHOPIFY_API_KEY,
      secret: SHOPIFY_API_SECRET_KEY, 
      scopes: ['read_products', 'write_products'], //填写相关应用api相关请求的权限
      afterAuth(ctx) {
        const { shop, accessToken } = ctx.session; // 通过session拿取相关商店地址以及请求api需要的accessToken
        ctx.cookies.set('shopOrigin', shop, { httpOnly: false }); 
        ctx.redirect('/'); // 重定向到index首页
      },
    }),
  );

  server.use(verifyRequest());
  server.use(async (ctx) => {
    await handle(ctx.req, ctx.res);
    ctx.respond = false;
    ctx.res.statusCode = 200;
    return
  });
  server.use(graphQLProxy({version: ApiVersion.October19})) // 这里填写相关api的版本

  server.listen(port, () => {
    console.log(`> Ready on http://localhost:${port}`); // 监听端口
  });
});
  • 修改package.json文件使用我们的server.js来启动项目
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "node server.js",
    "start": "NODE_ENV=production node server.js",
    "build": "next build",
  }
}
  • 现在我们启动项目并且用ngrok暴露出去的域名就能看到

Shopify koa授权跳转

这里还要在域名的shop填写我们的商店地址例如我自己的:

https://e44132cd.ngrok.io/auth/inline?shop=jetbn.myshopify.com

一切填写就绪之后一enter页面就自动跳转了。

最后展示的页面:

Shopify授权完成跳转页面

折腾其他框架尝试

前前后后都是使用React的next.js开发了两三个应用,感觉就是开发的时候太麻烦了,总要内网穿透,而且展示的页面都是Shopify的的自己平台上,而且开发写完代码等它响应过来还很慢。就这原因我又开始折腾了寻求其他的方案看看有没有能在自己开发完了再到它那上面,而且让验证Shopify的一系列操作让我们的后端小哥来操作。最终我前端选择Vue并且验证都放后端了,这样我就能像平常开发Vue项一样了。

下面介绍下我纯前端进行Shopify的验证操作使用vue(前提要素内网穿透,不过开发的时候不需要)

(1)添加安装应用路由

  {
    path: '/shopify/install',
    beforeEnter(to, _from, next) {
      if (to.query.shop) {  //要在域名后添加开发的商店地址
          const shop = to.query.shop,
          scopes = 'read_orders,read_products,write_products', // api权限
          // 重定向地址就是在创建应用的时候填写的第二个(重定向URL可以自己随意写了),我这里是域名加/shopify/auth
          redirect_uri = 'https://' + process.env.VUE_APP_ROOT_URL + '/shopify/auth', 
          // 拼接安装应用地址需要SHOPIFY_API_KEY我填写在我的.env文件中了
          install_url =
                'http://' + shop + '/admin/oauth/authorize?client_id=' +
                process.env.VUE_APP_SHOPIFY_API_KEY +
                '&scope=' + scopes + '&redirect_uri=' + redirect_uri
        // 本地跳转安装地址
        window.location = install_url
      } else {
        next({ path: '/error' })
      }
    }
  },

(2)重定向验证路由

  {
    path: '/shopify/auth',
    beforeEnter(to, _from, next) {
    // 通过回调的url获取相关的参数
      const shop = to.query.shop,
        hmac = to.query.hmac,
        code = to.query.code
    // 使用SHOPIFY_API_SECRET_KEY验证 并且之后拿取access_token(这步没写)
      if (shop && hmac && code) {
        const map = Object.assign({}, to.query)
        delete map['signature']
        delete map['hmac']
        const message = querystring.stringify(map)
        const encrypted =
          crypto.createHmac('sha256', process.env.VUE_APP_SHOPIFY_API_SECRET_KEY)
                .update(message)
                .digest('hex')
        // const providedHmac =  Buffer.from(hmac, 'utf-8')
        // const generatedHash = Buffer.from(encrypted, 'utf-8')

        let hashEquals = false

        try {
          // later: Auth fails with `crypto.timingSafeEqual`
          // hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
          hashEquals = hmac === encrypted
        } catch (e) {
          hashEquals = false
        }

        if (!hashEquals) {
          next({ path: '/error' })
        } else {
          next('/')
        }
      } else {
        next({ path: '/error' })
      }
    }
  }

Vue这相关的验证方案也是从Github上面捞的,特地记录下。具体地址忘了,有需要自己可以搜搜。

参考文档

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/26/shopify-plugin-development-experience/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Shopify插件开发入坑体验
前言 由于公司的需求开发Shopify的应用插件自己特地记录下。简单的介绍下Shopify,它是由托比亚斯·卢克创办的加拿大电子商务软件开发商,总部位于加拿大首都渥……
<<上一篇
下一篇>>
文章目录
关闭
目 录