Building a Credit System w/ Prisma (Pt. 1)

Abhi Aiyer
May 26, 2018 · 6 min read
Thank you https://www.windowscentral.com/gamble-night-away-slots-club-windows-phone-8 for the pic

In the spirits of gamification, I am going to build a microservice that can power in-app currency.

This is going to be a unique blog post. I am going to build the service as I am writing the blog post. Here goes:

First things first, let’s install prisma

$ npm install prisma -g

Alright next I’m going to make a new project:

$ prisma init credits

This returns some options to jump start your project. Let me get a screenshot for everyone:

I feel like I’m starting a video game, and I need to pick the right game mode. The way I look at these options are:

  1. Use existing database — This is a new project, so not going to choose this one!
  2. Create new database — I have experience with docker, so I’ll keep this in mind
  3. Demo server — Hmm hosted option, includes a DB, which means less work for me? Maybe.
  4. Use other server — Well I don’t have one so, not choosing this one.

So it comes down to creating and rolling a DB through docker, or going through the training wheels version with the hosted demo environment. I’m going to take the easy way out of this one. #3 it is.

Alright sweet. Can log in with Github!

Sure.

Wow 130ms latency vs 431ms latency. What a time to be alive. Forgive me, for I have just yelled “WEST SIDE” and hit enter.

Awesome prisma created 2 files for me:

  1. prisma.yml
  2. datamodel.graphql

From my understanding the primsa.yml is a manifest that will help me deploy my service to the cloud. Awesome. The datamodel.graphql will be a big GraphQL schema we’ll iterate on.

What we’re trying to build from the get go is our Data Access layer.

Let’s see whats in our datamodel thus far:

type User {
id: ID! @unique
name: String!
}

Oh man, this app is so complex already. :)

Okay let’s deploy this to the cloud

$ prisma deploy

Wow, would you like at that! Look ma, an API !

https://us1.prisma.sh/abhi-aiyer/credits/dev <- for those following along, be my guest.

If you inspect the schema of this api, you can actually see something really cool. Prisma generated a whole set of CRUD operations based on my datamodel.

Hmm this looks super familiar to me….wait. Oh it’s based off:

Nice, I love that Prisma uses this open specification for GraphQL databases.

Design Time

So as much as I love having the boilerplate data model, the design of our credits application doesn’t need to own the data model for a User. Ideally, you should be able to integrate this service into your own application.

Let’s delete the User type and make some new ones.

The first type I’m going to make is the CreditAccount. We’re going to use this to store basic info about the currency as it relates to a user. This type will hold information about the current balance. Here it is:

type CreditAccount {
id: ID! @unique
userId: ID! @unique
balance: Int
createdAt: DateTime!
updatedAt: DateTime!
}

Prisma’s data modeling exposes some nice convenience types like DateTime for example. And OpenCRUD provides the specification for a @unique field.

Next I want to model out a type for a Price

enum PriceCode {
CREDIT
US_CENTS
}
enum Interval {
MONTH
YEAR
DAY
HOUR
}
enum Term {
MONTHLY
YEARLY
}
type Price {
count: Int
unit: PriceCode
# If we were building a subscription product then
# these two fields would come in handy
interval: Interval
term: Term
}

When we price things in our system we want to know what that actually means. Our Price type here represents the count and unit pairs that we’ll use to derive cost. Though this initial version is not going to support a subscription system (like most businesses), I added some types there in case I added that functionality later.

The thing I love about building products is the ability to take small concepts to build bigger ones. We’re going to keep our Price types in mind and build a type for a Sku

What is a SKU? It’s a Stock Keeping Unit. I’m going to be a nerd and read up on the history of a SKU. I’ll be right back, maybe with a fun fact.

Has anyone gotten so lost in wikipedia? I just did. Imagine starting at SKU, learning about Inventory control, and somehow ending up reading the history of barcode scanners. Weird, but essentially I want a SKU based system so every purchase made is tied to a distinct item in our inventory.

enum Vendors {
ABHI
}
type Sku {
id: ID! @unique
name: String! @unique
price: Price
description: String!
vendor: Vendors
}

For our Sku, we’re going to keep track of the price, description, and who the vendor was.

Okay look at us, we’ve come a long way. We have a type that summarizes our Credit balance. We have a concept of Sku’s that have certain price units. Now we need a way to keep track of the different offerings our system may provide.

For this ladies and gentleman, I introduce to you the PricingTable. The pricing tables job is to represent a group of skus. You can imagine offering the user a bunch of skus at different price points and having them select an option.

type PricingTable {
id: ID! @unique
name: String! @unique
description: String
skuIds: [ID!]!
preferredSkus: [ID!]
}

I added a preferredSkus as an array of Sku IDs in case we want to promote certain Skus in the pricing table to the user. Who knows if we’ll need it though. Maybe.

Last but not least, in any currency system we’re going to need to represent the passing of money/currency for Skus. We’ll make a type for a Transaction

type TransactionUser {
userId: ID!
email: String
name: String
}
enum TransactionStatusCodes {
PENDING
FAILED
SUCCEEDED
}
enum TransactionType {
PURCHASE
ADJUSTMENT
SPEND
}
type TransactionItem {
sku: Sku
count: Int
}
type Transaction {
id: ID! @unique
transactionId: ID!
accountId: ID!
description: String
initiatedBy: TransactionUser!
type: TransactionType!
items: [TransactionItem!]!
total: Price
status: TransactionStatusCodes!
statusMessage: String
createdAt: DateTime!
updatedAt: DateTime!
}

Our transaction builds on the types we’ve created before and we introduce a few ones: TransactionUser, TransactionStatusCodes, TransactionType, and TransactionItem. Pretty straightforward I think, I hope, ¯\_(ツ)_/¯

Okay, we have a ton of types made. Let’s see what Prisma can do.

$ prisma deploy

Holy crap. Prisma just generated all of this into GraphQL APIs for my database.

Time to play in the playground:

Be OUR guest, Be our guest, Be our guest: https://us1.prisma.sh/abhi-aiyer/credits/dev

Alright, in the next chapter, I’m going to build out a GraphQL server and implement what I like to call the “Service” layer. This will use the data access layer Prisma just generated for me to actually build business logic.

Open GraphQL

Anything & Everything GraphQL