A Modern Full Stack REST Application

A Modern Full Stack REST Application

Plaid is a popular API that exposes a user's banking information through REST endpoints. We will make use of their service to create a REST API to create authorization information. We will then create a React application that consumes the API to create auth tokens for a user. Remember, you can click on the View Raw button to copy any code you need. This tutorial assumes familiarity with React and full-stack development. The repo for this can be found here:

A quickstart for setting up Plaid server and React client - https://github.com/qweliant/BetterPlaidQuickstart

Getting Started with Plaid API Keys

To get started, we need to head over to Plaid for our API keys.

Landing page after login to Plaid

Navigate to the Settings tab and click Keys to view your API keys.

Creds from Plaid

We will use the sandbox environment, which uses a different key for testing than development. Notice on the left sidebar a tab that says API. Click on that and you will see the section about Plaid's redirect URI. Click on Add New URI and add http://localhost:80 and http://localhost:3000. This will control where the redirect after linking happens. If you click on the Test in Sandbox button seen on the landing page, you will be taken to a page showing the test user credentials.

Quickstart repos exist for multiple languages. You can use your language of choice for this project since the client is backend agnostic.

Backend Setup

We won't necessarily run the exact setup they have, but next, we will walk through setting up the backend via the Go Not So Quickstart Repo.

1. Create Project and Clone Repository

git clone https://github.com/plaid/quickstart.git

2. Clean Up Repository

Delete the Makefile, README, and every folder except the go one.

Docker Configuration

These come preconfigured with a Dockerfile to make deployment easy. We won't be covering deployment of Docker containers, but we will be spinning them up using Docker for Desktop.

Edit docker-compose.yml

version: "3.4"

services:
  go:
    build:
      context: .
      dockerfile: ./go/Dockerfile
    ports:
      - "8000:8000"
    env_file:
      - .env

Build and Run

docker-compose up -d --build

Dockerfile Configuration

FROM golang:1.12 AS build
WORKDIR /opt/src
COPY . .
WORKDIR /opt/src/go
RUN go get -d -v ./...
RUN go build -o quickstart

FROM gcr.io/distroless/base-debian10
COPY --from=build /opt/src/go/quickstart /
EXPOSE 8000
ENTRYPOINT ["/quickstart"]

Environment Configuration

Create a .env file:

# Get your Plaid API keys from the dashboard: https://dashboard.plaid.com/account/keys
PLAID_CLIENT_ID=CLIENT_ID
PLAID_SECRET=SANDBOX_SECRET
PLAID_ENV=sandbox
PLAID_PRODUCTS=transactions
PLAID_COUNTRY_CODES=US,CA
PLAID_REDIRECT_URI=http://localhost:80

Server Configuration

Edit server.go:

var (
    PLAID_CLIENT_ID = os.Getenv("PLAID_CLIENT_ID")
    PLAID_SECRET = os.Getenv("PLAID_SECRET")
    PLAID_ENV = os.Getenv("PLAID_ENV")
    PLAID_PRODUCTS = os.Getenv("PLAID_PRODUCTS")
    PLAID_COUNTRY_CODES = os.Getenv("PLAID_COUNTRY_CODES")
    PLAID_REDIRECT_URI = os.Getenv("PLAID_REDIRECT_URI")
    APP_PORT = os.Getenv("APP_PORT")
)

var environments = map[string]plaid.Environment{
    "sandbox": plaid.Sandbox,
    "development": plaid.Development,
    "production": plaid.Production,
}

func init() {
    // Set defaults and create Plaid client
    // ... (rest of the initialization code)
}

React Frontend Setup

Create React App

npx create-react-app plaid

Update docker-compose.yml

version: "3.8"

services:
  go:
    env_file:
      - .env
    build:
      context: .
      dockerfile: ./go/Dockerfile
    ports:
      - "8000:8000"
    restart: on-failure

  client:
    stdin_open: true
    env_file:
      - .env
    build:
      context: .
      dockerfile: ./plaid/Dockerfile
    ports:
      - 80:80
    restart: on-failure

React Dockerfile

# STAGE 1 - build the react app
FROM node:alpine as build
WORKDIR /app
COPY ./package.json /app/
RUN yarn --silent
COPY . /app
RUN yarn build

# STAGE 2 - build the final image using a nginx web server
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Nginx Configuration

Create nginx/nginx.conf:

server {
    listen 80;
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

Install Dependencies

yarn add axios react-plaid-link

Create Link.js

import React, { useState, useCallback, useEffect } from "react";
import { usePlaidLink } from "react-plaid-link";
import axios from "axios";
import qs from "qs";

const tokenURL = "http://localhost:8000/api/create_link_token";
const sendTokenURL = "http://localhost:8000/api/set_access_token";

const Link = () => {
  const [data, setData] = useState("");

  const fetchToken = useCallback(async () => {
    const config = {
      method: "post",
      url: tokenURL,
    };
    const res = await axios(config);
    console.log(res);
    setData(res.data.link_token);
  }, []);

  useEffect(() => {
    fetchToken();
  }, [fetchToken]);

  const onSuccess = useCallback(async (token, metadata) => {
    const config = {
      method: "post",
      url: sendTokenURL,
      data: qs.stringify({ public_token: token }),
      headers: { "content-type": "application/json" },
    };
    try {
      const response = await axios(config);
      console.log(response);
    } catch (error) {
      console.error(error);
    }
  }, []);

  const config = {
    token: data,
    onSuccess,
  };

  const { open, ready, err } = usePlaidLink(config);

  if (err) return "Error!";

  return (
    <button onClick={() => open()} disabled={!ready}>
      Connect a bank account
    </button>
  );
};

export default Link;

Run the Application

docker-compose up

Your app should now be running at localhost:80.

Congrats! You are now on your way to implementing a fintech banking as a service application. Kinda like...BaaS...Ok ok. Thank you for viewing. Feel free to reach out to me on my social, or connect via LinkedIn. Have a wonderful day!