- Languages: Node.js, Typescript
- Tools Used: Stripe
- Time saved: 3 weeks -> 40 mins
- Source code on Github
This is Part 2 in the series of guides on building a Stripe App.
Introduction
Stripe Apps extend a Stripe Business Owner's capabilities by sharing screen real estate with Stripe Dashboard. Here's a look at a Stripe App we will be building.
In this guide, we will build a Stripe app called CRM Buddy that helps business owners leave notes on Customer profiles.
In Part 2, we will build the backend API service for the Stripe App using Node.js and Express. Here are the endpoints:
- /addNote: Add a new note for the customer
- /notes: Get all added notes
- /notes/:customerId: Get all notes for a given customer
Step 1: Create a new Node.js project
Create a new Node.js project with Typescript and Express.js. We've created a detailed post on this here. Follow Step 1 from there and come back.
Step 2: Set up Prisma DB
We will use Postgres as our DB and Prisma will help us interact with it using Node.js.
First, make sure you have a Postgres server running locally. I use Postgres.app. Verify that it is running on localhost:5432 and create a new table crmbuddy
. I use TablePlus as my client.
Install and initialize prisma with:
npm i prisma
npx prisma init
This will create a new folder called prisma
and a .env
Add the local DB url to the .env
:
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/crmbuddy
Now verify that the server does not throw a DB connection error when we start up the development server with:
npm run dev
Step 3: Create a Schema
Our schema is going to be very simple - just a Note with these properties:
- Id - *Unique ID of the note (Auto-generated)
- AgentId - Stripe ID of the user writing the note
- CustomerId - Stripe ID of the customer the note is about
- Message - Actual message on the note
We can create a schema by editing our prisma/schema.prisma
file like so:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Note {
id Int @id @default(autoincrement())
agentId String
customerId String
message String
}
We can now apply the schema by running:
npx prisma db push
Note: This will reset the DB and apply these new changes. In a PROD environment, you probably want to create a migration file. Prisma has support for this here.
Step 4 - Create the Note service
We will need service functions that interact with the DB to create and read data. We will use them in our API functions in the next step.
Let's start by adding a Prisma Client in a file called src/lib/prisma.ts
:
import {
PrismaClient
} from ".prisma/client";
declare global {
var prisma: PrismaClient | undefined;
};
export const prisma = global.prisma || new PrismaClient();
if (process.env.NODE_ENV !== 'production') {
global.prisma = prisma;
}
This will let us not create multiple connections when the development server restarts on new changes.
Create a new file called src/services/index.tsx
:
import { Prisma } from ".prisma/client";
import { prisma } from "../lib/prisma";
export async function createNote(data: Prisma.NoteUncheckedCreateInput) {
const { agentId, customerId, message } = data;
const user = await prisma.note.create({
data: {
agentId,
customerId,
message,
},
});
return user;
}
export async function getAllNotes() {
const allUsers = await prisma.note.findMany();
return allUsers;
}
export async function getNotesByCustomerId(customerId: string) {
const allUsers = await prisma.note.findMany({
where: {
customerId,
},
});
return allUsers;
}
Step 5 - Create the API endpoints
Update your src/app.ts
import { Prisma } from ".prisma/client";
import cors from "cors";
import express from "express";
import helmet from "helmet";
import { createNote, getAllNotes, getNotesByCustomerId } from "./services";
const app = express();
app.use(helmet());
app.use(cors());
cors({
credentials: true,
origin: true,
});
app.use(express.json());
app.post("/note", async (req, res) => {
const { agentId, customerId, message } = req.body;
const newNote: Prisma.NoteUncheckedCreateInput = {
agentId,
customerId,
message,
};
await createNote(newNote);
res.json({
error: false,
data: {},
});
});
app.get("/notes", async (req, res) => {
const notes = await getAllNotes();
res.json({
error: false,
data: {
notes,
},
});
});
app.get("/notes/:customerId", async (req, res) => {
const customerId = req.params.customerId;
const notes = await getNotesByCustomerId(customerId);
res.json({
error: false,
data: {
notes,
},
});
});
export default app;
We can now start our API with:
npm run dev
Step 6: Connect Stripe App with Node.js Backend
Currently, our Stripe App is using mock data as the backend. We can easily replace that and connect it our running Node.js server by updating the src/api/index.ts
in the Stripe App project:
import axios from "axios";
import {
APIResponse
} from "../types";
export async function addNoteAPI({
customerId,
message,
agentId
}: {
customerId: string,
message: string,
agentId: string
}) {
const response = await axios.post("<http://localhost:3000/note>", {
agentId,
customerId,
message
}) return response.data;
}
export async function getAllNotesAPI(): Promise < APIResponse > {
const response = await axios.get("<http://localhost:3000/notes>") return response.data;
}
export async function getNotesForCustomerAPI({
customerId
}: {
customerId: string
}): Promise < APIResponse > {
const response = await axios.get(`http://localhost:3000/notes/${customerId}`) return response.data;
}
That's it - everything else stays the same.
Restart your Stripe App by running:
stripe apps start
Try creating a note, you can see new entries being created in your DB like so:
https://launchman-space.nyc3.cdn.digitaloceanspaces.com/saasbase/images/2022/07/Screen-Shot-2022-07-30-at-10.59.38-PM.pngExcellent - You just created a Full Stack Stripe App!