This guide was contributed by Josep Vidal from Grafbase
Grafbase allows you to combine your data sources into a centralized GraphQL endpoint and deploy a serverless GraphQL backend.
This guide describes how to create a GraphQL API using Grafbase and use Grafbase Edge Resolvers with the Neon serverless driver to interact with your Neon database at the edge.
The example project in this guide simulates a marketplace of products, where the product price is dynamically calculated based on data retrieved from your Neon database.
Prerequisites
- The Grafbase CLI
- A Neon project. See Create a Neon project.
Create a backend with Grafbase
-
Create a directory and initialize your Grafbase project by running the following commands:
npx grafbase init grafbase-neon cd grafbase-neon
-
In your project directory, open the
grafbase/schema.graphql
file and replace the existing content with the following schema:extend type Mutation { addProductVisit(productId: ID!): ID! @resolver(name: "add-product-visit") } type Product @model { name: String! price: Float @resolver(name: "product/price") }
Create the schema in Neon
-
Navigate to the Neon Console and select your project.
-
Open the Neon SQL Editor and run the following
CREATE TABLE
statement:CREATE TABLE product_visits(id SERIAL PRIMARY KEY, product_id TEXT NOT NULL);
The
product_visits
table stores product page view data that the application uses to dynamically calculate a product price.
Create the resolver files
The schema includes an addProductVisit
query and prodcut/price
field. Create resolvers for those by creating the following files in your project directory:
grafbase/resolvers/add-product-visit.js
grafbase/resolvers/product/price.js
You can use the following commands to create the files:
cd grafbase
mkdir resolvers
cd resolvers
touch add-product-visit.js
mkdir product
cd product
touch price.js
You will add code to these files in a later step.
Install the Neon serverless driver
Inside the grafbase
directory in your project, run the following commands to install the Neon serverless driver:
cd ..
npm init -y
npm install @neondatabase/serverless
Retrieve your Neon connection string
A database connection string is required to forward queries to your Neon database. You can find your database connection string by clicking the Connect button on your Project Dashboard.
-
Navigate to the Neon Project Dashboard.
-
Click Connect and copy the connection string for your database. The connection string should appear similar to the following:
postgresql://[user]:[password]@[neon_hostname]/[dbname]
-
Add a
DATABASE_URL
environment variable to yourgrafbase/.env
file and set the value to your connection string. For example:DATABASE_URL=postgresql://[user]:[password]@[neon_hostname]/[dbname]
Add code to the resolvers
-
In the
resolvers/product/add-product-visit
resolver, add the following code, which inserts a new record in theproduct_visits
table with aproductId
each time the resolver is queried.# grafbase/resolvers/add-product-visit.js import { Client } from '@neondatabase/serverless' export default async function Resolver(_, { productId }) { const client = new Client(process.env.DATABASE_URL) await client.connect() await client.query( `INSERT INTO product_visits (product_id) VALUES ('${productId}')` ) await client.end() return productId }
-
In the
grafbase/resolvers/product/price.js
resolver, add the following code, which calculates the product price based on the number of product visits (the number of visits represents customer interest in the product).# grafbase/resolvers/product/price.js import { Client } from '@neondatabase/serverless' export default async function Resolver({ id }) { const client = new Client(process.env.DATABASE_URL) await client.connect() const { rows: [{ count }] } = await client.query( `SELECT COUNT(*) FROM product_visits WHERE product_id = '${id}'` ) await client.end() return Number.parseInt(count) }
Test the resolvers
To test the resolvers with Neon, perform the following steps:
-
Start the Grafbase CLI:
npx grafbase dev
-
Go to http://localhost:4000 and execute the following GraphQL mutation, which creates a new product:
mutation { productCreate(input: { name: "Super Product" }) { product { id name } } }
-
Use the product
id
to execute the following mutation, which adds a row to the database table in Neon:mutation { addProductVisit(productId: "PREVIOUS_PRODUCT_ID") }
-
Query the same product, and check the price:
query { product(input: { by: "PREVIOUS_PRODUCT_ID" }) { id name price } }
-
Run the query several more times and watch how the price increases as "interest" in the product increases.