![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@shopify/shopify-api
Advanced tools
Shopify TypeScript API to support core API functionality (auth, graphql proxy, webhooks)
@shopify/shopify-api is an official Node.js library provided by Shopify to interact with the Shopify API. It allows developers to build applications that can integrate with Shopify stores, manage store data, and perform various operations related to e-commerce.
Authentication
This feature allows you to authenticate your application with Shopify using API keys and scopes. The code sample demonstrates how to set up the Shopify object with necessary credentials and scopes.
const { Shopify } = require('@shopify/shopify-api');
const shopify = new Shopify({
apiKey: 'your-api-key',
apiSecretKey: 'your-api-secret',
scopes: ['read_products', 'write_products'],
hostName: 'your-app-hostname',
apiVersion: '2023-01'
});
// Use the shopify object to authenticate requests
REST API Client
This feature provides a REST API client to interact with Shopify's REST API. The code sample shows how to create a REST client and fetch a list of products from a Shopify store.
const { Shopify } = require('@shopify/shopify-api');
const client = new Shopify.Clients.Rest('your-shop-name.myshopify.com', 'your-access-token');
async function getProducts() {
const products = await client.get({
path: 'products'
});
console.log(products.body);
}
getProducts();
GraphQL API Client
This feature provides a GraphQL API client to interact with Shopify's GraphQL API. The code sample demonstrates how to create a GraphQL client and query shop details.
const { Shopify } = require('@shopify/shopify-api');
const client = new Shopify.Clients.Graphql('your-shop-name.myshopify.com', 'your-access-token');
async function getShopDetails() {
const query = `{
shop {
name
primaryDomain {
url
host
}
}
}`;
const response = await client.query({
data: query
});
console.log(response.body.data.shop);
}
getShopDetails();
Webhook Management
This feature allows you to manage webhooks for your Shopify app. The code sample shows how to register a webhook handler for the 'PRODUCTS_CREATE' event.
const { Shopify } = require('@shopify/shopify-api');
const webhook = new Shopify.Webhooks.Registry();
webhook.addHandler('PRODUCTS_CREATE', {
path: '/webhooks/products/create',
webhookHandler: async (topic, shop, body) => {
console.log(`Received webhook: ${topic} for shop: ${shop}`);
}
});
shopify-api-node is a popular Node.js library for interacting with the Shopify API. It provides a simple and flexible interface for making requests to Shopify's REST and GraphQL APIs. Compared to @shopify/shopify-api, it is community-maintained and may not have the same level of official support or updates.
shopify-node-api is another Node.js library for accessing the Shopify API. It offers features for authentication, REST API requests, and webhook handling. While it provides similar functionalities to @shopify/shopify-api, it is less frequently updated and may lack some of the latest features provided by Shopify's official library.
@shopify/shopify-api
TypeScript API supporting authentication, graphql and REST client, and registration/receipt of webhooks for Shopify applications.
Requirements
To follow these usage guides, you will need to:
ngrok
url and the appropriate redirect for your OAuth callback route to your app settingsEnvironment
You'll need your application to load the API secret and API secret key (found when you create an app in your Partner Account). The mechanism is entirely up to you. For example, you could use a library like dotenv
to read them from a .env
file, or set environment variables with the values. However you do it, be sure to NOT save the API secret and key in GitHub or other code repository where others can view them.
For this guide, basic understanding of the Express app framework is required.
Install dependencies
package.json
and install the following necessary dependencies:
@shopify/shopify-api
- this libraryexpress
- the Express frameworkdotenv
- tool to read from .env
filestypescript
- TypeScript language@types/express
- Express types$ yarn init -y
$ yarn add @shopify/shopify-api express
$ yarn add --dev dotenv typescript @types/express
Setup environment
Begin by placing the following in an .env
file at the root of your project:
ngrok
tunnel to provide a secure connection to our localhost)SHOP={dev store url}
API_KEY={api key}
API_SECRET_KEY={api secret key}
SCOPES={scopes}
HOST={your app's host, we used ngrok}
Setup base files
tsconfig.json
in the root of your project:
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*"
]
}
},
"include": [
"src/**/*"
]
}
scripts
to your package.json
:
"scripts": {
"build": "npx tsc",
"prestart": "yarn run build",
"start": "node dist/index.js"
},
src/index.ts
Add imports, environment variables, and setup Context
// src/index.ts
import express from 'express';
import Shopify, { ApiVersion, AuthQuery } from '@shopify/shopify-api';
require('dotenv').config()
const app = express()
const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST } = process.env
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST,
IS_EMBEDDED_APP: {boolean},
API_VERSION: ApiVersion.{version} // all supported versions are available, as well as "unstable" and "unversioned"
})
// the rest of the example code goes here
app.listen(3000, () => {
console.log('your app is now listening on port 3000')
})
Add a route to start OAuth
beginAuth
function takes in the request
and response
objects, along with the target shop (string), redirect route (string), and whether or not you are requesting "online access" (boolean)async
in order to await
the return value, since beginAuth
returns a Promise
app.get('/oauth/begin', async (req, res) => {
let authRoute = await Shopify.Auth.OAuth.beginAuth(req, res, SHOP, '/auth/callback', true)
return res.redirect(authRoute)
})
Add your OAuth callback route
validateAuthCallback
methodrequest
and response
object, as well as the req.query
objectcatch
any errors it may throwPromise
so you should use async/await
here as well
app.get('/auth/callback', async (req, res) => {
try {
await Shopify.Auth.OAuth.validateAuthCallback(req, res, req.query as unknown as AuthQuery); // req.query must be cast to unkown and then AuthQuery in order to be accepted
} catch (error) {
console.error(error); // in practice these should be handled more gracefully
}
return res.redirect('/'); // wherever you want your user to end up after OAuth completes
})
Make a REST API call
RestClient
to make an API callRestClient
using the current shop URL and session accessToken
client.get
to request some products
app.get('/shopify/rest-call', async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(req, res) // load the current session to get the `accessToken`
const client = new Shopify.Clients.Rest.RestClient(session.shop, session.accessToken) // create a new client for the specified shop
const products = await client.get({ // use client.get to request the REST endpoint you need, in this case "products"
path: 'products'
})
res.send(products) // do something with the returned data
})
Make a GraphQL API call
GraphQLClient
to make requests to the GraphQL API in a similar wayGraphQLClient
using the current shop URL and session accessToken
client.query
to make your request, passing your query as data
app.get('/shopify/graphql-call', async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(req, res) // load the current session to get the `accessToken`
const client = new Shopify.Clients.Graphql.GraphqlClient(session.shop, session.accessToken) // GraphQLClient accepts the same arguments as RestClient
const products = await client.query({ // use client.query and pass your query as `data`
data: `{
products (first: 10) {
edges {
node {
id
title
bodyHtml
}
}
}
}`
})
res.send(products) // do something with the returned data
})
Running your app
ngrok
tunnel and add the displayed ngrok
url to the app setup in your admin, along with the redirect route
$ ngrok http 3000
yarn start
and you should have your app running on your specified localhost
{your ngrok address}/oauth/begin
to begin OAuthInstall dependencies
package.json
and install the following necessary dependencies:
@shopify/shopify-api
- this librarydotenv
- tool to read from .env
filestypescript
- TypeScript language@types/node
- Node types$ yarn init -y
$ yarn add @shopify/shopify-api
$ yarn add --dev dotenv typescript @types/node
Setup environment
Begin by placing the following in an .env
file at the root of your project:
ngrok
tunnel to provide a secure connection to our localhost)SHOP={dev store url}
API_KEY={api key}
API_SECRET_KEY={api secret key}
SCOPES={scopes}
HOST={your app's host, we used ngrok}
Setup base files
tsconfig.json
in the root of your project:
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*"
]
}
},
"include": [
"src/**/*"
]
}
scripts
to your package.json
:
"scripts": {
"build": "npx tsc",
"prestart": "yarn run build",
"start": "node dist/index.js"
},
src/index.ts
Add imports, environment variables, and setup Context
// src/index.ts
import http from 'http';
import url from 'url';
import querystring from 'querystring';
import Shopify, { ApiVersion, AuthQuery } from '@shopify/shopify-api';
require('dotenv').config()
const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST } = process.env
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST,
IS_EMBEDDED_APP: {boolean},
API_VERSION: ApiVersion.{version} // all supported versions are available, as well as "unstable" and "unversioned"
});
Create a basic Node router
:
async function onRequest(request: http.IncomingMessage, response: http.ServerResponse): Promise<void> {
const { headers, url: req_url } = request;
const pathName: string | null = url.parse(req_url).pathname;
const queryString: string = (String)(url.parse(req_url).query);
const query: Record<string, any> = querystring.parse(queryString);
if (pathName === '/') {
// check if we're logged in/authorized
const currentSession = await Shopify.Utils.loadCurrentSession(request, response);
if(!currentSession) {
// not logged in, redirect to login
response.writeHead(302, { 'Location': `/login` });
response.end();
} else {
// do something amazing with your application!
}
return;
} // end of if(pathName === '/')
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Add a route to start OAuth
The route for starting the OAuth process (in this case /login
) will use the library's beginAuth
method. The beginAuth
method takes in the request and response objects (from the http
server), along with the target shop (string), redirect route (string), and whether or not you are requesting "online access" (boolean). The method will return a URI that will be used for redirecting the user to the Shopify Authentication screen.
:
} // end of if(pathName === '/')
if (pathName === '/login') {
// process login action
try {
const authRoute = await Shopify.Auth.OAuth.beginAuth(request, response, SHOP, callbackPath);
response.writeHead(302, { 'Location': authRoute });
response.end();
}
catch (e) {
console.log(e);
response.writeHead(500);
if (e instanceof Shopify.Errors.ShopifyError) {
response.end(e.message);
}
else {
response.end(`Failed to complete OAuth process: ${e.message}`);
}
}
return;
} // end of if (pathName === '/login')
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Add your OAuth callback route
After the app is authenticated with Shopify, the Shopify platform will send a request back to your app using this route (which you provided as a parameter to beginAuth
, above). Your app will now use the provided validateAuthCallback
method to finalized the OAuth process.
:
} // end of if (pathName === '/login')
if (pathName === callbackPath) {
try {
await Shopify.Auth.OAuth.validateAuthCallback(request, response, query as AuthQuery);
// all good, redirect to '/'
response.writeHead(302, { 'Location': '/' });
response.end();
}
catch (e) {
console.log(e);
response.writeHead(500);
if (e instanceof Shopify.Errors.ShopifyError) {
response.end(e.message);
}
else {
response.end(`Failed to complete OAuth process: ${e.message}`);
}
}
return;
} // end of if (pathName === 'callbackPath')
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Register a Webhook
If your application's functionality depends on knowing when events occur on a given store, you need to register a Webhook! You should register your webhooks after the OAuth process completes.
:
} // end of if (pathName === '/login')
if (pathName === callbackPath) {
try {
await Shopify.Auth.OAuth.validateAuthCallback(request, response, query as AuthQuery);
// all good, register any required webhooks
const handleWebhookRequest = (topic: string, shop_domain: string, webhookRequestBody: Buffer) => {
// this handler is triggered when a webhook is sent by the Shopify platform to your application
}
const currentSession = await Shopify.Utils.loadCurrentSession(request, response, false);
const resp = await Shopify.Webhooks.Registry.register({
path: '/webhooks',
topic: 'PRODUCTS_CREATE',
accessToken: currentSession.accessToken,
shop: currentSession.shop,
apiVersion: Context.API_VERSION,
webhookHandler: handleWebhookRequest
});
response.writeHead(302, { 'Location': '/' });
response.end();
}
catch (e) {
:
Process a Webhook
To process a webhook, you need to listen on the route(s) you provided during the Webhook registration process, then call the appropriate handler. The library provides a convenient process
method which takes care of calling the correct handler for the registered Webhook topics.
:
} // end of if (pathName === 'callbackPath')
if (Shopify.Webhooks.Registry.isWebhookPath(pathName)) {
let data: Buffer[] = [];
request.on('data', function (chunk: Buffer) {
data.push(chunk)
}).on('end', function () {
const buffer: Buffer = Buffer.concat(data);
try {
const result = Shopify.Webhooks.Registry.process({ headers: headers, body: buffer });
response.writeHead(result.statusCode, result.headers);
response.end();
}
catch (e) {
console.log(e);
response.writeHead(500);
if (e instanceof Shopify.Errors.ShopifyError) {
response.end(e.message);
}
else {
response.end(`Failed to complete webhook processing: ${e.message}`);
}
}
});
return;
} // end of if (Shopify.Webhooks.Registry.isWebhookPath(pathName))
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Running your app
ngrok
tunnel and add the displayed ngrok
url to the app setup in your admin, along with the redirect route
$ ngrok http 3000
yarn start
and you should have your app running on your specified localhost
{your ngrok address}/login
to begin OAuthFAQs
Shopify API Library for Node - accelerate development with support for authentication, graphql proxy, webhooks
The npm package @shopify/shopify-api receives a total of 68,403 weekly downloads. As such, @shopify/shopify-api popularity was classified as popular.
We found that @shopify/shopify-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 8 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.