Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
10 changes: 5 additions & 5 deletions docs/reference/server-adapters/api-handlers/rest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ The factory function accepts an options object with the following fields:

- externalIdMapping

Optional. An `Record<string, string>` value that provides a mapping from model names (as defined in ZModel) to unique contraint name. This is useful when you for example want to expose natural keys in place of a surrogate keys:
Optional. An `Record<string, string>` value that provides a mapping from model names (as defined in ZModel) to unique constraint name. This is useful when you for example want to expose natural keys in place of a surrogate keys:

```ts
// Expose tags by unique name and not by ID, ie. /tag/blue intead of /tag/id
Expand All @@ -112,7 +112,7 @@ The factory function accepts an options object with the following fields:
})
```

Currentlly it is not possible to use custom index names. This also works for compound unique contraints just like for [compound IDs](#compound-id-fields).
Currently it is not possible to use custom index names. This also works for compound unique constraints just like for [compound IDs](#compound-id-fields).


## Endpoints and Features
Expand Down Expand Up @@ -408,15 +408,15 @@ You can use the `filter[:selector1][:selector2][...]=value` [query parameter fam

1. Filtering with multiple values

Multiple filter values can be separated by comma. Items statisfying any of the values will be returned.
Multiple filter values can be separated by comma. Items satisfying any of the values will be returned.

```ts
GET /api/post?filter[author]=1,2
```

1. Multiple filters

A request can carry multiple filters. Only items statisfying all filters will be returned.
A request can carry multiple filters. Only items satisfying all filters will be returned.

```ts
GET /api/post?filter[author]=1&filter[published]=true
Expand Down Expand Up @@ -917,7 +917,7 @@ The JSON:API specification doesn't have a native way to represent compound IDs.
}
```

You can use this ID value convension in places where an ID is needed, e.g., reading a single entity.
You can use this ID value convention in places where an ID is needed, e.g., reading a single entity.

```ts
GET /post/1_2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,15 +360,15 @@ You can use the `filter[:selector1][:selector2][...]=value` [query parameter fam

1. Filtering with multiple values

Multiple filter values can be separated by comma. Items statisfying any of the values will be returned.
Multiple filter values can be separated by comma. Items satisfying any of the values will be returned.

```ts
GET /api/post?filter[author]=1,2
```

1. Multiple filters

A request can carry multiple filters. Only items statisfying all filters will be returned.
A request can carry multiple filters. Only items satisfying all filters will be returned.

```ts
GET /api/post?filter[author]=1&filter[published]=true
Expand Down
5 changes: 5 additions & 0 deletions versioned_docs/version-3.x/reference/package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
sidebar_position: 5
---

# Packages
2 changes: 1 addition & 1 deletion versioned_docs/version-3.x/reference/plugin-dev.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 6
description: Plugin development guide
---

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
position: 4
position: 5
label: Plugins
collapsible: true
collapsed: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
position: 7
label: Server Adapters
collapsible: true
collapsed: true
link:
type: generated-index
title: Server Adapters
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Error Handling

Refer to the specific sections for [RPC Handler](../../service/api-handler/rpc#http-status-code-and-error-responses) and [RESTful Handler](../../service/api-handler/rest#error-handling).
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>The <code>{props.module}</code> module provides a quick way to install a full set of CRUD API onto <a href={props.url} target="_blank">{props.framework}</a> apps. Combined with ZenStack's powerful access policies, you can achieve a secure data backend without manually coding it.</p>
11 changes: 11 additions & 0 deletions versioned_docs/version-3.x/reference/server-adapters/_options.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- getClient (required)

<blockquote>{props.getClient}</blockquote>

A callback for getting a ZenStackClient instance for talking to the database. Usually you'll return a client instance with access policy enabled and user identity bound.

- apiHandler (required)

<blockquote>{'ApiHandler'}</blockquote>

The [API handler](../../service/api-handler/) instance that determines the API specification.
67 changes: 67 additions & 0 deletions versioned_docs/version-3.x/reference/server-adapters/elysia.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: Elysia
description: Adapter for integrating with Elysia
sidebar_position: 8
---

import PackageInstall from '../../_components/PackageInstall';
import ErrorHandling from './_error-handling.md';
import Intro from './_intro.mdx';
import AdapterOptions from './_options.mdx';

# Elysia Adapter

<Intro module='@zenstackhq/server/elysia' framework='Elysia' url="https://elysiajs.com" />

This feature is contributed by [@rodrigoburigool](https://github.com/rodrigoburigool).

### Installation

<PackageInstall dependencies={['@zenstackhq/server@next']} />

### Mounting the API

You can use the `createElysiaHandler` API to create an Elysia request handler that handles CRUD requests automatically:

```ts
import { Elysia, Context } from 'elysia';
import { RPCApiHandler } from '@zenstackhq/server/api';
import { createElysiaHandler } from '@zenstackhq/server/elysia';
import { getSessionUser } from '~/auth';
import { client } from '~/db';
import { schema } from '~/zenstack/schema';

const app = new Elysia({ prefix: '/api' });

// install the CRUD middleware under route "/api/crud"
app.group('/crud', (app) =>
app.use(
createElysiaHandler({
apiHandler: new RPCApiHandler({ schema }),
basePath: '/api/model',
// getSessionUser extracts the current session user from the request,
// its implementation depends on your auth solution
getClient: (context) => client.$setAuth(getSessionUser(context)) }),
})
)
);

function getCurrentUser(context: Context) {
// the implementation depends on your authentication mechanism
...
}

app.listen(3000);
```

The middleware factory takes the following options to initialize:

<AdapterOptions getClient='(ctx: Context) => ClientContract<Schema> | Promise<ClientContract<Schema>>' />

- basePath (optional)

<blockquote>string</blockquote>

Optional base path to strip from the request path before passing to the API handler. E.g., if your CRUD handler is mounted at `/api/crud`, set this field to `'/api/crud'`.

<ErrorHandling />
59 changes: 59 additions & 0 deletions versioned_docs/version-3.x/reference/server-adapters/express.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Express.js
description: Adapter for integrating with Express.js
sidebar_position: 5
---

import PackageInstall from '../../_components/PackageInstall';
import ErrorHandling from './_error-handling.md';
import Intro from './_intro.mdx';
import AdapterOptions from './_options.mdx';

# Express.js Adapter

<Intro module='@zenstackhq/server/express' framework='Express.js' url="https://expressjs.com/" />

### Installation

<PackageInstall dependencies={['@zenstackhq/server@next']} />

### Mounting the API

You can integrate ZenStack into your project with the `ZenStackMiddleware` [express middleware](https://expressjs.com/en/guide/using-middleware.html):

```ts
import express from 'express';
import { ZenStackMiddleware } from '@zenstackhq/server/express';
import { RPCApiHandler } from '@zenstackhq/server/api';
import { getSessionUser } from '~/auth';
import { client } from '~/db';
import { schema } from '~/zenstack/schema';

const app = express();

app.use(express.json());

app.use(
'/api/model',
ZenStackMiddleware({
apiHandler: new RPCApiHandler({ schema }),
// getSessionUser extracts the current session user from the request, its
// implementation depends on your auth solution
getClient: (request) => client.$setAuth(getSessionUser(request)),
})
);
```

The Express.js adapter takes the following options to initialize:

<AdapterOptions getClient='(request: Request, response: Response) => ClientContract<Schema> | Promise<ClientContract<Schema>>' />

- sendResponse (optional)

<blockquote>boolean</blockquote>

Controls if the middleware directly sends a response. If set to false, the response is stored in the `res.locals` object and then the middleware calls the `next()` function to pass the control to the next middleware. Subsequent middleware or request handlers need to make sure to send a response.

Defaults to `true`.

<ErrorHandling />
53 changes: 53 additions & 0 deletions versioned_docs/version-3.x/reference/server-adapters/fastify.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: Fastify
description: Adapter for integrating with Fastify
sidebar_position: 6
---

import PackageInstall from '../../_components/PackageInstall';
import ErrorHandling from './_error-handling.md';
import Intro from './_intro.mdx';
import AdapterOptions from './_options.mdx';

# Fastify Adapter

<Intro module='@zenstackhq/server/fastify' framework='Fastify' url="https://www.fastify.io/" />

### Installation

<PackageInstall dependencies={['@zenstackhq/server@next']} />

### Mounting the API

You can integrate ZenStack into your project with the `ZenStackFastifyPlugin` [fastify plugin](https://www.fastify.io/docs/latest/Reference/Plugins/):

```ts
import fastify from 'fastify'
import { ZenStackFastifyPlugin } from '@zenstackhq/server/fastify';
import { RPCApiHandler } from '@zenstackhq/server/api';
import { getSessionUser } from '~/auth';
import { client } from '~/db';
import { schema } from '~/zenstack/schema';

const server = fastify();

server.register(ZenStackFastifyPlugin, {
apiHandler: new RPCApiHandler({ schema }),
prefix: '/api/model',
// getSessionUser extracts the current session user from the request, its
// implementation depends on your auth solution
getClient: (request) => client.$setAuth(getSessionUser(request)),
});
```

The Fastify adapter takes the following options to initialize:

- prefix

<blockquote>string</blockquote>

Prefix for the mounted API endpoints. E.g.: /api/model.

<AdapterOptions getClient='(request: FastifyRequest, reply: FastifyReply) => ClientContract<Schema> | Promise<ClientContract<Schema>>' />

<ErrorHandling />
49 changes: 49 additions & 0 deletions versioned_docs/version-3.x/reference/server-adapters/hono.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: Hono
description: Adapter for integrating with Hono
sidebar_position: 7
---

import PackageInstall from '../../_components/PackageInstall';
import ErrorHandling from './_error-handling.md';
import Intro from './_intro.mdx';
import AdapterOptions from './_options.mdx';

# Hono Adapter

<Intro module='@zenstackhq/server/hono' framework='Hono' url="https://hono.dev/" />

### Installation

<PackageInstall dependencies={['@zenstackhq/server@next']} />

### Mounting the API

You can use the `createHonoHandler` API to create a [Hono middleware](https://hono.dev/docs/getting-started/basic#using-middleware) that handles CRUD requests automatically:

```ts
import { Context, Hono } from 'hono';
import { createHonoHandler } from '@zenstackhq/server/hono';
import { RPCApiHandler } from '@zenstackhq/server/api';
import { getSessionUser } from '~/auth';
import { client } from '~/db';
import { schema } from '~/zenstack/schema';

const app = new Hono();

app.use(
'/api/model/*',
createHonoHandler({
apiHandler: new RPCApiHandler({ schema }),
// getSessionUser extracts the current session user from the request,
// its implementation depends on your auth solution
getClient: (ctx) => client.$setAuth(getSessionUser(ctx)),
})
);
```

The middleware factory takes the following options to initialize:

<AdapterOptions getClient='(ctx: Context) => ClientContract<Schema> | Promise<ClientContract<Schema>>' />

<ErrorHandling />
Loading