Shopify插件开发入坑体验

10,095 阅读7分钟

前言


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

    由于是国外的官网文档也都是英文,看起来有点吃力哦(小生英文水平有限🤣🤣)。不过之后应该有中文了现在很多页面有中文了已经。

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

注册获取开发前提要素

  1. 创建Shopify开发者账号
    如图在developers.shopify.com/网站注册相关的账号。
  2. 在相关partners的页面创建商店(以供后面开发应用使用)以及应用
    1. 在创建应用的有自定义应用和公共应用如图:
      一般我相信我我们都是创建的公共应用,到目前我开发的应用也都是公共类型,在创建应用的时候URL和相关的重定向URL都是必须写的因为我也没有注册域名啥的吧,所以此时是用了ngrok内网穿透,在官方的开发介绍中也是使用这个。在此我们填写的URL就要和你使用ngrok暴露出去的地址对应了,不过使用nodekoa框架有个专门的中间件也是官方使用的重定向地址都是域名后加上了shopify/auth 例如: URL:https://30aca829.ngrok.io, 重定向URL:https://30aca829.ngrok.io/shopify/auth/(电脑重启重新暴露出去这个连个地址都是要重新填一遍,然后koa的中间件就会跳转到https://30aca829.ngrok.io/shopify/auth/进行相关的验证操作。(这在后面的入口)。序中会上代码,然后在后期我们没有用koa作为入口这个地址也是可以自己想怎么填就怎么填)。
    2. 创建完成(拿取相关的密钥很重要!!很重要!!作为开发读取数据和请求官方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"
      }
    }
    

    运行开发环境

    npm run dev
    

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

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

    ngrok http 3000
    

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

  5. 使用nodekoa来进行渲染页面操作

    1. 创建env环境变量文件并写入在上面创建的应用的KEY

      SHOPIFY_API_KEY='YOUR API KEY FROM SHOPIFY PARTNERS DASHBOARD'
      SHOPIFY_API_SECRET_KEY='YOUR API SECRET KEY FROM SHOPIFY PARTNERS DASHBOARD'
      
    2. 安装相关Shopify的验证koa中间件

      npm install --save koa @shopify/koa-shopify-auth dotenv koa-session isomorphic-fetch
      
    3. 创建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}`); // 监听端口
        });
      });
      
      
    4. 修改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暴露出去的域名就能看到

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

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

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

      最后展示的页面:

折腾其他框架尝试

    前前后后都是使用Reactnext.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上面捞的,特地记录下。具体地址忘了,有需要自己可以搜搜。🤣

总结

    经过一段时间的熟悉,自己也算又掌握一项新东西了。刚开始这个Shopify插件应用开发真的是巨坑啊,虽然官方有文档流程,但是都是英文的而且基础的搭建都是api都是用GraphQL然后我自己尝试了都是各种超时操作,请求不到最后就自己弃用了,用ResfulApi。然后就是遇到问题啊啥的都跟本搜不到,我想着这也太难了我,然后只能硬着头皮去官方文档里找,最后到现在也算是起起伏伏终于都熟悉了,搞懂了。

     这之后发现了英文水平太重要了。虽然开发文档基本内容能看懂,但是都是半猜半疑的,然后翻译一波。(各种不准确),然后开始补英文吧。🤞

     最后放上几个Shopify开发常用的官方文档地址:

    Shopify Partners(创建应用查看应用): vue-composition-api-rfc.netlify.com

    Shopify Developers(官方开发文档): developers.shopify.com(搭建参考文档)

    Shopify Polaris(官方UI框架): developers.shopify.com