Skip to main content

NextJS

EmbraceSQL connects into NextJS with a single POST app route handler.

This provides full access to AutoCRUD and can be extended with your own SQL.

Requirements

You are going to need:

  • NodeJs >= 18
  • PostgreSQL >= 14

These examples assume you are running locally with your shell able to connect to your PostgreSQL with:

psql

Create a new database dvdrental on your local PostgeSQL server.

curl "https://embracesql.github.io/dvdrental.sql" | psql

Steps

NextJS App

If you have an NextJS app great! -- if not Create One.

Make sure to pick TypeScript!

Add EmbraceSQL

cd into the root of your application.

npm install @embracesql/shared
mkdir -p ./src/server
npx embracesqlcli generate express --database postgres://postgres:postgres@localhost/dvdrental > ./src/server/dvdrental.ts

Code up a Route Handler

./src/embracesql/route.ts
import { OperationDispatcher, Database } from "../../server/dvdrental";
import { EmbraceSQLRequest, EmbraceSQLResponse } from "@embracesql/shared";

/**
* Connect next app route to EmbraceSQL with a plain
* PostgreSQL connection url.
*/
function embraceSQL(postgresUrl: string) {
let database: Database;
return async (req: Request) => {
// do we already have a connection
if (!database) {
database = await Database.connect(postgresUrl);
}
// dispatcher finds the right method for a request
const dispatcher = new OperationDispatcher(database);
try {
// do we have a valid request?
const request: EmbraceSQLRequest<object, object> = await req.json();
if (!request.operation && !(request.parameters || request.values)) {
throw new Error("Invalid Request");
}
// now we are 🥘
const results = await dispatcher.dispatch(request);
const response: EmbraceSQLResponse<unknown, object, object> = {
...request,
results,
};
return Response.json(response);
} catch (e) {
return new Response((e as Error)?.message, { status: 400 });
}
};
}

/**
* NextJS POST route connection.
*/
export const POST = embraceSQL(
"postgres://postgres:postgres@localhost/dvdrental",
);

Test

Start that server:

npm run dev

And curl for some data:

curl -X POST http://localhost:3000 \
-H 'Content-Type: application/json' \
-d '{"operation":"Public.Tables.Actor.ByActorId.read","parameters":{"actorId": 1}}'

Generate a Client

It's fun to curl and all, but TypeScript is about types and autocompletion.

Generate a fully typed fetch wrapping client.

npm install @embracesql/react
npx embracesqlcli generate react --database postgres://postgres:postgres@localhost/dvdrental > ./src/client/dvdrental-react.ts

Create a Page

Create as shown. This is a client component in this simple example to illlustrate the power of the auto-update hooks.

For fun, try typing it to get a sense of the autocomplete.

./src/app/sample.css


.card {
padding: 2em;
display: flex;
flex-direction: column;
row-gap: 1rem;
}
./src/app/actor/page.tsx
"use client";

import {
EmbraceSQLClient,
EmbraceSQLProvider,
Public,
} from "../../client/dvdrental-react";
import "../sample.css";

const Actor = () => {
// this is hooking to an AutoCRUD method to read an actor
const { row: actor } = Public.Tables.Actor.useActorPkey({ actorId: 100 });
// 🪄 - automatic onChange saving though the hook, with debounce to not smoke your DB!
// notice there is no <form> to post back or additional hooks

if (actor) {
return (
<div className="card">
<input value={actor.firstName} onChange={actor.changeFirstName} />
<input value={actor.lastName} onChange={actor.changeLastName} />
</div>
);
} else {
return null;
}
};

export default function Page() {
// connect to where we mounted EmbraceSQL in our server
const client = new EmbraceSQLClient({
url: `/embracesql`,
});
return (
<EmbraceSQLProvider client={client}>
<Actor />
</EmbraceSQLProvider>
);
}