Backend

This solution requires manual schema creation. It also requires the usage of Node.js The Node.js API Starter Kit is probably the most basic approach to getting a GraphQL API up and running. It’s a boilerplate project that comes with all the Node.js libraries needed to connect to a Postgres DB, running an HTTP server and create GraphQL schema and resolvers. It’s a good start for projects that need full control in every part of their API.

db.ts

import { PrismaClient } from '@prisma/client';

export const prisma = new PrismaClient();

constants.ts

export const PORT = process.env.PORT || 3000;

app.ts

import express, { Request, Response } from 'express';
import helmet from 'helmet';
import * as bodyParser from 'body-parser';
import cors from 'cors';
import { PORT } from './constants';
import morgan from 'morgan';
import { upsertUser, getUserByWalletAddress } from './controllers/user';
import { getNfts, listNft } from './controllers/nft';

const app = express();

app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(helmet());
app.disable('x-powered-by');
app.set('json spaces', 2);
app.use(morgan('tiny'));

app.get('/', (req: Request, res: Response) => {
  res.send({
    ok: true,
    message: 'App is running'
  });
});

app.get('/api/user/:walletAddress', async (req: Request, res: Response) => {
  try {
    const { walletAddress } = req.params;
    const user = await getUserByWalletAddress(walletAddress);

    res.send({
      ok: true,
      user
    });
  } catch (e) {
    res.status(500).send({
      ok: false,
      error: 'User was not found'
    });
  }
});

app.post('/api/user', async (req: Request, res: Response) => {
  try {
    const { body } = req;
    const user = await upsertUser(body);

    res.send({
      ok: true,
      user
    });
  } catch (e) {
    console.log(e);
    res.status(500).send({
      ok: false,
      error: 'Could not create user'
    });
  }
});

app.post('/api/nft', async (req: Request, res: Response) => {
  try {
    const { body } = req;
    const nft = await listNft(body);

    res.send({
      ok: true,
      nft
    });
  } catch (e) {
    console.log(e);
    res.status(500).send({
      ok: false,
      error: 'Could not list nft'
    });
  }
});

app.get('/api/nfts', async (req: Request, res: Response) => {
  try {
    const nft = await getNfts();

    res.send({
      ok: true,
      nft
    });
  } catch (e) {
    console.log(e);
    res.status(500).send({
      ok: false,
      error: 'Could not get nfts'
    });
  }
});

app.listen(PORT, () => {
  console.log(`App running on port ${PORT}`);
});

controllers/nft.ts

import { prisma } from '../db';

export const listNft = async (nft: {
  contractAddress: string;
  type: string;
  tokenId: number;
  royaltyReceiver: string;
  royaltyPercent: number;
  paymentAmount: number;
  paymentCurrencyAddress: string;
}) => {
  return await prisma.nft.create({ data: nft });
};

export const getNfts = async () => {
  return await prisma.nft.findMany();
};

controllers/users.ts

import { prisma } from '../db';

export const getUserByWalletAddress = async (walletAddress: string) => {
  return await prisma.user.findFirst({
    select: {
      walletAddress: true,
      id: true
    },
    where: {
      walletAddress
    }
  });
};

// TODO: Replace any type
export const upsertUser = async (userInfo: { walletAddress: string }) => {
  return await prisma.user.upsert({
    where: {
      walletAddress: userInfo.walletAddress
    },
    update: {
      walletAddress: userInfo.walletAddress
    },
    create: {
      walletAddress: userInfo.walletAddress
    }
  });
};

prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
    id        Int      @id @default(autoincrement())
    createdAt DateTime @default(now())
    walletAddress     String   @unique
}

model Nft {
    contractAddress         String
    type                    String // 1155 or 721
    tokenId                 Int
    royaltyReceiver         String
    royaltyPercent          Int
    paymentAmount           Int
    paymentCurrencyAddress  String
  @@unique([contractAddress, tokenId])
}

env.example

DATABASE_URL=postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public

Last updated