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.graphqlfile 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 TABLEstatement:CREATE TABLE product_visits(id SERIAL PRIMARY KEY, product_id TEXT NOT NULL);The
product_visitstable 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.jsgrafbase/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.jsYou 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/serverlessRetrieve 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_URLenvironment variable to yourgrafbase/.envfile 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-visitresolver, add the following code, which inserts a new record in theproduct_visitstable with aproductIdeach 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.jsresolver, 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
idto 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.