Skip to content

Instantly share code, notes, and snippets.

@debuss
Last active June 5, 2022 19:26
Show Gist options
  • Save debuss/ef2e8738bf6d434854afcfe5f06cb734 to your computer and use it in GitHub Desktop.
Save debuss/ef2e8738bf6d434854afcfe5f06cb734 to your computer and use it in GitHub Desktop.
/**
* CustomSessionStorage implementation with FaunaDb for your Node API Shopify app.
*
* On Fauna Dashboard, in my database, I created a Collection "Sessions" (with a TTL of 2 days, but configure it as you wish).
* I also added an Index "session_by_id" with Terms set as "data.id" and Serialized.
*
* In the constructor, replace my settings with yours to make the connection.
* If you have a different Collection and/or Index, then also update each method to use the correct configuration.
*
* @author Alexandre DEBUSSCHÈRE <alexandre@kosmonaft.dev>
* @see https://github.com/Shopify/shopify-node-api/blob/main/docs/usage/customsessions.md
* @see https://fauna.com/
*/
import faunadb from "faunadb";
import "dotenv/config";
import { Session } from "@shopify/shopify-api/dist/auth/session/index.js";
const q = faunadb.query;
class FaunaDbStore {
constructor() {
this.client = new faunadb.Client({
secret: process.env.FAUNADB_SECRET,
domain: "db.eu.fauna.com",
port: 443,
scheme: "https",
});
}
/**
* @param session
* @returns {Promise<boolean>}
*/
async storeCallback(session) {
try {
await this.client.query(
// Upsert
q.Let(
{
match: q.Match(q.Index("session_by_id"), session.id),
data: { data: session },
},
q.If(
q.Exists(q.Var("match")),
q.Update(q.Select("ref", q.Get(q.Var("match"))), q.Var("data")),
q.Create(q.Collection("Sessions"), q.Var("data"))
)
)
);
return true;
} catch (err) {
throw new Error(err);
}
}
/**
* @param id
* @returns {Promise<undefined|*>}
*/
async loadCallback(id) {
let reply = undefined;
try {
await this.client
.query(q.Get(q.Match(q.Index("session_by_id"), id)))
.then((response) => (reply = response.data));
if (!reply) {
return undefined;
}
return Session.cloneSession(reply, reply.id);
} catch (err) {
throw new Error(err);
}
}
/**
* @param id
* @returns {Promise<boolean>}
*/
async deleteCallback(id) {
try {
await this.client.query(
q.Delete(q.Select("ref", q.Get(q.Match(q.Index("session_by_id"), id))))
);
return true;
} catch (err) {
throw new Error(err);
}
}
}
export default FaunaDbStore;
// server/index.js
// ...
import faunadb from "faunadb";
import FaunaDbStore from "./storage/faunadb-store.js";
const sessionStorage = new FaunaDbStore();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.April22,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE:
process.env.NODE_ENV === "production"
? new Shopify.Session.CustomSessionStorage(
sessionStorage.storeCallback.bind(sessionStorage),
sessionStorage.loadCallback.bind(sessionStorage),
sessionStorage.deleteCallback.bind(sessionStorage)
)
: new Shopify.Session.MemorySessionStorage(),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment