Serverless is a computing paradigm that provides a pay-as-you-use model. It lets you deploy your projects easily and scale to meet large demands without the stress of maintaining or managing servers.
Wherever there are conversations on serverless, two important concepts often come up:
- Compute — the processing power of a server.
- Storage — the capacity to store data.
Traditionally, accessing a database from a serverless computing service like AWS Lambda is tricky due to the differences in connection protocols. Lambda functions are “ephemeral” — relying on short-lived, HTTP-centric connections, while databases utilize long-lived, TCP-centric connections.
It is possible to send a single-shot HTTP query to retrieve data from your database. However, maintaining a persistent connection (like streaming data to your clients) could lead to timeouts in your lambda runtime or compute costs that balloon unexpectedly.
One way to solve this problem is connecting via a gateway or proxy. This way, your client can establish a long-lived connection (using WebSockets) with the proxy, which then interacts with your backend using standard HTTP requests.
Neon’s serverless driver is a drop-in replacement for node-postgres
that combines the benefits of WebSockets and HTTP into one simple package, optimizing the number of round trips required to interact with a Neon Postgres database.
This article will teach you how to access a Neon Postgres database from an AWS Lambda function via Neon’s serverless driver.
Source code
Here’s a link to the GitHub repository for this article’s demo.
Prerequisites
- A Neon account. Neon offers a generous free tier that you can start with. Get it here.
- An AWS account. Explore its free tier here.
-
Node.js installed on your PC. It comes with
npm
, which you will use to add Neon’s serverless driver to your project. - A code editor. This article’s demo was built with Visual Studio Code.
Setting up a Neon database
Create a project
When you sign up on Neon, you’ll be prompted to create a project and a database like this:
Once created, your project’s dashboard will contain a general overview of your database connection details, branches, compute, and storage data.
Please take note of your database connection string because you will add it as an environment variable in your project.
Seed data
In your Neon project’s console sidebar, click on ‘SQL Editor’ and run the queries below to seed your database with some data:
CREATE TABLE cars (
id SERIAL PRIMARY KEY,
car TEXT NOT NULL,
model TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
INSERT INTO cars (car, model)
VALUES
('Toyota', 'Camry'),
('Honda', 'Civic'),
('Ford', 'Mustang'),
('Tesla', 'Model S'),
('Chevrolet', 'Silverado'),
('BMW', '3 Series'),
('Mercedes-Benz', 'E-Class'),
('Jeep', 'Wrangler'),
('Audi', 'Q5'),
('Subaru', 'Outback');
This SQL script creates a cars
table with columns for id
, car
, model
, and created_at
, then inserts the provided car makes and models into the table.
Accessing Neon’s database with serverless driver
Setup project
In your terminal, navigate to your project’s folder and start a new Node.js project by running the command below:
mkdir neon-serverless-lambda
cd neon-serverless-lambda
npm init -y
This will create a Node.js project with default values. Open your project in a code editor and update the package.json
with the code below:
{
"name": "neon-serverless-lambda",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Here, you added "type": "module"
to enable EcmaScript’s import/export
functionality.
In your project’s terminal, run the command below to install Neon’s serverless driver:
npm install @neondatabase/serverless
Write function
Open your project in a code editor, then create an index.js
file and update it with the code below:
// index.js (using `neon` object)
import { neon } from '@neondatabase/serverless';
export async function handler(event) {
try {
const sql = neon(process.env.DATABASE_URL);
const rows = await sql('SELECT * from cars');
console.log(rows);
return {
statusCode: 200,
body: JSON.stringify({
message: 'Successful',
data: rows,
}),
};
} catch (err) {
console.log('Error', err);
}
}
In the code above, you did the following:
- Imported the
neon
object from@neondatabase/serverless
. This object will allow you to connect to and run SQL queries on a Neon database using a connection string. - Created a
handler()
function with anevent
parameter. - In your
handler()
function, you wrote atry-catch
block that attempts to establish a connection to the database using theneon
object and theDATABASE_URL
environment variable. It executes a SQL query (SELECT * from cars
) to retrieve all rows from the "cars" table. Any errors during the database operation are logged usingconsole.log()
. - After fetching the rows from the database, your function constructs and returns an HTTP response with a status code of 200 (indicating success) and a JSON body containing a success message ('Successful') along with the retrieved rows (
data: rows
).
Choosing between the Neon serverless driver’s
neon
orPool/Client
objects
If you want to execute multiple queries in a single connection, Neon’sPool
object uses WebSockets and can bring latencies down to 4ms once a connection is established. However, it is best to use theneon
object for single-shot queries. Check out this blog post for more insights.
Prepare for deployment
In your PC’s file explorer, navigate to your project’s folder and zip all of its contents:
You will upload this .zip
file to AWS while creating the Lambda.
Deploying to AWS
Create a Lambda function
In your browser, log into your AWS console, search for “Lambda,” and select it from the results:
Click “Create function” and fill out the basic information for your new Lambda function:
After filling out the required basic information, scroll down and click “Create function” to finish creating your new Lambda function:
Upload your code as a zip file
In your Lambda function’s dashboard, scroll down to “Code source”, click “Upload from”, and select “.zip file”:
Navigate to your project’s folder and select the .zip file you created in the last section, then click “Save”:
Set environment variables
In your Lambda function’s dashboard, click “Configuration”, then select “Environment variables” and click the “Edit” button:
In the “Edit environment variables” page, click “Add environment variable”, then input DATABASE_URL
as the variable key and your Neon project’s database connection string as the value, then click “Save”:
Test your deployment
In your Lambda function, click “Test” to create a new test event, then fill out the event name, and click “Save”:
After saving your test, click the “Test” button to run it. If it is successful, you will see something like this:
Creating and testing your API
Create an API with AWS API Gateway
In your Lambda’s “Function overview” section, click “Add trigger” and select “API Gateway”:
Select “Create a new API”, specify “HTTP API” as the API type and the security mechanism as “Open”, then scroll down and click “Add”:
Once your API endpoint has been created, scroll down to “Triggers” to see its URL:
Test your API endpoint
To quickly test your new endpoint, copy its URL and make a “GET” request in your preferred API testing platform:
Conclusion
Following this guide, you’ve had hands-on experience bridging the gap between AWS Lambda and Neon’s database using the Neon serverless driver. In this guide, you manually zipped and deployed your code; however, you can explore The Serverless Framework or AWS Serverless Application Model (SAM) for continuous integration and deployment.
Serverless computing can help you scale to meet enormous demands. When paired with a robust, scalable, serverless database service like Neon, the result is a seamless experience for your development team and end users. Neon also offers innovative features like database branching, autoscaling, and bottomless storage, saving you time and money. Click here to explore its free tier today.