Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom API Functions #943

Merged
merged 135 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 110 commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
11c7f36
User api routes
kyscott18 May 27, 2024
8358ebd
graphql server
kyscott18 May 28, 2024
96de148
move graphql
kyscott18 May 28, 2024
dd74238
graphql middleware
kyscott18 May 28, 2024
41a81cf
.
kyscott18 May 28, 2024
8827016
example server
kyscott18 Jun 12, 2024
5a1ae49
more custom api
kyscott18 Jun 12, 2024
2b23657
cleanup server
kyscott18 Jun 12, 2024
da92dcb
more cleanup:
kyscott18 Jun 12, 2024
419a461
hono peer dep
kyscott18 Jun 12, 2024
526d717
wip graphql
kyscott18 Jun 12, 2024
8af92a2
fix graphql
kyscott18 Jun 12, 2024
3bc6803
Merge branch 'main' into kjs/api2
kyscott18 Jun 17, 2024
d55a2a5
cleanup
kyscott18 Jun 17, 2024
63d3a78
more cleanup
kyscott18 Jun 17, 2024
56fd057
.
kyscott18 Jun 17, 2024
bbb1eab
fix graphql json
kyscott18 Jun 17, 2024
821fb29
remove patch
kyscott18 Jun 17, 2024
f67fdb5
direct sql
kyscott18 Jun 17, 2024
ef36400
search path
kyscott18 Jun 17, 2024
b5c8e49
Merge branch 'main' into kjs/api2
kyscott18 Jun 17, 2024
5f36800
direct sql
kyscott18 Jun 17, 2024
f221186
Merge branch 'main' into kjs/api2
kyscott18 Jun 17, 2024
f0468f8
fix package.json
kyscott18 Jun 18, 2024
0134f38
pnpm dedupe
kyscott18 Jun 18, 2024
ea5e16d
readonly db
kyscott18 Jun 18, 2024
e3ed3b8
directories
kyscott18 Jun 18, 2024
b88e6dd
ponder.get
kyscott18 Jun 18, 2024
350ff28
hono peer dep
kyscott18 Jun 18, 2024
d9bb141
fix tests
kyscott18 Jun 18, 2024
210adb7
more logs
kyscott18 Jun 18, 2024
1bb9f57
dynamic batch size based on number of columns (#944)
kyscott18 Jun 18, 2024
ee9d6aa
format on lint staged
kyscott18 Jun 18, 2024
96f4e04
chore: version packages (#945)
github-actions[bot] Jun 18, 2024
e33c7e9
Fix bug with material columns (#946)
kyscott18 Jun 19, 2024
c349d41
chore: version packages (#947)
github-actions[bot] Jun 19, 2024
5c4bf59
server error handling
kyscott18 Jun 19, 2024
aaa044d
return error stack in response
kyscott18 Jun 19, 2024
cb12dc6
text error
kyscott18 Jun 19, 2024
0fae4bf
.
kyscott18 Jun 19, 2024
1a7762f
wip docs
typedarray Jun 20, 2024
761bfe5
fix biome config
typedarray Jun 20, 2024
6254e26
file conventions
kyscott18 Jun 20, 2024
b159182
sql tagged template
kyscott18 Jun 20, 2024
47e3ada
remove custom not found
kyscott18 Jun 20, 2024
5905e57
fix e2e tests
kyscott18 Jun 20, 2024
4b7652f
Merge branch 'main' into kjs/api2
kyscott18 Jun 20, 2024
979cb9b
.
kyscott18 Jun 20, 2024
3e60f95
docs tweak
typedarray Jun 20, 2024
f018a69
chore: wip changeset
typedarray Jun 20, 2024
a171ab4
fix: docs
typedarray Jun 20, 2024
4e05dfc
start drizzle
kyscott18 Jun 24, 2024
791a1eb
select types
kyscott18 Jun 24, 2024
9484a13
db select injection
kyscott18 Jun 25, 2024
87f5137
re-export drizzle objects
kyscott18 Jun 25, 2024
a9a00e3
wip
kyscott18 Jun 25, 2024
8685c9e
bigdog
kyscott18 Jun 25, 2024
f6e6713
more
kyscott18 Jun 25, 2024
c376e90
more column types
kyscott18 Jun 26, 2024
f0f818d
cleanup + add all types
kyscott18 Jun 26, 2024
acf2309
pair programming with kevin
kyscott18 Jun 27, 2024
a601122
revert build service changes
kyscott18 Jun 27, 2024
f38aadf
use schemas in drizzle tables
kyscott18 Jun 27, 2024
0fe58bd
plugin without serve fix
typedarray Jun 27, 2024
03e36b5
type configuration
kyscott18 Jun 27, 2024
020f70e
simplify order by and group by
kyscott18 Jun 27, 2024
ebb4076
join tests
kyscott18 Jun 27, 2024
9afab48
status endpoint
kyscott18 Jul 10, 2024
2d0e3c5
graphql metadata entity
kyscott18 Jul 10, 2024
9809d14
nits
kyscott18 Jul 10, 2024
9346d82
chore: changeset
kyscott18 Jul 10, 2024
542e7aa
fix: kysely types
kyscott18 Jul 10, 2024
0ee458a
fix: ponder_metadata table name
kyscott18 Jul 10, 2024
95f18e4
fix: database ponder_metadata creation and initialization
kyscott18 Jul 10, 2024
aaf9d2f
fix tests
kyscott18 Jul 10, 2024
bdd94cd
cleanup virtual modules
kyscott18 Jul 11, 2024
fb97142
ponder.get
kyscott18 Jul 11, 2024
ea2e215
ponder.use
kyscott18 Jul 11, 2024
40ec552
add db to hono context
kyscott18 Jul 11, 2024
ea520ac
c.tables
kyscott18 Jul 12, 2024
b9b5f65
cleanup drizzle database setup
kyscott18 Jul 12, 2024
3897be3
cleanup
kyscott18 Jul 12, 2024
5ef606d
Merge branch 'main' into kjs/api2
kyscott18 Jul 12, 2024
a554e3f
Merge branch 'kjs/api2' into kjs/drizzle
kyscott18 Jul 12, 2024
0c13213
Merge pull request #966 from ponder-sh/kjs/drizzle
kyscott18 Jul 12, 2024
047d76b
Merge branch 'kjs/status' into kjs/api2
kyscott18 Jul 12, 2024
ed57d99
use virtual module in shim
kyscott18 Jul 12, 2024
518d608
separate indexing and server build
kyscott18 Jul 12, 2024
08235b4
change name of metadata table and metadata graphql field, update shap…
kyscott18 Jul 12, 2024
95f9313
use status in e2e tests
kyscott18 Jul 12, 2024
4fdf813
fix: tests
kyscott18 Jul 12, 2024
5932a69
fix: e2e tests
kyscott18 Jul 12, 2024
9c73c24
fix: race condition w/ status
kyscott18 Jul 12, 2024
8dbb489
delete module cache for hot reloads
kyscott18 Jul 12, 2024
1037403
fix: dev server reloading
kyscott18 Jul 12, 2024
321728e
chore: cleanup e2e test
kyscott18 Jul 12, 2024
b188f6f
fix metadata for graphql and create graphql endpoint when no custom e…
kyscott18 Jul 12, 2024
40e8a9b
rename metadata table
kyscott18 Jul 12, 2024
d3ac5e8
Merge branch 'kjs/status' into kjs/api2
kyscott18 Jul 15, 2024
76d9e4c
Merge branch 'main' into kjs/api2
kyscott18 Jul 15, 2024
b9d8955
fix e2e tests
kyscott18 Jul 15, 2024
9181ad1
fix server tests
kyscott18 Jul 15, 2024
81ce418
cleanup
kyscott18 Jul 15, 2024
377af20
fix: hot reloading
kyscott18 Jul 15, 2024
ce0077f
add more drizzle tests
kyscott18 Jul 15, 2024
4a2681e
jsdoc
kyscott18 Jul 15, 2024
d99266d
cleanup
kyscott18 Jul 15, 2024
40b2ba0
cleanup hot reloading
kyscott18 Jul 15, 2024
12fec05
add server validation at build step and remove /_ponder from interna…
kyscott18 Jul 15, 2024
5e82d47
drizzle list column
kyscott18 Jul 15, 2024
411b638
nits
kyscott18 Jul 16, 2024
8672adf
fix graphql middleware
kyscott18 Jul 16, 2024
7ea2e35
refactor build service to emit two separate events
kyscott18 Jul 16, 2024
bb270da
:(
kyscott18 Jul 16, 2024
6e029c5
fix tests
kyscott18 Jul 16, 2024
17a27d6
fix graphql error status code
typedarray Jul 16, 2024
b5b3869
trpc example and add drizzle objects to hono context
kyscott18 Jul 17, 2024
646cd1e
Merge branch 'kjs/api2' of https://github.com/0xOlias/ponder into kjs…
kyscott18 Jul 17, 2024
1cc22a1
codegen
kyscott18 Jul 17, 2024
d54af6d
cleanup new example
kyscott18 Jul 17, 2024
71a56cd
fix lockfile
kyscott18 Jul 17, 2024
757f601
readonly database
typedarray Jul 17, 2024
ecf4d7c
fix: dev server reloading
kyscott18 Jul 17, 2024
c03df64
Merge branch 'kjs/api2' of https://github.com/0xOlias/ponder into kjs…
kyscott18 Jul 17, 2024
dfe2a78
e2e typesafe client
kyscott18 Jul 17, 2024
411434a
clean up example app
kyscott18 Jul 17, 2024
c8c49e6
codegen and server tests
kyscott18 Jul 17, 2024
7b3466b
new example for feature api functions
kyscott18 Jul 17, 2024
4822f8e
update api functions example
kyscott18 Jul 17, 2024
4012209
docs
typedarray Jul 17, 2024
b7e5016
add hono and new env to create ponder
kyscott18 Jul 17, 2024
63a3a23
Merge branch 'kjs/api2' of https://github.com/0xOlias/ponder into kjs…
kyscott18 Jul 17, 2024
5cab628
docs
typedarray Jul 17, 2024
1c539bc
tweaks
typedarray Jul 17, 2024
b419b84
chore: changeset
kyscott18 Jul 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/shy-donuts-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"create-ponder": minor
"@ponder/core": minor
---

[Experimental] Introduced API functions. [Read more](https://ponder-docs-git-kjs-api2-ponder-sh.vercel.app/docs/query/api-functions).
5 changes: 5 additions & 0 deletions .changeset/silent-walls-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ponder/core": patch
---

Added per network progress to the "/status" endpoint on the server and the "_metadata" entity on the GraphQL schema.
6 changes: 3 additions & 3 deletions docs/pages/docs/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export default {
},
indexing: { display: "children", title: "Indexing" },

"-- Query the database": {
"-- Query": {
type: "separator",
title: "Query the database",
title: "Query",
},
query: { display: "children", title: "Query the database" },
query: { display: "children", title: "Query" },

"-- Production": {
type: "separator",
Expand Down
1 change: 1 addition & 0 deletions docs/pages/docs/query/_meta.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
"api-functions": "API functions (experimental)",
"graphql": "GraphQL",
"direct-sql": "Direct SQL",
};
137 changes: 137 additions & 0 deletions docs/pages/docs/query/api-functions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: "API functions"
description: "Use API functions to customize the API layer of your app."
---

import { Callout, Steps } from "nextra/components";

# API functions (experimental)

**API functions** are user-defined functions that respond to incoming Web requests. You can use them to customize the API layer of your app with direct SQL queries, authentication, data from external sources, and more.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "Web" supposed to be capitalized


API functions are built on top of [Hono](https://hono.dev/), a fast and lightweight routing framework.

## Get started

<Steps>

### Install `hono` and `@ponder/core@next`

To use API functions, install `hono` and the prerelease version of `@ponder/core`.

```bash
npm install hono @ponder/core@next
```

### Create `src/api/index.ts` file

To opt-in to API functions, create a file named `src/api/index.ts` with the following code.

```ts filename="src/api/index.ts"
import { ponder } from "@/generated";

ponder.get("/hello", (c) => {
return c.text("Hello, world!");
});
```

### Send a request

With the server running, visit `http://localhost:42069/hello` in your browser to see the response.

### Add the GraphQL middleware

To register the standard GraphQL API that was automatically included in versions `<0.5.0`, register the `graphql` middleware exported from `@ponder/core`.

```ts filename="src/api/index.ts" {2,4}
import { ponder } from "@/generated";
import { graphql } from "@ponder/core";

ponder.use("/graphql", graphql());

// ...
```

</Steps>

## Query the database

API functions have read-only access to your database using a [Hono Variable](https://hono.dev/docs/api/context#set-get) named `db`. Unlike indexing functions, the `create`, `update`, `delete`, `createMany`, and `updateMany` methods are not available in API functions.

### `findUnique` and `findMany`

API functions can use `findUnique` and `findMany` to query the database. These methods work just like they do within indexing functions. [Read more](/docs/indexing/create-update-records#findmany) about the store API.

```ts filename="src/api/index.ts" {5,7-9}
import { ponder } from "@/generated";

ponder.get("/account/:address", (c) => {
const address = c.req.param("address");
const db = c.get("db");

const account = await db.Account.findUnique({
id: address,
});

if (account) {
return c.json(account);
} else {
return c.status(404).json({ error: "Account not found" });
}
});
```

### Direct SQL

Use `db.query(...){:ts}` to execute raw SQL queries against your database.

```ts filename="src/api/index.ts" {6,8-10}
import { ponder } from "@/generated";
import { sql } from "@ponder/core";

ponder.get("/:token/ticker", (c) => {
const token = c.req.param("token");
const db = c.get("db");

const result = await db.query(
sql`SELECT ticker FROM "Token" WHERE id = ${token}`
);
const ticker = result.rows[0]?.ticker;

return c.text(ticker);
});
```

## Register middleware

Use `ponder.use(...){:ts}` to add middleware to your API functions. Middleware functions can modify the request and response objects, add logs, do authentication, and more. [Read more](https://hono.dev/docs/guides/middleware) about Hono middleware.

```ts filename="src/api/index.ts" {3}
import { ponder } from "@/generated";

ponder.use((c) => {
console.log("Request received:", c.req.url);
return c.next();
});
```

## Access the Hono instance

You can register API functions and middleware using `ponder.get(...){:ts}`, `ponder.post(...){:ts}`, and `ponder.use(...){:ts}`. If you need to access the underlying Hono instance, use the `hono` property.

```ts filename="src/api/index.ts" {3}
import { ponder } from "@/generated";

ponder.hono.notFound((c) => {
return c.text("Custom 404 Message", 404);
});

// ...
```

## Internal routes

Ponder registers internal routes under the `/_ponder/*` path. If you attempt to register API functions that conflict with internal routes, the build will fail.

- `/_ponder/health`: Returns a `200` status code after the app has completed historical indexing OR the healthcheck timeout has expired, whichever comes first. [Read more](/docs/production/zero-downtime) about healthchecks.
- `/_ponder/metrics`: Returns Prometheus metrics. [Read more](/docs/advanced/metrics) about metrics.
1 change: 1 addition & 0 deletions examples/reference-erc20/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@ponder/core": "workspace:*",
"hono": "^4.4.6",
"viem": "^1.19.9"
},
"devDependencies": {
Expand Down
19 changes: 19 additions & 0 deletions examples/reference-erc20/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ponder } from "@/generated";
import { desc, graphql } from "@ponder/core";
import { formatEther } from "viem";

ponder.use("/graphql", graphql()).get("/big", async (c) => {
const { Account } = c.tables;

const account = await c.db
.select({ balance: Account.balance })
.from(Account)
.orderBy(desc(Account.balance))
.limit(1);

if (account.length === 0) {
return c.text("Not Found!");
} else {
return c.text(`Balance: ${formatEther(account[0]!.balance)}`);
}
});
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
"@biomejs/biome": "^1.8.1",
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
"hono": "4.0.0",
"lint-staged": "^15.1.0",
"simple-git-hooks": "^2.9.0",
"typescript": "5.0.4",
"viem": "1.16.0"
},
"lint-staged": {
"*.ts": ["biome format --no-errors-on-unmatched --write", "biome check"],
"*.ts": [
"biome format --no-errors-on-unmatched --write",
"biome check --no-errors-on-unmatched"
],
"!(*.ts)": ["biome format --no-errors-on-unmatched --write"]
},
"simple-git-hooks": {
Expand All @@ -32,7 +36,6 @@
"packageManager": "pnpm@8.6.10",
"pnpm": {
"patchedDependencies": {
"graphql@16.8.1": "patches/graphql@16.8.1.patch",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remind me why we're able to remove this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patched dependency wasn't working with the new middleware setup, my guess is some vite thing because vite is executing that code.

"detect-package-manager@3.0.1": "patches/detect-package-manager@3.0.1.patch"
},
"peerDependencyRules": {
Expand Down
5 changes: 2 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"hono": ">=4",
"typescript": ">=5.0.4",
"viem": ">=1.16"
},
Expand All @@ -56,17 +57,15 @@
"dataloader": "^2.2.2",
"detect-package-manager": "^3.0.1",
"dotenv": "^16.3.1",
"drizzle-orm": "^0.31.2",
"emittery": "^1.0.1",
"ethereum-bloom-filters": "^1.0.10",
"glob": "^10.3.10",
"graphql": "^16.8.1",
"graphql-type-json": "^0.3.2",
"graphql-yoga": "^5.3.0",
"hono": "^4.4.2",
"http-terminator": "^3.2.0",
"ink": "^4.4.1",
"kysely": "^0.26.3",
"magic-string": "^0.30.5",
"p-queue": "^7.4.1",
"pg": "^8.11.3",
"pg-connection-string": "^2.6.2",
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/_test/e2e/erc20/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @ts-ignore
import { ponder } from "@/generated";
import { graphql } from "@/index.js";

// biome-ignore lint/suspicious/noRedeclare: :)
declare const ponder: import("@/index.js").Virtual.Registry<
typeof import("../../ponder.config.js").default,
typeof import("../../ponder.schema.js").default
>;

ponder.use("/graphql", graphql());
11 changes: 11 additions & 0 deletions packages/core/src/_test/e2e/factory/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @ts-ignore
import { ponder } from "@/generated";
import { graphql } from "@/index.js";

// biome-ignore lint/suspicious/noRedeclare: :)
declare const ponder: import("@/index.js").Virtual.Registry<
typeof import("../../ponder.config.js").default,
typeof import("../../ponder.schema.js").default
>;

ponder.use("/graphql", graphql());
8 changes: 5 additions & 3 deletions packages/core/src/_test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,10 +694,12 @@ export async function waitForIndexedBlock(
reject(new Error("Timed out while waiting for the indexed block."));
}, 5_000);
const interval = setInterval(async () => {
const response = await fetch(`http://localhost:${port}/status`);
const response = await fetch(`http://localhost:${port}/_ponder/status`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder to remove the _ponder segment for now

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch

if (response.status === 200) {
const status = (await response.json()) as Status;
const statusBlockNumber = status[networkName]?.block?.number;
const status = (await response.json()) as Status | null;
const statusBlockNumber = status
? status[networkName]?.block?.number
: undefined;
if (
statusBlockNumber !== undefined &&
statusBlockNumber >= blockNumber
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/bin/commands/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export async function codegen({ cliOptions }: { cliOptions: CliOptions }) {
properties: { cli_command: "codegen" },
});

runCodegen({ common, graphqlSchema: buildResult.build.graphqlSchema });
runCodegen({ common, graphQLSchema: buildResult.build.graphQLSchema });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move this to userland in this PR?

Also, any reason for the rename here? IMO still think graphqlSchema is better.


logger.info({ service: "codegen", msg: "Wrote ponder-env.d.ts" });
logger.info({ service: "codegen", msg: "Wrote schema.graphql" });
Expand Down
Loading
Loading