<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Common Ninja</title>
    <description>The latest articles on DEV Community by Common Ninja (@commonninja).</description>
    <link>https://dev.to/commonninja</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5581%2Ff9b552b8-deac-4258-ba8b-24f9c194e6d9.png</url>
      <title>DEV Community: Common Ninja</title>
      <link>https://dev.to/commonninja</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/commonninja"/>
    <language>en</language>
    <item>
      <title>Common Ninja Platform News: Squarespace Integration | Payment Plans Metadata | Shopify Partners Integration</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Wed, 31 Aug 2022 07:20:47 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninja-platform-news-squarespace-integration-payment-plans-metadata-shopify-partners-integration-6p9</link>
      <guid>https://dev.to/commonninja/common-ninja-platform-news-squarespace-integration-payment-plans-metadata-shopify-partners-integration-6p9</guid>
      <description>&lt;p&gt;We are very excited to share with you recent news and updates related to our &lt;a href="https://www.commoninja.com"&gt;developer platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although August is mostly a quiet month, we worked hard to add amazing features to Common Ninja's Developer Platform including new e-commerce and payments APIs, a new e-commerce integration with Squarespace, and an interesting connection between Common Ninja and Shopify's partners API.&lt;/p&gt;

&lt;p&gt;Just to remind you, Common Ninja is a developer platform for building and monetizing universal e-commerce apps. We provide a universal e-commerce API that allows developers to build apps once and launch them across multiple platforms. In addition, Common Ninja provides integrations with popular payment platforms - helping developers to monetize their apps very easily.&lt;/p&gt;




&lt;p&gt;🎉 What’s New:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Squarespace integration&lt;/li&gt;
&lt;li&gt;Payment plans metadata&lt;/li&gt;
&lt;li&gt;Integration with Shopify Partners API&lt;/li&gt;
&lt;li&gt;APIs

&lt;ul&gt;
&lt;li&gt;Product images API&lt;/li&gt;
&lt;li&gt;Checkout URL API&lt;/li&gt;
&lt;li&gt;User subscriptions API&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LOtKM4gP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ciz9v1szwphlt0aea480.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LOtKM4gP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ciz9v1szwphlt0aea480.png" alt="Common Ninja's Squarespace Integration" width="880" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Squarespace integration
&lt;/h2&gt;

&lt;p&gt;We're happy to announce our 9th e-commerce platform integration support, which will allow you to make your app accessible to Squarespace merchants and users. &lt;/p&gt;

&lt;p&gt;In order to add the integration, you'll need to create a Squarespace app, and use the provided &lt;code&gt;client ID&lt;/code&gt; and &lt;code&gt;client secret&lt;/code&gt;. You can learn more about it &lt;a href="https://developers.squarespace.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---pOcLr80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlv9oz33vc3nuvgu7b9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---pOcLr80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wlv9oz33vc3nuvgu7b9r.png" alt="Payment plans metadata" width="668" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment plans metadata
&lt;/h2&gt;

&lt;p&gt;Introducing the payment plan metadata editor — a new way to add custom metadata based on your app's needs. You can attach  &lt;code&gt;metadata&lt;/code&gt; to any plan or feature created in the Common Ninja's payments admin, and then consume it with the &lt;a href="https://docs.commoninja.com/apis/payments/plans/plan-object"&gt;payment plans API&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8JY_Fdby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on0fyctdg8d2sgmz1b18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8JY_Fdby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on0fyctdg8d2sgmz1b18.png" alt="Shopify partners integration" width="880" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shopify Partners API integration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;We're truly excited about this one&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This month we've added an option to connect your Common Ninja app to Shopify Partners’ API, allowing you to see subscriptions, payments, and the usage data of your universal e-commerce. Not only will this information be from Shopify merchants, but also from all other merchants from any other platform that your app is integrated with — all in one place!&lt;/p&gt;

&lt;p&gt;Learn more about how to connect your Common Ninja app to Shopify &lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/shopify"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  New APIs
&lt;/h2&gt;

&lt;p&gt;We've added support for 3 new APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/e-commerce/products/get-products-images"&gt;Product images API&lt;/a&gt;: A new set of CRUD APIs for better management of the product images resource.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/payments/plans/get-checkout-url"&gt;Checkout URL API&lt;/a&gt;: A simple endpoint for getting the checkout URL of a payment plan integrated with our payment integrations' solution.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/payments/subscriptions/get-user-subscriptions"&gt;User subscriptions&lt;/a&gt;: A new endpoint for fetching a list of user's subscriptions based on status or platform.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you have any specific requests or ideas, we'll be more than happy to &lt;a href="//mailto:contact@commoninja.com"&gt;hear them&lt;/a&gt; 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;You can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>api</category>
      <category>webdev</category>
      <category>shopify</category>
    </item>
    <item>
      <title>Fixing "frame-ancestors directive" Errors on Shopify Embedded Apps</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 22 Aug 2022 07:40:06 +0000</pubDate>
      <link>https://dev.to/commonninja/fixing-frame-ancestors-directive-errors-on-shopify-embedded-apps-3afg</link>
      <guid>https://dev.to/commonninja/fixing-frame-ancestors-directive-errors-on-shopify-embedded-apps-3afg</guid>
      <description>&lt;p&gt;Building a Shopify app can be complex, and you might face many challenges during the process. From understanding the authentication flow to using the different APIs, and handling webhooks. &lt;/p&gt;

&lt;p&gt;When you build a Shopify app, you can choose either if you want your app to be an embedded app or not. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embeddable app&lt;/strong&gt; - You can let merchants access and interact with your app within the Shopify admin or Shopify POS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-embeddable apps&lt;/strong&gt;- Merchants install your app and are then redirected outside of Shopify to your app's hosted page.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you decided to build an &lt;strong&gt;embedded app&lt;/strong&gt; for Shopify you’ll need to make sure that your app is secured and meets Shopify’s security policies and standards.&lt;/p&gt;

&lt;p&gt;One of the most common content security policy Shopify requires you to handle is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors" rel="noopener noreferrer"&gt;frame-ancestors&lt;/a&gt; - which tells the browser to allow or disallow the resources getting embedded using iframe, frame, object, embed, and applet element.&lt;/p&gt;

&lt;p&gt;I saw that many developers are facing issues with embedded apps and looking for solutions in different communities, so I decided to write about it.&lt;/p&gt;

&lt;p&gt;Here are the top 4 &lt;code&gt;frame-ancestors&lt;/code&gt; errors on Shopify embedded apps and how to fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The 'content-security-policy' header should set frame-ancestors https://[shop].myshopify.com &lt;a href="https://admin.shopify.com" rel="noopener noreferrer"&gt;https://admin.shopify.com&lt;/a&gt;, where [shop] is the shop domain the app is embedded on.
&lt;/h2&gt;

&lt;p&gt;When you submit an app to Shopify, it might be rejected even before it got to the review team. Shopify has a set of automations that run when you submit your app. If you got the above rejection, it means that you haven't set the &lt;code&gt;Content-Security-Policy: frame-ancestors &amp;lt;source&amp;gt;;&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;In order to fix it you'll need to add the &lt;code&gt;frame-ancestors&lt;/code&gt; header on the response of the frame's request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// A middleware for setting up the header&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Set the `frame-ancestors` header on the response&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Security-Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`frame-ancestors https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; https://admin.shopify.com;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Send a file, or redirect to your app's frame&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Please note&lt;/strong&gt;: the &lt;code&gt;frame-ancestors&lt;/code&gt; header must be different for each shop.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Refused to frame '{URL}' because it violates the following Content Security Policy directive: "child-src 'self' https://* shopify-pos://*". Note that 'frame-src' was not explicitly set, so 'child-src' is used as a fallback.
&lt;/h2&gt;

&lt;p&gt;This error might be caused because you're trying to load a non-secured URL. Make sure that the App URL you're using is under the &lt;code&gt;HTTPS&lt;/code&gt; protocol and not &lt;code&gt;HTTP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you're running locally (&lt;code&gt;localhost&lt;/code&gt;) you might want to use a tunnel service such as &lt;code&gt;ngrok&lt;/code&gt; or &lt;code&gt;localtunnel&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. On Safari: [Error] Refused to load &lt;a href="https://XXXX.myshopify.com/admin/auth/login" rel="noopener noreferrer"&gt;https://XXXX.myshopify.com/admin/auth/login&lt;/a&gt; because it does not appear in the frame-ancestors directive of the Content Security Policy.
&lt;/h2&gt;

&lt;p&gt;Safari is a more strict browser than Chrome or Firefox, this error might appear if you're trying to redirect the user to a different URL after the initial app URL was loaded.&lt;/p&gt;

&lt;p&gt;To fix this issue you'll need to make the redirect from the client instead of the server. Here's how:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateRedirectHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;!DOCTYPE html&amp;gt;
  &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;title&amp;gt;Redirecting, please wait...&amp;lt;/title&amp;gt;
      &amp;lt;script&amp;gt;
        setTimeout(()=&amp;gt;{
          window.top.location="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;";
        }, 3000);
      &amp;lt;/script&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        Redirecting...
    &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redirectUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_REDIRECT_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// For Safari, use client redirect&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shopify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;safari&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chrome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firefox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;generateRedirectHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// For other browsers, use redirect header&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  4. Refused to display '{URL}' in a frame because it set 'X-Frame-Options' to 'deny'.
&lt;/h2&gt;

&lt;p&gt;This error might appear when you're trying to redirect a user to your app's checkout page, or on the first time your app loads. &lt;/p&gt;

&lt;p&gt;The first thing you need to do is to make sure that the App URL is being configured correctly for the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bfaosfwyzy8zno8pw0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bfaosfwyzy8zno8pw0x.png" alt="App URL field on Shopify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, if you're trying to make the redirect from the server, try instead to make a request to the server to get the redirect URL, and make the actual redirect from the client. For example&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRedirectUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/getRedirectUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getRedirectUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Click Me&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I hope this post will help you not to spend more time on fixing &lt;code&gt;frame-ancestors&lt;/code&gt; errors on Shopify. If not, or if you have any other errors that you've seen, please leave a comment and I'll update the blog post.&lt;/p&gt;

&lt;p&gt;In addition, if you're not familiar with the &lt;a href="https://www.commoninja.com" rel="noopener noreferrer"&gt;Common Ninja Developer Platform&lt;/a&gt;, that might be a good time to mention that you can spend less time integrating with Shopify and handling these kinds of errors by using our platform 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ What is Common Ninja?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.commoninja.com" rel="noopener noreferrer"&gt;Common Ninja&lt;/a&gt; is a platform that helps developers to build &amp;amp; monetize apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;

&lt;p&gt;In addition, Common Ninja offers a set of APIs and tools that help developers to boost up the development process, and provide payments and storage solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;If you're not familiar with Common Ninja or how to build your first app using our API, here's the previous article we wrote about it.&lt;/p&gt;

&lt;p&gt;In addition, you can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com" rel="noopener noreferrer"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd" rel="noopener noreferrer"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>shopify</category>
      <category>ecommerce</category>
      <category>node</category>
    </item>
    <item>
      <title>Common Ninja's Template for WooCommerce - Bring Your E-Commerce App to WooCommerce With Zero Effort</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 18 Jul 2022 11:13:00 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninjas-template-for-woocommerce-bring-your-e-commerce-app-to-woocommerce-with-zero-effort-23dh</link>
      <guid>https://dev.to/commonninja/common-ninjas-template-for-woocommerce-bring-your-e-commerce-app-to-woocommerce-with-zero-effort-23dh</guid>
      <description>&lt;p&gt;Developing a WooCommerce plugin is not the greatest experience for developers.&lt;/p&gt;

&lt;p&gt;If you decide that you want to bring your e-commerce app to WooCommerce, you'll need to download WordPress, learn PHP, and hack your way through WordPress' different APIs and hooks in order to build the plugin you want.&lt;/p&gt;

&lt;p&gt;It’s safe to say that if you developed the original app for Shopify, BigCommerce, or Wix, you probably didn’t  use  PHP as your backend, or even plain HTML. In WordPress / WooCommerce you must use both, and the plugin development process will require you to upload your plugin's files to WordPress’ plugins directory, rather than load the app remotely from a URL.&lt;/p&gt;

&lt;p&gt;At Common Ninja, we believe that developers should focus and spend their time on building the product side of their e-commerce app, and not on the integrations with the different e-commerce platforms.&lt;/p&gt;

&lt;p&gt;The way we do that is by creating a set of tools for e-commerce app developers that allow them to reduce the time they spend on platform integrations by 90%, and to create &lt;strong&gt;one universal e-commerce app&lt;/strong&gt; for all platforms.&lt;/p&gt;

&lt;p&gt;This is why we're so happy to introduce to you &lt;strong&gt;Common Ninja's template for WooCommerce&lt;/strong&gt; — a simple way to bring your Shopify app to WooCommerce.&lt;/p&gt;

&lt;p&gt;Link to the template's repository:&lt;br&gt;
&lt;a href="https://github.com/CommonNinja/woocommerce-plugin-template"&gt;https://github.com/CommonNinja/woocommerce-plugin-template&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use
&lt;/h2&gt;

&lt;p&gt;1) Download || clone the following repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/CommonNinja/woocommerce-plugin-template.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Change the main folder's name (&lt;code&gt;plugin-template&lt;/code&gt;) to your plugin's slug name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The plugin's slug name must be unique, lower and kebab case.
3) In the &lt;code&gt;plugin-template&lt;/code&gt; folder, rename the &lt;code&gt;plugin-template.php&lt;/code&gt; file to the slug name you chose in the previous step.
4) Open the &lt;code&gt;config.php&lt;/code&gt; file under the &lt;code&gt;plugin-template&lt;/code&gt; folder and change the following details:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cn_app_id&lt;/code&gt; - Your public &lt;a href="https://www.commoninja.com/developer/apps"&gt;Common Ninja's app ID&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugin_name&lt;/code&gt; - The name of the plugin as it will appear on WordPress's menu.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugin_icon&lt;/code&gt; - The icon of the plugin as it will appear on WordPress's menu. (accepts url, base64 format, or relative path from the &lt;code&gt;_inc&lt;/code&gt; folder as root).
5) In the &lt;code&gt;plugin-template&lt;/code&gt; file, change the meta data of the plugin (the comments on top).&lt;/li&gt;
&lt;li&gt;Note, the &lt;code&gt;Text Domain&lt;/code&gt; setting must be your plugin's slug.
6) Edit and change the details on the &lt;code&gt;readme.txt&lt;/code&gt; file under the &lt;code&gt;plugin-template&lt;/code&gt; folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Please note&lt;/strong&gt;, the actual folder that you'll use for pushing your code to WordPress's SVN repo is the main folder (the one that includes the &lt;code&gt;plugin-template&lt;/code&gt; and &lt;code&gt;assets&lt;/code&gt; folders).&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Once your plugin is ready, the next step will be to submit it to WordPress' plugin directory.&lt;/p&gt;

&lt;p&gt;1) Create a .zip file from the main &lt;code&gt;plugin-template&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;2) Go to &lt;a href="https://wordpress.org/plugins/developers/add/"&gt;https://wordpress.org/plugins/developers/add/&lt;/a&gt; and submit the zip file.&lt;/p&gt;

&lt;p&gt;3) After WordPress' team reviews it, you'll get an email from &lt;code&gt;plugins@wordpress.org&lt;/code&gt;. This email will contain two links. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SVN URL: https://plugins.svn.wordpress.org/{PLUGIN_NAME}
Public URL: https://wordpress.org/plugins/{PLUGIN_NAME}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4) Run the following command to download your new repository code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;svn co https://plugins.svn.wordpress.org/{PLUGIN_NAME} {PLUGIN_NAME}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5) Copy the original code from the previous section to the &lt;code&gt;trunk&lt;/code&gt; folder. Add the relevant assets to the &lt;code&gt;assets&lt;/code&gt; folder (icon and banner).&lt;/p&gt;

&lt;p&gt;Your project's file structure should look like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- assets
- tags
- trunk
 |__ _inc
 |__ commonninja
 |__ &lt;span class="o"&gt;{&lt;/span&gt;PLUGIN_NAME&lt;span class="o"&gt;}&lt;/span&gt;.php
 |__ config.php
 |__ readme.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6) Browse to the plugin's folder and add the new files to svn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;PLUGIN_NAME&lt;span class="o"&gt;}&lt;/span&gt;
svn add trunk/&lt;span class="k"&gt;*&lt;/span&gt;
svn add assets/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7) Commit and push changes to WordPress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;svn ci &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'Adding first version of my plugin'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Your app will be ready to be used by WooCommerce users.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ What is Common Ninja?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.commoninja.com"&gt;Common Ninja&lt;/a&gt; is a platform that allows developers to build &amp;amp; monetize apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;

&lt;p&gt;In addition, Common Ninja offers a set of APIs and tools that help developers to boost up the development process, and provide payments and storage solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;If you're not familiar with Common Ninja or how to build your first app using our API, here's the previous article we wrote about it.&lt;/p&gt;

&lt;p&gt;In addition, you can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>ecommerce</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Common Ninja Platform News: New Dashboard | Store Details API | Summer Hackathon</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 11 Jul 2022 12:32:33 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninja-platform-news-new-dashboard-store-details-api-summer-hackathon-5215</link>
      <guid>https://dev.to/commonninja/common-ninja-platform-news-new-dashboard-store-details-api-summer-hackathon-5215</guid>
      <description>&lt;p&gt;We are very excited to share with you recent news and updates related to our &lt;a href="https://www.commoninja.com"&gt;developer platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This month we announced our summer hackathon for e-commerce app developers, a couple of new commerce APIs, and a brand new dashboard where you can see statistics and important information about your app.&lt;/p&gt;

&lt;p&gt;Just to remind you, Common Ninja is a developer platform for building and monetizing universal e-commerce apps. We provide a universal e-commerce API that allows developers to build apps once and launch them across multiple platforms. In addition, Common Ninja provides integrations with popular payment platforms - helping developers to monetize their apps very easily.&lt;/p&gt;




&lt;p&gt;🎉 What’s New:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New dashboard (!)&lt;/li&gt;
&lt;li&gt;APIs

&lt;ul&gt;
&lt;li&gt;Store details API&lt;/li&gt;
&lt;li&gt;Orders' range filter&lt;/li&gt;
&lt;li&gt;Proxy API&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Summer hackathon&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---_v01PtM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzyszn8rjmbrtnlxtkpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---_v01PtM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzyszn8rjmbrtnlxtkpv.png" alt="Common Ninja's Developer Dashboard" width="880" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New Dashboard (!)
&lt;/h2&gt;

&lt;p&gt;The new dashboard was released this month and introduce some important information and useful statistics about your app.&lt;/p&gt;

&lt;p&gt;The new dashboard gives you an overall snapshot of your app's performance, how many stores are using your app, and how many active subscriptions your app has. In addition it will show you information about your app's revenue and installations based on data from multiple platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  New APIs
&lt;/h2&gt;

&lt;p&gt;We added support for 3 new APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/e-commerce/store/get-store-details"&gt;Store details API&lt;/a&gt;: An endpoint for getting the store's basic details such as &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;, and &lt;code&gt;country&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/e-commerce/orders/get-orders"&gt;Orders' range filter&lt;/a&gt;: We've added support for fetching a list of store's orders with a time range filter.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/apis/proxy"&gt;Proxy API&lt;/a&gt;: An endpoint proxies requests to the relevant resource on a &lt;strong&gt;specific platform&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--llQN5WWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wa7bv7ydxrldi7l7rkb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--llQN5WWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wa7bv7ydxrldi7l7rkb.png" alt="Common Ninja's Summer Hackathon" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summer Hackathon for E-Commerce App Developers
&lt;/h2&gt;

&lt;p&gt;As &lt;a href="https://dev.to/commonninja/common-ninjas-summer-hackathon-build-e-commerce-apps-and-win-awesome-prizes-1f8j"&gt;announced&lt;/a&gt; earlier this month, our summer hackathon was officially launched last week with more than &lt;strong&gt;180 developers&lt;/strong&gt; who signed up to participate and develop e-commerce apps.&lt;/p&gt;

&lt;p&gt;Learn more about the hackathon: &lt;br&gt;
&lt;a href="https://www.commoninja.com/hackathon-2022/"&gt;https://www.commoninja.com/hackathon-2022/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you have any specific requests or ideas, we'll be more than happy to &lt;a href="//mailto:contact@commoninja.com"&gt;hear them&lt;/a&gt; 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;You can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>dashboard</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Common Ninja's Summer Hackathon: Build E-Commerce Apps, and Win Awesome Prizes!</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 04 Jul 2022 10:18:10 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninjas-summer-hackathon-build-e-commerce-apps-and-win-awesome-prizes-1f8j</link>
      <guid>https://dev.to/commonninja/common-ninjas-summer-hackathon-build-e-commerce-apps-and-win-awesome-prizes-1f8j</guid>
      <description>&lt;p&gt;The e-commerce market is huge and presents numerous opportunities for developers and companies to bring their innovation and creativity forward and solve problems for merchants and their customers.&lt;/p&gt;

&lt;p&gt;From tools that improve conversions, to smart automations that optimize sales, to useful apps that help bring more customers and more.&lt;/p&gt;

&lt;p&gt;We're happy to announce a Common Ninja's virtual hackathon for &lt;strong&gt;e-commerce app developers&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;p&gt;In the hackathon, you will build an e-commerce app using Common Ninja's universal API for commerce. You'll only need to focus on building the app’s functionality while the Common Ninja platform will take care of the integrations, authentication and monetization of your app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Registration ends on July 7th, 2022. So hurry up!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Register and learn more about the hackathon below 👇🏻&lt;br&gt;
&lt;a href="https://www.commoninja.com/hackathon-2022/"&gt;https://www.commoninja.com/hackathon-2022/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ecommerce</category>
      <category>hackathon</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Common Ninja Starter Kit - A Boilerplate Project For Building Universal E-Commerce Apps With NodeJS &amp; React</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Thu, 30 Jun 2022 10:02:38 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninja-starter-kit-a-boilerplate-project-for-building-universal-e-commerce-apps-with-nodejs-react-1aoe</link>
      <guid>https://dev.to/commonninja/common-ninja-starter-kit-a-boilerplate-project-for-building-universal-e-commerce-apps-with-nodejs-react-1aoe</guid>
      <description>&lt;p&gt;In one of the previous articles we wrote, we walked you through the process of &lt;a href="https://dev.to/commonninja/kick-off-your-first-shopify-app-with-react-nodejs-and-common-ninja-3821"&gt;building your first Shopify app with Common Ninja, NodeJS, and React&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article was very detailed, and contained a lot of code examples, but we got some feedback from many developers that it would be helpful to get a boilerplate project that will save more time on bootstrapping a new project. &lt;/p&gt;

&lt;p&gt;Well, your prayer was heard, and today we're happy to launch the official &lt;strong&gt;Common Ninja Starter Kit for NodeJS &amp;amp; ReactJS developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project is available in the link below 👇🏻, and you can follow the main &lt;code&gt;README.md&lt;/code&gt; file to see how it works:&lt;br&gt;
&lt;a href="https://github.com/CommonNinja/commonninja-node-react-starter-kit"&gt;https://github.com/CommonNinja/commonninja-node-react-starter-kit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O-n7odUQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2qocvm0esqn2ycciyt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O-n7odUQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2qocvm0esqn2ycciyt5.png" alt="Common Ninja Starter Kit" width="880" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The starter kit will enable you to run a single command, after which you'll be able to start working on your universal e-commerce app. The app will be able to support multiple platforms, including Shopify, BigCommerce, WooCommerce, Wix, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;In order to run the project you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/get-started/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yarnpkg.com/"&gt;Yarn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An account and an app on the &lt;a href="https://www.commoninja.com/developer/apps"&gt;Common Ninja Developer Platform&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these, the next step would be to prepare your environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clone the starter kit repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/CommonNinja/commonninja-node-react-starter-kit.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Browse to the project's folder (&lt;code&gt;cd commonninja-node-react-starter-kit&lt;/code&gt;) and run the following script:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/dev-setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the &lt;code&gt;packages/server&lt;/code&gt; folder, edit the &lt;code&gt;.env&lt;/code&gt; file and set your Common Ninja app credentials:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Common Ninja App&lt;/span&gt;
&lt;span class="nv"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;XXXX-XXXX-XXXX-XXXX-XXXX
&lt;span class="nv"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cn_XXXX-XXXX-XXXX-XXXX-XXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, start the project by running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Browse to the project locally at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;You can read more about the project's structure &lt;a href="https://github.com/CommonNinja/commonninja-node-react-starter-kit/blob/main/README.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next thing you should do, is to start adding integrations to e-commerce platforms, and connect your app to payment providers.&lt;/p&gt;

&lt;p&gt;You may read more about it in Common Ninja's &lt;a href="https://docs.commoninja.com"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ What is Common Ninja?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.commoninja.com"&gt;Common Ninja&lt;/a&gt; is a platform that allows developers to build &amp;amp; monetize apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;

&lt;p&gt;In addition, Common Ninja offers a set of APIs and tools that help developers to boost up the development process, and provide payments and storage solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;If you're not familiar with Common Ninja or how to build your first app using our API, here's the previous article we wrote about it.&lt;/p&gt;

&lt;p&gt;In addition, you can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>react</category>
      <category>webdev</category>
      <category>shopify</category>
    </item>
    <item>
      <title>Common Ninja Platform News: Storage API | Payment Trials | Webhooks Management</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Tue, 14 Jun 2022 07:15:07 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninja-platform-news-storage-api-payment-trials-webhooks-management-4ob1</link>
      <guid>https://dev.to/commonninja/common-ninja-platform-news-storage-api-payment-trials-webhooks-management-4ob1</guid>
      <description>&lt;p&gt;We are very excited to share with you recent news and updates related to our &lt;a href="https://www.commoninja.com"&gt;developer platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This month we announce the new Storage API, a full support in payment trials, and a brand new webhooks management tool.&lt;/p&gt;

&lt;p&gt;Just to remind you, the Common Ninja Developer Platform allows you to &lt;strong&gt;build&lt;/strong&gt; &amp;amp; &lt;strong&gt;monetize&lt;/strong&gt; apps for e-commerce platforms very easily. With our universal e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;




&lt;p&gt;🎉 What’s New:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage API&lt;/li&gt;
&lt;li&gt;Payment trials support&lt;/li&gt;
&lt;li&gt;Webhooks management tool&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Storage API
&lt;/h2&gt;

&lt;p&gt;Earlier this month we announced the new Storage API and platform integrations - an easy way for adding storage capabilities to any e-commerce app.&lt;/p&gt;

&lt;p&gt;The new API is simple and you can decide whether you want Common Ninja to manage your storage, or to integrate it with your own AWS S3 bucket.&lt;/p&gt;

&lt;p&gt;We wrote a detailed article about the motivation behind it as well as how to start using it. See below:&lt;br&gt;
&lt;a href="https://dev.to/commonninja/announcing-common-ninja-storage-a-simple-api-for-adding-storage-capabilities-to-e-commerce-apps-2dii"&gt;https://dev.to/commonninja/announcing-common-ninja-storage-a-simple-api-for-adding-storage-capabilities-to-e-commerce-apps-2dii&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v6RJbTJM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b1pn80kuuu3yxgheneb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v6RJbTJM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b1pn80kuuu3yxgheneb9.png" alt="Trial setting" width="740" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment Trials
&lt;/h2&gt;

&lt;p&gt;Last month we introduced the new payments capabilities that will allow you to seamlessly monetize your app by connecting it to popular payments platforms like Stripe, PayPal, Paddle, BlueSnap, and Shopify app payments solution.&lt;/p&gt;

&lt;p&gt;With Payments you can create payment plans and set the amount and period you want to charge your users. &lt;/p&gt;

&lt;p&gt;A new feature that we added is payment trials that enables you to set time so your users will be able to test your app for free before they start paying.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qYwX7HDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tagldrvy7eqr8ydhnkh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qYwX7HDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tagldrvy7eqr8ydhnkh7.png" alt="Webhooks Management Tool" width="880" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhooks Management Tool
&lt;/h2&gt;

&lt;p&gt;One of the most difficult thing to track and debug when you're developing an app is webhook messages that being sent by 3rd party platform and being received by your server. This is why we developed the new Webhooks Management Tool. With the new tool you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create multiple webhooks&lt;/li&gt;
&lt;li&gt;Resend webhook messages&lt;/li&gt;
&lt;li&gt;View messages' payload, request, status code, and error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new tool is available under the "Webhooks" menu item in the &lt;a href="https://www.commoninja.com/developer/apps"&gt;Common Ninja app's dashboard&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you have any specific requests or ideas, we'll be more than happy to &lt;a href="//mailto:contact@commoninja.com"&gt;hear them&lt;/a&gt; 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;You can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>storage</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Announcing Common Ninja Storage - A Simple API For Adding Storage Capabilities to E-Commerce Apps</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 06 Jun 2022 12:18:19 +0000</pubDate>
      <link>https://dev.to/commonninja/announcing-common-ninja-storage-a-simple-api-for-adding-storage-capabilities-to-e-commerce-apps-2dii</link>
      <guid>https://dev.to/commonninja/announcing-common-ninja-storage-a-simple-api-for-adding-storage-capabilities-to-e-commerce-apps-2dii</guid>
      <description>&lt;p&gt;We’ve recently built a &lt;a href="https://apps.shopify.com/common-ninja-info-labels-1"&gt;new app&lt;/a&gt; for Shopify and other e-commerce platforms. The app allows merchants to add info labels to a product image. This is a very common use case, as merchants frequently create multiple variations of a product image to highlight some of the product's features.&lt;/p&gt;

&lt;p&gt;One of the app’s features is the ability to create an image with the info labels editor we’ve built, and then to save it for future use. To make this possible, we needed to integrate with a storage solution such as &lt;a href="https://aws.amazon.com/s3/"&gt;AWS S3&lt;/a&gt;, &lt;a href="https://cloud.google.com/storage"&gt;Google Cloud Storage&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/services/storage/blobs/"&gt;Azure Blob Storage&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;For some reason, adding this capability and understanding what the best way to save files on a cloud storage was, as well as coding the feature end-to-end in both client and server sides — wasn't an easy task at all (although this is something I've handled dozens of times).&lt;/p&gt;

&lt;p&gt;Our stack includes &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;Node&lt;/strong&gt; and &lt;strong&gt;AWS S3&lt;/strong&gt;. Having said that, here are some of the problems we encountered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to send an image from a ReactJS app to a server?&lt;/li&gt;
&lt;li&gt;How to accept an image file in NodeJS?&lt;/li&gt;
&lt;li&gt;How to save an image to AWS S3?&lt;/li&gt;
&lt;li&gt;How to get the uploaded image URL?&lt;/li&gt;
&lt;li&gt;How to create and manage folders for each user?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These seem like trivial questions, but answering each one of them and understanding how they all &lt;strong&gt;play together&lt;/strong&gt; is something that can take a long time.&lt;/p&gt;

&lt;p&gt;I believe that the main issue here is that there are multiple ways to upload images from client to server — base64, urls, form-data, blobs. So many terms when the only thing you want, as the app's developer, is to allow your users to upload images and files.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ What is Common Ninja?
&lt;/h2&gt;

&lt;p&gt;Common Ninja is a platform that allows developers to build &amp;amp; monetize apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;

&lt;p&gt;In addition, Common Ninja offers a set of APIs and tools that help developers to boost up the development process, and provide payments and storage solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  📣 Announcing Common Ninja Storage
&lt;/h2&gt;

&lt;p&gt;Common Ninja's Storage solution is a new and easy way for adding storage capabilities to any e-commerce app.&lt;/p&gt;

&lt;p&gt;Our API is simple and you can decide whether you want Common Ninja to manage your storage, or to integrate it with your own AWS S3 bucket.&lt;/p&gt;

&lt;p&gt;You can read more about the API in our &lt;a href="https://docs.commoninja.com/apis/storage"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 Code Example
&lt;/h2&gt;

&lt;p&gt;We'll publish a much more technical article soon, but meanwhile, just to taste how easy it is, here's a quick code example from our &lt;a href="https://apps.shopify.com/common-ninja-info-labels-1"&gt;Info Labels app&lt;/a&gt; (developed with React &amp;amp; NodeJS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;FileUpload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectedFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedFile&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changeHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;setSelectedFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectedFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/storage/files&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File url: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Could not upload image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changeHandler&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadImage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Upload&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in our NodeJS server we use Common Ninja's API to upload the file and return its url:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CommonNinja&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@commonninja/node-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing Common Ninja app ID or secret key.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CommonNinja&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CommonNinja&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;envs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/storage/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Zero effort and your users can upload images, videos, documents, and any other file you want your app to support.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;If you're not familiar with Common Ninja or how to build your first app using our API, &lt;a href="https://dev.to/commonninja/kick-off-your-first-shopify-app-with-react-nodejs-and-common-ninja-3821"&gt;here's&lt;/a&gt; the previous article we wrote about it.&lt;/p&gt;

&lt;p&gt;In addition, you can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com/"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ecommerce</category>
      <category>node</category>
      <category>storage</category>
    </item>
    <item>
      <title>May 2022: What's New in Common Ninja Integrations</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 23 May 2022 12:27:25 +0000</pubDate>
      <link>https://dev.to/commonninja/may-2022-whats-new-in-common-ninja-integrations-4f4b</link>
      <guid>https://dev.to/commonninja/may-2022-whats-new-in-common-ninja-integrations-4f4b</guid>
      <description>&lt;h2&gt;
  
  
  ❓ What is Common Ninja?
&lt;/h2&gt;

&lt;p&gt;Common Ninja is a platform that allows developers to build &amp;amp; monetize apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like Shopify, BigCommerce, Wix, WooCommerce, and more. There's no need to rebuild the app and make it work on every platform individually. &lt;/p&gt;

&lt;p&gt;In addition, Common Ninja offers an easy way to monetize your app by creating payment plans, and connecting them to the most popular payments platforms such as PayPal, Stripe, Paddle, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  📣 What's new in Common Ninja integrations?
&lt;/h2&gt;

&lt;p&gt;We're constantly working on improving  the platform and adding support for more integrations, each of which can help solve issues in different areas of the e-commerce app development process.&lt;/p&gt;

&lt;h3&gt;
  
  
  E-Commerce
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l8IggGux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y86xcpy1ven77kgylp5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l8IggGux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y86xcpy1ven77kgylp5k.png" alt="E-Commerce integrations" width="880" height="585"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We started with e-commerce platform integrations and we currently support the following platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/shopify"&gt;Shopify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/bigcommerce"&gt;BigCommerce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/woocommerce"&gt;WooCommerce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/wix"&gt;Wix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/ecwid"&gt;Ecwid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/shift4shop"&gt;Shift4Shop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/bigcartel"&gt;BigCartel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The meaning of these integrations is that Common Ninja provides an API for authenticating, marking API calls for consuming resources (such as products, customers, orders, etc.), and handling webhooks - all from a &lt;strong&gt;single interface&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Payments
&lt;/h3&gt;

&lt;p&gt;Earlier this month we announced our &lt;a href="https://dev.to/commonninja/common-ninja-platform-news-payments-new-e-commerce-apis-4n8p"&gt;payment solutions&lt;/a&gt;. This solution is a game changer for developers as it simplifies the way you can monetize your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q7jPPljr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p91mqnxnlebp8szhvn4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q7jPPljr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p91mqnxnlebp8szhvn4i.png" alt="Common Ninja's payments solution" width="880" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a simple interface you can define the available features that your app has to offer, and then create plans for different tiers and users. For each plan you can set multiple prices (i.e monthly or annually), and then to access everything through an API and get the checkout URL for each plan.&lt;/p&gt;

&lt;p&gt;And the best part is that you can connect multiple payment platforms (!).&lt;/p&gt;

&lt;p&gt;The payment platforms we currently support are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/payment-platforms/stripe"&gt;Stripe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.commoninja.com/integrations/payment-platforms/paypal"&gt;PayPal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.commoninja.com/integrations/ecommerce-platforms/shopify"&gt;Shopify&lt;/a&gt; *&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*Shopify has a payment solution for app developers.&lt;/p&gt;

&lt;p&gt;You can learn more about how it works &lt;a href="https://docs.commoninja.com/getting-started/payments"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What's next?
&lt;/h2&gt;

&lt;p&gt;Our roadmap is full and we're working hard (and fast) to add more integrations that will solve different problems and accommodate different needs.&lt;/p&gt;

&lt;p&gt;We plan to add support to more e-commerce and payment platforms, as well as storage and email marketing solutions - everything that is required for building the best e-commerce app for your customers, as fast as possible.&lt;/p&gt;

&lt;p&gt;If you have any specific requests or ideas, we'll be more than happy to &lt;a href="//mailto:contact@commoninja.com"&gt;hear them&lt;/a&gt; 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Learn more
&lt;/h2&gt;

&lt;p&gt;You can use the following resources to learn more and get help:&lt;/p&gt;

&lt;p&gt;📜 &lt;a href="https://docs.commoninja.com"&gt;Common Ninja Docs&lt;/a&gt;&lt;br&gt;
💬 &lt;a href="https://discord.com/invite/cxqUTbvMNd"&gt;Discord Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>integrations</category>
      <category>webdev</category>
      <category>ecommerce</category>
      <category>platforms</category>
    </item>
    <item>
      <title>Kick-Off Your First Shopify App With React, NodeJS and Common Ninja</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 16 May 2022 12:23:50 +0000</pubDate>
      <link>https://dev.to/commonninja/kick-off-your-first-shopify-app-with-react-nodejs-and-common-ninja-3821</link>
      <guid>https://dev.to/commonninja/kick-off-your-first-shopify-app-with-react-nodejs-and-common-ninja-3821</guid>
      <description>&lt;p&gt;Let's start at the end. There are tons of tutorials and resources out there on how to build apps for Shopify, so what's so special about this one?&lt;/p&gt;

&lt;p&gt;Well, I'm glad you asked! 😉&lt;/p&gt;

&lt;p&gt;If you had any previous experience with building Shopify apps, you probably wasted endless time on reading their documentation, trying to understand the authentication flow, connecting to webhooks, testing different ways to charge money for your app — basically - trying to connect everything together.&lt;/p&gt;

&lt;p&gt;The thing is, once you’ve finished building your app (and presuming that you’ve survived the above process) it will only be available to Shopify merchants. But what about other e-commerce platforms like WooCommerce, Wix, BigCommerce, etc.? Your app is probably suitable for them as well. But in order to make it work on those platforms, you'll need to rewrite your app from scratch and, in some cases, you'll need to add more capabilities that aren’t supported by these platforms, like &lt;strong&gt;monetization&lt;/strong&gt; and &lt;strong&gt;payments&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can read more about &lt;a href="https://dev.to/commonninja/the-problems-with-building-apps-for-e-commerce-platforms-and-why-we-built-common-ninja-40f6"&gt;The Problems With Building Apps for E-Commerce Platforms&lt;/a&gt; in a previous post we wrote.&lt;/p&gt;

&lt;p&gt;At Common Ninja we solve these problems by providing developers with a single interface for E-Commerce and payments platforms, allowing you to focus solely on building the business logic of your app, rather than spending too much time on integrating it with multiple platforms.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk you through the process of building your first Shopify app with Common Ninja, NodeJS, and React. And the best part? Once your app is ready, you can use the same code to monetize it on other e-commerce platforms that we support! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Before we start, there are a few things you need to set, so make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A developer account on &lt;a href="https://www.commoninja.com/developers/" rel="noopener noreferrer"&gt;Common Ninja&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A partner account on &lt;a href="https://partners.shopify.com/" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An integration between Shopify and Common Ninja. See a tutorial &lt;a href="https://docs.commoninja.com/integrations/e-commerce-platforms/shopify" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technical requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.dev/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yarnpkg.com/" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; (or any other code editor)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;If you have all of the above installed you can start running the following code to create a comfortable environment and start working on your app with a simple integration to Common Ninja:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @commonninja/create-nindo-app project-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll be asked to select a template. For the purpose of this quick start tutorial, choose the Server template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgg0ciwabn4fm49jv7dwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgg0ciwabn4fm49jv7dwf.png" alt="Nindo CLI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project will automatically install all of its dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Open the generate project in VSCode - or any other code editor you're using, and edit its .env file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Env&lt;/span&gt;
&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4000

&lt;span class="c"&gt;# Common Ninja App&lt;/span&gt;
&lt;span class="nv"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the &lt;code&gt;COMMONNINJA_APP_ID&lt;/code&gt; and the &lt;code&gt;COMMONNINJA_APP_SECRET&lt;/code&gt; based on your Common Ninja app (if you haven't created an app yet, &lt;a href="https://www.commoninja.com/developer/apps" rel="noopener noreferrer"&gt;now is the time&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgy8qjfd8q5u15p1ildy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgy8qjfd8q5u15p1ildy.png" alt="App Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, start the development server by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure that the server is up and navigate to &lt;code&gt;localhost:4000&lt;/code&gt;. You should see a &lt;code&gt;Hey there!&lt;/code&gt; message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;This is a very simple and basic NodeJS project with Docker. It is already set up with TypeScript and an automatic watch on files for server restart. Under the &lt;code&gt;src&lt;/code&gt; folder there are two files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;src
    app.ts
    routes.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  app.ts
&lt;/h4&gt;

&lt;p&gt;A very common NodeJS app entry file. Here we set up the initial Express server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cookieParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cookie-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Parse cookies&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cookieParser&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Parse application/x-www-form-urlencoded&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Parse application/json&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;50mb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Start server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing special here.&lt;/p&gt;

&lt;h4&gt;
  
  
  routes.ts
&lt;/h4&gt;

&lt;p&gt;This is an example of how to use Common Ninja's &lt;a href="https://github.com/CommonNinja/node-sdk" rel="noopener noreferrer"&gt;Node SDK library&lt;/a&gt;. Each one of the routes is initializing the CommonNinja class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing Common Ninja app ID or secret key.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a new Common Ninja instance&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommonNinja&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;COMMONNINJA_APP_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CommonNinja&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;envs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;routes.ts&lt;/code&gt; file we define 3 routes, each one interacts with different parts of Common Ninja's API.&lt;/p&gt;

&lt;h3&gt;
  
  
  /connect
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/connect&lt;/code&gt; route is responsible for redirecting your user to an authentication flow with the platforms your app supports. So if you've added the Shopify and WooCommerce integrations to your Common Ninja app - by browsing to &lt;strong&gt;&lt;a href="http://localhost:4000" rel="noopener noreferrer"&gt;http://localhost:4000&lt;/a&gt;&lt;/strong&gt; you'll see these platforms' logos. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygybhq4kvtms16jlpe9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygybhq4kvtms16jlpe9v.png" alt="Common Ninja connect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By clicking on one of them you'll be redirected to the platform's authentication page. Once the authentication flow is done, Common Ninja will redirect the user to the &lt;strong&gt;Redirect URL&lt;/strong&gt; you defined in the relevant section of your app's dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9wlwxvzxpne2fucx1v2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9wlwxvzxpne2fucx1v2.png" alt="Redirect URL setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code that handles this route is using the SDK's &lt;code&gt;getConnectUrl&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Authentication&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get a new Common Ninja instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Get authentication url for platform&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getConnectUrl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Redirect to authentication url&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /api
&lt;/h3&gt;

&lt;p&gt;This route is in fact a proxy to Common Ninja's API. The SDK has a built-in proxy method that handles the incoming requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// API Proxy&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextFunction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get a new Common Ninja instance&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Proxy api requests to Common Ninja API&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apiProxyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 4th parameter in the &lt;code&gt;apiProxyMiddleware&lt;/code&gt; method is the route in your app that will be rewritten. &lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;code&gt;/api/ecommerce/products&lt;/code&gt; will be proxied to  &lt;code&gt;https://api.commonninja.com/integrations/api/v1/ecommerce/products&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please note&lt;/strong&gt;: You don't have to use the API that way, instead you can support selected APIs by using the different methods the SDK supports. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ecommerce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /webhooks
&lt;/h3&gt;

&lt;p&gt;Lastly, the &lt;code&gt;/webhooks&lt;/code&gt; route will accept webhook messages from Common Ninja's supported platforms. You may read more about Webhooks &lt;a href="https://docs.commoninja.com/getting-started/webhooks" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Webhook messages should be validated, and our SDK will take care of that for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Validate and handle Common Ninja's webhooks&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCommonNinjaClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Validate webhook message source&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webhooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cannot validate signature.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Webhook message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Send a 200 OK response back to Common Ninja&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Cannot handle webhook message`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to test the webhooks, you'll need to work with https protocol locally. The way we handle it is by using tunnels.&lt;br&gt;
This project has another docker compose file for this purpose. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.https.yml up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll get a secured URL that you can use to test the webhooks integration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bn9pdktx2qoqgllceyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bn9pdktx2qoqgllceyd.png" alt="HTTPS with Localtunnel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have the URL, simply add a new webhook URL to your Common Ninja app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjal5g0dxzijb3gemd6a7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjal5g0dxzijb3gemd6a7.png" alt="Setting up webhook URLs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Client
&lt;/h2&gt;

&lt;p&gt;Now that we have the server ready, let's create a simple react app using React CRA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app client-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the generated project, look for the &lt;code&gt;package.json&lt;/code&gt; file, and add a &lt;code&gt;proxy&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proxy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts eject"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React will proxy requests to the server we created.&lt;/p&gt;

&lt;p&gt;Next, let's start the project with &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just for the sake of the simplicity, we'll see how easy it is to access Common Ninja APIs through the app, without adding a single line of code to the server.&lt;/p&gt;

&lt;p&gt;Let's edit the &lt;code&gt;App.jsx&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/ecommerce/products?token=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Products&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// eslint-disable-next-line&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;renderProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:4000/connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;Connect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;54 lines of code&lt;/strong&gt; (even less) is all it takes to get a products list from Shopify API (or any other e-commerce platform), using Common Ninja.&lt;/p&gt;

&lt;p&gt;In the first 3 lines of the function we set an initial state for the &lt;code&gt;token&lt;/code&gt; and &lt;code&gt;products&lt;/code&gt; list. In case the user has already gone through the authentication process, the url of the page will include a unique token, generated by Common Ninja that allows him to access his store's resources.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;useEffect&lt;/code&gt; hook, we make sure there's a token in the url. If there is, we're making an API call to our server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getProducts&lt;/code&gt; function is using the &lt;code&gt;fetch&lt;/code&gt; API to make a simple request to our server with the generated token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/ecommerce/products?token=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The render function is also pretty straight forward. If there's a token in the URL, we show a list of products, else, we render a &lt;code&gt;connect&lt;/code&gt; button that leads to the &lt;code&gt;/connect&lt;/code&gt; route we mentioned before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;renderProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:4000/connect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;Connect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;renderProduct&lt;/code&gt; function simply iterates on the products list that the API returns, as described in the &lt;a href="https://docs.commoninja.com/apis/e-commerce/products/get-products" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Products&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And vualah! Here's the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugwaixzhkfukn6d17dry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugwaixzhkfukn6d17dry.png" alt="Products API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article, we've learned how to create a Shopify app using React, NodeJS, and Common Ninja.&lt;/p&gt;

&lt;p&gt;We saw how easy and simple it is to connect your app to Shopify, without being worried about authentication, APIs, and other complexities.&lt;/p&gt;

&lt;p&gt;This is an example of a very simple app, but Common Ninja supports much complex use cases. &lt;/p&gt;

&lt;p&gt;You can learn more about our e-commerce and payments APIs in our &lt;a href="https://docs.commoninja.com" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, and as always, we'll be more than happy to help you to get your app up and running so if you have any questions feel free to reach out!&lt;/p&gt;

&lt;p&gt;Meanwhile, join our growing &lt;a href="https://discord.com/invite/cxqUTbvMNd" rel="noopener noreferrer"&gt;Discord community&lt;/a&gt;! 🔥&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>shopify</category>
      <category>react</category>
      <category>node</category>
    </item>
    <item>
      <title>Common Ninja Platform News: Payments | New E-Commerce APIs</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Thu, 12 May 2022 08:41:01 +0000</pubDate>
      <link>https://dev.to/commonninja/common-ninja-platform-news-payments-new-e-commerce-apis-4n8p</link>
      <guid>https://dev.to/commonninja/common-ninja-platform-news-payments-new-e-commerce-apis-4n8p</guid>
      <description>&lt;p&gt;We are very excited to share with you recent news and updates related to our developer platform. We are planning on posting these updates once a month, so stay tuned!&lt;/p&gt;

&lt;p&gt;Just to remind you, the &lt;a href="https://www.commoninja.com/developers"&gt;Common Ninja Developer Platform&lt;/a&gt; allows you to &lt;strong&gt;build &amp;amp; monetize&lt;/strong&gt; apps for e-commerce platforms very easily. With our single e-commerce API you can build your app once, and integrate it with multiple platforms like &lt;strong&gt;Shopify&lt;/strong&gt;, &lt;strong&gt;BigCommerce&lt;/strong&gt;, &lt;strong&gt;Wix&lt;/strong&gt;, &lt;strong&gt;WooCommerce&lt;/strong&gt;, and more. There's no need to rebuild the app and make it work on every platform individually.&lt;/p&gt;




&lt;p&gt;🎉 What’s New:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payments&lt;/li&gt;
&lt;li&gt;API updates

&lt;ul&gt;
&lt;li&gt;Products&lt;/li&gt;
&lt;li&gt;Orders&lt;/li&gt;
&lt;li&gt;Customers&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V2thQQ1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n91b72c7jd6yci5h3ygs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V2thQQ1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n91b72c7jd6yci5h3ygs.png" alt="Payments in Common Ninja" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Payments
&lt;/h2&gt;

&lt;p&gt;We are proud to present the brand new &lt;strong&gt;payments capabilities&lt;/strong&gt; — that includes a simple interface that allows you to create payment plans for your app, connect them to popular payment providers like Stripe, PayPal, and Shopify app payment APIs, and dynamically create checkout URLs for your app’s users 🚀&lt;/p&gt;

&lt;p&gt;Learn more about how it works in the &lt;a href="https://docs.commoninja.com/"&gt;docs&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  API Updates
&lt;/h2&gt;

&lt;p&gt;We’ve added 3 new e-commerce APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Products&lt;/strong&gt; - a new set of API endpoints for managing the store’s products resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orders&lt;/strong&gt; - with the new orders API you can create, update, and see store’s orders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customers&lt;/strong&gt; - a simple API to consume a list of store’s customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may learn more about all of the supported APIs &lt;a href="https://docs.commoninja.com/apis/e-commerce"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;More exciting updates will be released soon so stay tuned!&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>develop</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Problems With Building Apps for E-Commerce Platforms and Why We Built Common Ninja</title>
      <dc:creator>Daniel Sternlicht</dc:creator>
      <pubDate>Mon, 02 May 2022 09:31:41 +0000</pubDate>
      <link>https://dev.to/commonninja/the-problems-with-building-apps-for-e-commerce-platforms-and-why-we-built-common-ninja-40f6</link>
      <guid>https://dev.to/commonninja/the-problems-with-building-apps-for-e-commerce-platforms-and-why-we-built-common-ninja-40f6</guid>
      <description>&lt;p&gt;Let's start with the bottom line:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Building apps for e-commerce platforms is hard.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;E-Commerce platforms (such as Shopify, BigCommerce, Wix, WooCommerce, etc.) are great for people who want to build and manage shops online. They provide the best tools for shop owners to manage inventory, customize their storefront, and start making revenues from online orders.&lt;/p&gt;

&lt;p&gt;But at the end, &lt;strong&gt;these platforms are limited&lt;/strong&gt;, and this is why they allow developers to leverage their APIs and data to develop apps on top them.&lt;/p&gt;

&lt;p&gt;These apps are being used by merchants and their customers and they are quite varied. From storefront widgets that increase conversions and enhance the user experience, to apps that collects data to improve inventory management, to social proof apps, and easy drop shipping. &lt;/p&gt;

&lt;p&gt;E-Commerce apps are widely used by online merchants, and become very popular. How popular? Shopify &lt;a href="https://techcrunch.com/2021/06/29/shopify-drops-its-app-store-commissions-to-0-on-developers-first-million-in-revenue/"&gt;says&lt;/a&gt; that in 2020 the average merchant installed 6 apps on his store, and that developer partners earned $233M in 2020 alone. &lt;/p&gt;

&lt;p&gt;The thing is... &lt;/p&gt;

&lt;p&gt;If you ask any developer who had an experience with building apps for e-commerce platforms "How was your experience?" you'll get the same answer: "&lt;strong&gt;It was a hell of a nightmare&lt;/strong&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problems With E-Commerce Platforms For Developers
&lt;/h2&gt;

&lt;p&gt;When you first start building an app you're entering a world of pain.&lt;/p&gt;

&lt;p&gt;It starts with the documentation. In order to build an app you'll need to read. A lot. And while some platforms did a nice job with onboarding developers to their platform and documenting everything, others don't.&lt;/p&gt;

&lt;p&gt;Once you find your way in the endless docs, and understand the different types of apps each platform allows you to build, the next thing will be to handle authentication. &lt;/p&gt;

&lt;p&gt;Surprisingly, although most of the platforms are using &lt;strong&gt;OAuth&lt;/strong&gt;, each one of them implemented the authentication flow differently so you'll need to learn exactly how it works on each platform separately while using tunnels (and in some cases to debug the code in production because you have to contact the platforms in order to change the auth endpoints). &lt;/p&gt;

&lt;p&gt;I hope you're still here because there's more!&lt;/p&gt;

&lt;p&gt;The next thing would be APIs. Let's take the &lt;code&gt;Product&lt;/code&gt; resource as an example.&lt;/p&gt;

&lt;p&gt;In Shopify a product object looks like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IShopifyProduct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;body_html&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;product_type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// no unit supported in api&lt;/span&gt;
    &lt;span class="nl"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;weight_unit&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}[]&lt;/span&gt;
  &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IShopifyProductImage&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;archived&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IShopifyProductImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;weight_unit&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;variant_ids&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;admin_graphql_api_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in BigCommerce like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IBigCommerceProduct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;date_created&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;date_modified&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;custom_url&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;physical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;digital&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;primary_image&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IBigCommerceProductImage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;images&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IBigCommerceProductImage&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IBigCommerceProductImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;image_file&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;is_thumbnail&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sort_order&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;date_modified&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;url_standard&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;url_thumbnail&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;url_tiny&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While in Wix it's:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IWixProduct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;productType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;physical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;priceData&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;media&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IWixProductMedia&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;lastUpdated&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no standardization, each platform sees things differently which is ok, &lt;strong&gt;unless you want to build an app that supports multiple platforms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And finally - &lt;strong&gt;monetization&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If you're building an app, either for yourself or for a company you're working for, your end goal is obviously to see revenues out of it. However, while some platforms like Shopify and Wix are giving you some tools to monetize your app in different business models, &lt;strong&gt;all of the other platforms don't&lt;/strong&gt;. Which means, that in addition to everything else you'll need to integrate payment solutions as well, and develop these integrations yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Ninja: A New Era Of E-Commerce Apps Development
&lt;/h2&gt;

&lt;p&gt;We know these problems very closely, since in the past 10 years we developed dozen of apps for website building and e-commerce platforms. &lt;/p&gt;

&lt;p&gt;During these years we developed a lot of tools that helped us to decrease the development time of e-commerce platforms apps in 80%, which led us to establish Common Ninja and offer these tools to any developer out there 🎉&lt;/p&gt;

&lt;p&gt;Common Ninja is a platform for building &amp;amp; monetizing e-commerce apps.&lt;/p&gt;

&lt;p&gt;Our main offering is "&lt;strong&gt;One API to rule them all&lt;/strong&gt;". &lt;/p&gt;

&lt;p&gt;You'll work with a single API for consuming e-commerce resources such as products, orders, customers, etc. regardless the platform your user/merchant is using. You always know what you get, and if an e-commerce platform is changing their API, we take care of it behind the scenes so you won't have to.&lt;/p&gt;

&lt;p&gt;In addition, with Common Ninja you'll be able to monetize your app flawlessly, create subscriptions based plans, and connect your app to popular payment providers like Stripe and PayPal.&lt;/p&gt;

&lt;p&gt;Too good to be true? Probably. But this is us, and that's what we do 🙂&lt;/p&gt;

&lt;p&gt;Want to learn more? go here:&lt;br&gt;
&lt;a href="https://www.commoninja.com/developers"&gt;https://www.commoninja.com/developers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any feedback, question or comment, we're here.&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>shopify</category>
      <category>webdev</category>
      <category>integration</category>
    </item>
  </channel>
</rss>
