docs/pages/packages/server.mdx 7.2 K raw
1
import { Button } from "vocs/components";
2
3
# `server`
4
5
This package lets us build an API or connect databases and other tools that require a server environment. bhvr uses [Hono](https://hono.dev) to power the API as it's simple, easy to use, and has a lot of ecosystem plugins and adoption. It's similar to express but lighter and more modern.
6
7
:::tip
8
Check out the [official Hono documentation](https://hono.dev) for a full reference
9
:::
10
11
## Basics
12
13
You can declare routes in your API like so
14
15
```typescript
16
import { Hono } from "hono";
17
18
const app = new Hono();
19
20
app.get("/", (c) => {
21
  return c.text("Hello Hono!");
22
});
23
24
export default app;
25
```
26
27
Hono also makes it easy to add in path parameters
28
29
```typescript
30
app.get("/user/:name", async (c) => {
31
  const name = c.req.param("name");
32
  // ...
33
});
34
```
35
36
or multiple parameters
37
38
```typescript
39
app.get("/posts/:id/comment/:comment_id", async (c) => {
40
  const { id, comment_id } = c.req.param();
41
  // ...
42
});
43
```
44
45
The `(c)` in Hono is the `Context` which has loads of primary features of your API.
46
47
**Access a Request**
48
49
```typescript
50
app.get("/hello", (c) => {
51
  const userAgent = c.req.header("User-Agent");
52
  // ...
53
});
54
```
55
56
**Return JSON or HTML**
57
58
```typescript
59
app.get("/api", (c) => {
60
  return c.json({ message: "Hello!" });
61
});
62
```
63
64
```typescript
65
app.get("/", (c) => {
66
  return c.html("<h1>Hello! Hono!</h1>");
67
});
68
```
69
70
**Access an ENV**
71
72
```typescript
73
// Type definition to make type inference
74
type Bindings = {
75
  MY_KV: KVNamespace;
76
};
77
78
const app = new Hono<{ Bindings: Bindings }>();
79
80
// Environment object for Cloudflare Workers
81
app.get("/", async (c) => {
82
  c.env.MY_KV.get("my-key");
83
  // ...
84
});
85
```
86
87
## RPC
88
89
One of the unique built in features of Hono is it's RPC. With this enabled you can create a Hono client in your frontend and get automatic type safety without needing to import or export types from `shared`. This is not enabled by default to help keep an unbiased template starter, but when creating a new bhvr project it is easy to enable.
90
91
```bash [terminal]
92
bun create bhvr@latest --rpc
93
```
94
95
This will setup your API with the following code, and the key being the use of `const routes` and exporting the `AppType`
96
97
```typescript src/index.ts
98
import { Hono } from "hono";
99
import { cors } from "hono/cors";
100
import type { ApiResponse } from "shared/dist";
101
102
const app = new Hono();
103
104
app.use(cors());
105
106
const routes = app
107
  .get("/", (c) => {
108
    //[!code focus]
109
    return c.text("Hello Hono!");
110
  })
111
112
  .get("/hello", async (c) => {
113
    const data: ApiResponse = {
114
      message: "Hello BHVR!",
115
      success: true,
116
    };
117
118
    return c.json(data, { status: 200 });
119
  });
120
121
export type AppType = typeof routes; // [!code focus]
122
export default app;
123
```
124
125
In your `client` code Hono is installed as a dependency, and the `hc` client is imported and initialized. The `AppType` is also used so we can build types with it.
126
127
```typescript src/App.tsx
128
import { useState } from 'react'
129
import beaver from './assets/beaver.svg'
130
import type { AppType } from 'server' // [!code focus]
131
import { hc } from 'hono/client' // [!code focus]
132
import './App.css'
133
134
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"
135
136
const client = hc<AppType>(SERVER_URL); // [!code focus]
137
138
type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; // [!code focus]
139
140
function App() {
141
  const [data, setData] = useState<Awaited<ReturnType<ResponseType["json"]>> | undefined>()
142
143
  async function sendRequest() {
144
    try {
145
      const res = await client.hello.$get()
146
      if (!res.ok) {
147
        console.log("Error fetching data")
148
        return
149
      }
150
      const data = await res.json()
151
      setData(data)
152
    } catch (error) {
153
      console.log(error)
154
    }
155
  }
156
157
  return (
158
    <>
159
      {/* JSX markup...*/}
160
    </>
161
  )
162
}
163
164
export default App
165
```
166
167
## DB Connections
168
169
There are lots of options out there which can be simple as installing some packages and setting up API keys like [Supabase](https://supabase.com). You can also install ORM clients to handle raw connections like [Drizzle](https://orm.drizzle.team) or [Prisma](https://prisma.io/orm). Since Hono works great with Cloudflare Workers I would also highly recommend checking out [D1](https://developers.cloudflare.com/d1) as it can be easily accessed through the Hono context.
170
171
```typescript
172
import { Hono } from "hono";
173
174
// This ensures c.env.DB is correctly typed
175
type Bindings = {
176
  DB: D1Database;
177
};
178
179
const app = new Hono<{ Bindings: Bindings }>();
180
181
// Accessing D1 is via the c.env.YOUR_BINDING property
182
app.get("/query/users/:id", async (c) => {
183
  const userId = c.req.param("id");
184
  try {
185
    let { results } = await c.env.DB.prepare("SELECT * FROM users WHERE user_id = ?")
186
      .bind(userId)
187
      .all();
188
    return c.json(results);
189
  } catch (e) {
190
    return c.json({ err: e.message }, 500);
191
  }
192
});
193
194
// Export our Hono app: Hono automatically exports a
195
// Workers 'fetch' handler for you
196
export default app;
197
```
198
199
## Cloudflare Workers
200
201
One of the best ways to use Hono is with Cloudflare Workers. They're cheap, pretty easy to use, and can link to other Cloudflare services like KVs or Databases. However there are some differences with how you use Hono if you take the Worker route, so we'll point out some tips here.
202
203
### Environment Variables
204
205
Cloudlfare has both public and private variables, and can only be accessed through the Hono Context. This means if you have a function in another file or folder using something like `process.env.MY_SECRET` it's not going to work. Instead you need to put your environemnt names as Bindings to make everything typesafe.
206
207
```typescript
208
type Bindings = {
209
  MY_BUCKET: R2Bucket;
210
  USERNAME: string;
211
  PASSWORD: string;
212
};
213
214
const app = new Hono<{ Bindings: Bindings }>();
215
216
// Access to environment values
217
app.put("/upload/:key", async (c, next) => {
218
  const key = c.req.param("key");
219
  await c.env.MY_BUCKET.put(key, c.req.body);
220
  return c.text(`Put ${key} successfully!`);
221
});
222
```
223
224
To set these variables, public ones can be put inside the `wrangler.jsonc` or `wrangler.toml` file.
225
226
```jsonc
227
{
228
  "$schema": "node_modules/wrangler/config-schema.json",
229
  "name": "server",
230
  "main": "src/index.ts",
231
  "compatibility_date": "2025-05-07",
232
  // "compatibility_flags": [
233
  //   "nodejs_compat"
234
  // ],
235
  "vars": {
236
    "MY_VAR": "my-variable",
237
  },
238
  "kv_namespaces": [
239
    {
240
      "binding": "MY_KV_NAMESPACE",
241
      "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
242
    },
243
  ],
244
  // "r2_buckets": [
245
  //   {
246
  //     "binding": "MY_BUCKET",
247
  //     "bucket_name": "my-bucket"
248
  //   }
249
  // ],
250
  // "d1_databases": [
251
  //   {
252
  //     "binding": "MY_DB",
253
  //     "database_name": "my-database",
254
  //     "database_id": ""
255
  //   }
256
  // ],
257
  // "ai": {
258
  //   "binding": "AI"
259
  // },
260
  // "observability": {
261
  //   "enabled": true,
262
  //   "head_sampling_rate": 1
263
  // }
264
}
265
```
266
267
Secret variables can be used in a test env by storing them in a `.dev.vars` file
268
269
```
270
MY_SECRET = "SOME_SECRET"
271
```
272
273
To use secret variables for deployment you can use the Cloudflare dashboard or use the Wrangler CLI
274
275
```bash [terminal]
276
bunx wrangler secret put MY_SECRET
277
278
# Prompt: Enter your secret to have it encrypted on Cloudflare
279
```
280
281
:::tip
282
Read the [Hono documentation](https://hono.dev/docs/getting-started/cloudflare-workers) on Workers for more info
283
:::
284
285
## Deployment
286
287
<Button href="/deployment/server/cloudflare-workers">Deployments Section</Button>