/supabase-graphql-example

A HackerNews-like clone built with Supabase and pg_graphql

Primary LanguagePLpgSQL

Supabase GraphQL Example

A basic HackerNews-like clone where posts can be submitted with url links and then up and down voted.

graphql-hn

Showcase

Backend

  • CRUD (Query + Mutation Operations)
  • Cursor Based Pagination
  • Authorization / Postgres Row Level Security
  • Supabase - Create a backend in less than 2 minutes. Start your project with a Postgres Database, Authentication, instant APIs, Realtime subscriptions and Storage.
  • pg_graphql - A native PostgreSQL extension adding GraphQL support. The extension keeps schema generation, query parsing, and resolvers all neatly contained on your database server requiring no external services.
  • Postgres Triggers and Postgres Functions - When votes are in, use triggers to invoke a Postgres function that calculates a post score to rank the feed
  • Postgres Enumerated Types - Enums help defined the direction of a vote: UP or DOWN.

Frontend

  • Next.js - React Framework
  • TypeScript - TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.
  • graphql-code-generator - Generate code from your GraphQL schema and operations with a simple CLI
  • gql-tag-operations-preset - This code gen preset generates typings for your inline gql function usages, without having to manually specify import statements for the documents
  • urql - A highly customizable and versatile GraphQL client
  • Gravatar - Default avatar profile images from Gravatar

Functionality

  • Registration
  • Get a ranked feed of posts
  • Create Post
  • Delete Post
  • Create Comment
  • Delete Comment
  • Upvote/Downvote Post
  • View Profile (Account)
  • View Profile (Public)
  • Pagination (Posts, Comments)

QuickStart

Setup env vars

Install dependencies, GraphQL codegen, run app

yarn
yarn codegen
yarn workspace app dev

Deploy to Vercel

Provide the following settings to deploy a production build to Vercel:

  • BUILD COMMAND: yarn codegen && yarn workspace app build
  • OUTPUT DIRECTORY: ./app/.next
  • INSTALL COMMAND: yarn
  • DEVELOPMENT COMMAND: yarn codegen && yarn workspace app dev --port $PORT

Development

  1. Fetch latest GraphQL Schema
yarn codegen:fetch
  1. Generate Types and Watch for Changes
yarn codegen:watch
  1. Run server
yarn workspace app dev

Synchronize the GraphQL schema

Note: You need to call select graphql.rebuild_schema() manually to synchronize the GraphQL schema with the SQL schema after altering the SQL schema.

Manage Schema with dbmate

  1. brew install dbmate
  2. Setup .env with DATABASE_URL
  3. Dump Schema
cd data
dbmate dump

Note: If pgdump fails due to row locks, a workaround is to grant the postgres role superuser permissions with ALTER USER postgres WITH SUPERUSER. After dumping the schema, you should reset the permissions using ALTER USER postgres WITH NOSUPERUSER. You can run these statements in the Superbase Dashboard SQL Editors.

Schema (Public)

  • Profile belongs to auth.users

  • Post

  • Comment belongs to Post and Profile

  • Vote belongs to Post (can have a direction of UP/DOWN)

  • direction enum is "UP" or "DOWN"

Constraints

  • Post url is unique
  • Vote is unique per Profile, Post (ie, you cannot vote more than once -- up or down)

See: ./data/db/schema.sql

Note: The schema includes the entire Supabase schema with auth, storage, functions, etc.

Seed Data

A data file for all Supabase Blog posts from the RSS feed can be found in ./data/seed/blog_posts.csv and can be loaded. Another file for comments is available as well.

Note: Assumes a known profileId currently.

GraphQL Schema

See: ./graphql/schema/schema.graphql

Example Query

See: ./graphql/queries/

Use: https://mvrfvzcivgabojxddwtk.supabase.co/graphql/v1

Note: Needs headers


Content-Type: application/json
apiKey: <supabase_anon_key>

GraphiQL

GraphiQL is an in-browser IDE for writing, validating, and testing GraphQL queries.

Visit http://localhost:3000/api/graphiql for the Yoga GraphiQL Playground where you can experiment with queries and mutations.

Note: Needs headers


Content-Type: application/json
apiKey: <supabase_anon_key>

Note: In order for the RLS policies authenticate you, you have to pass an authorization header (see example):

authorization: Bearer <access_token>

Ranked Feed

query {
  rankedFeed: postCollection(orderBy: [{ voteRank: AscNullsFirst }]) {
    edges {
      post: node {
        id
        title
        url
        upVoteTotal
        downVoteTotal
        voteTotal
        voteDelta
        score
        voteRank
        comments: commentCollection {
          edges {
            node {
              id
              message
              profile {
                id
                username
                avatarUrl
              }
            }
          }
          commentCount: totalCount
        }
      }
    }
  }
}

Row Level Security Matrix (RLS)

You can query all policies via: select * from pg_policies.

See: Row Level Security Matrix (RLS)

Read More

Troubleshooting

  1. dbmate can create schema_migrations tables in schemas. To make sure they are not included in your GraphQL Schema:
revoke select on table public.schema_migrations from anon, authenticated;
  1. To enable inflection
comment on schema public is e'@graphql({"inflect_names": true})';
  1. Try the heartbeat to see if pg_graphql can access requests
select graphql_public.graphql(
	null,
	$$ { heartbeat }$$
)

Returns:

{ "data": { "heartbeat": "2022-07-28T17:07:07.90513" } }
  1. Is the public_graphql schema not exposed properly?

Getting an 406 status or error message like:

{
    "message": "The schema must be one of the following: public, storage"
}

Then be sure to expose the graphql_public in Settings > Project settings > API.

The schema to expose in your API. Tables, views and stored procedures in this schema will get API endpoints.

image