You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/at-glance.md
+38-27Lines changed: 38 additions & 27 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,23 +1,25 @@
1
1
---
2
2
title: At glance - ElysiaJS
3
3
head:
4
-
- - meta
5
-
- property: 'og:title'
6
-
content: At glance - ElysiaJS
4
+
- - meta
5
+
- property: 'og:title'
6
+
content: At glance - ElysiaJS
7
7
8
-
- - meta
9
-
- name: 'description'
10
-
content: Designed with ergonomic design, extensive support for TypeScript, modern JavaScript API, optimized for Bun. Offers a unique experience unified type, and end-to-end type safety while maintaining excellent performance.
8
+
- - meta
9
+
- name: 'description'
10
+
content: Designed with ergonomic design, extensive support for TypeScript, modern JavaScript API, optimized for Bun. Offers a unique experience unified type, and end-to-end type safety while maintaining excellent performance.
11
11
12
-
- - meta
13
-
- property: 'og:description'
14
-
content: Designed with ergonomic design, extensive support for TypeScript, modern JavaScript API, optimized for Bun. Offers a unique experience unified type, and end-to-end type safety while maintaining excellent performance.
12
+
- - meta
13
+
- property: 'og:description'
14
+
content: Designed with ergonomic design, extensive support for TypeScript, modern JavaScript API, optimized for Bun. Offers a unique experience unified type, and end-to-end type safety while maintaining excellent performance.
15
15
---
16
16
17
17
# At glance
18
+
18
19
Elysia is designed with familiar API from Express and Fastify with extensive support for TypeScript, modern JavaScript API, and optimized for Bun.
19
20
20
21
Here's a simple hello world in Elysia.
22
+
21
23
```typescript
22
24
import { Elysia } from'elysia'
23
25
@@ -29,34 +31,37 @@ new Elysia()
29
31
Navigate to [localhost:3000](http://localhost:3000/) and it should show 'Hello Elysia' as a result.
30
32
31
33
## Performance
34
+
32
35
Building on Bun and extensive optimization like Static Code Analysis allows Elysia to generate optimized code on the fly.
33
36
34
37
Elysia can outperform most of the web frameworks available today<ahref="#ref-1"><sup>[1]</sup></a>, and even match the performance of Golang and Rust framework<ahref="#ref-2"><sup>[2]</sup></a>.
35
38
36
-
| Framework | Runtime| Average | Plain Text | Dynamic Parameters | JSON Body |
Elysia is built with a complex type system trying to infer every possible detail from simple path parameters to full-blown recursive instance deep merge to provide you the most out of TypeScript.
53
57
54
58
Take a look at this example:
59
+
55
60
```typescript
56
61
import { Elysia } from'elysia'
57
62
58
63
newElysia()
59
-
.get('/id/:id', ({ params: { id }}) =>id)
64
+
.get('/id/:id', ({ params: { id }}) =>id)
60
65
.listen(3000)
61
66
```
62
67
@@ -67,14 +72,16 @@ In most framework, you need to provide a generic type to the **id** parameter wh
67
72
Elysia's goal is to help you write less TypeScript and focus more on Business logic. Let the complex type be handled by the framework.
68
73
69
74
## Unified Type
75
+
70
76
To take a step further, Elysia provide **Elysia.t**, a schema builder to validate type and value in both runtime and compile-time to create a single source of truth for your data-type. Elysia refers this term as **Unified Type**.
71
77
72
78
Let's modify the previous code to accept only a numeric value instead of a string.
79
+
73
80
```typescript
74
81
import { Elysia, t } from'elysia'
75
82
76
83
newElysia()
77
-
.get('/id/:id', ({ params: { id }}) =>id, {
84
+
.get('/id/:id', ({ params: { id }}) =>id, {
78
85
params: t.Object({
79
86
id: t.Numeric()
80
87
})
@@ -87,6 +94,7 @@ This code ensures that our path parameter **id**, will always be a numeric strin
87
94
With Elysia schema builder, we can ensure type safety like a strong-typed language with a single source of truth.
88
95
89
96
## Standard
97
+
90
98
Elysia adopts many standards by default, like OpenAPI, and WinterCG compliance, allowing you to integrate with most of the industry standard tools or at least easily integrate with tools you are familiar with.
91
99
92
100
For instance, as Elysia adopts OpenAPI by default, generating a documentation with Swagger is as easy as adding a one-liner:
@@ -97,7 +105,7 @@ import { swagger } from '@elysiajs/swagger'
97
105
98
106
newElysia()
99
107
.use(swagger())
100
-
.get('/id/:id', ({ params: { id }}) =>id, {
108
+
.get('/id/:id', ({ params: { id }}) =>id, {
101
109
params: t.Object({
102
110
id: t.Numeric()
103
111
})
@@ -108,6 +116,7 @@ new Elysia()
108
116
With the Swagger plugin, you can seamlessly generate a Swagger page without additional code or specific config and share it with your team effortlessly.
109
117
110
118
## End-to-end Type Safety
119
+
111
120
With Elysia, type safety is not only limited to server-side only.
112
121
113
122
With Elysia, you can synchronize your type with your frontend team automatically like tRPC, with Elysia's client library, "Eden".
@@ -118,7 +127,7 @@ import { swagger } from '@elysiajs/swagger'
118
127
119
128
const app =newElysia()
120
129
.use(swagger())
121
-
.get('/id/:id', ({ params: { id }}) =>id, {
130
+
.get('/id/:id', ({ params: { id }}) =>id, {
122
131
params: t.Object({
123
132
id: t.Numeric()
124
133
})
@@ -129,6 +138,7 @@ export type App = typeof app
129
138
```
130
139
131
140
And on your client side:
141
+
132
142
```typescript
133
143
// client.ts
134
144
import { edenTreaty } from'@elysiajs/eden'
@@ -145,6 +155,7 @@ With Eden, you can use the existing Elysia type to query Elysia server **without
145
155
Elysia is not only about helping you to create a confident backend but for all that is beautiful in this world.
146
156
147
157
---
158
+
148
159
<smallid="ref-1">1. Measure in requests/second. The benchmark for parsing query, path parameter and set response header on Debian 11, Intel i7-13700K tested on Bun 0.7.2 on 6 Aug 2023. See the benchmark condition [here](https://github.com/SaltyAom/bun-http-framework-benchmark/tree/c7e26fe3f1bfee7ffbd721dbade10ad72a0a14ab#results).</small>
149
160
150
161
<smallid="ref-2">2. Based on [TechEmpower Benchmark round 22](https://www.techempower.com/benchmarks/#section=data-r22&hw=ph&test=composite).</small>
Copy file name to clipboardExpand all lines: docs/essential/context.md
+59-45Lines changed: 59 additions & 45 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,37 +1,39 @@
1
1
---
2
2
title: Handler - ElysiaJS
3
3
head:
4
-
- - meta
5
-
- property: 'og:title'
6
-
content: Handler - ElysiaJS
4
+
- - meta
5
+
- property: 'og:title'
6
+
content: Handler - ElysiaJS
7
7
8
-
- - meta
9
-
- name: 'description'
10
-
content: Context is information about each request from the client, unique to each request with a global mutable store. Context can be customized using state, decorate and derive.
8
+
- - meta
9
+
- name: 'description'
10
+
content: Context is information about each request from the client, unique to each request with a global mutable store. Context can be customized using state, decorate and derive.
11
11
12
-
- - meta
13
-
- property: 'og:description'
14
-
content: Context is information about each request from the client, unique to each request with a global mutable store. Context can be customized using state, decorate and derive.
12
+
- - meta
13
+
- property: 'og:description'
14
+
content: Context is information about each request from the client, unique to each request with a global mutable store. Context can be customized using state, decorate and derive.
15
15
---
16
16
17
17
# Context
18
-
Context is information of each request passed to [route handler](/essential/handler).
19
-
20
-
Context is unique for each request, and is not shared except it's a `store` property which is a global mutable state object, (aka state).
21
-
22
-
Elysia context is consists of:
23
-
-**path** - Pathname of the request
24
-
-**body** - [HTTP message](https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages), form or file upload.
25
-
-**query** - [Query String](https://en.wikipedia.org/wiki/Query_string), include additional parameters for search query as JavaScript Object. (Query is extract from a value after pathname starting from '?' question mark sign)
26
-
-**params** - Elysia's path parameters parsed as JavaScript object
27
-
-**headers** - [HTTP Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers), additional information about the request like User-Agent, Content-Type, Cache Hint.
28
-
-**request** - [Web Standard Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)
29
-
-**store** - A global mutable store for Elysia instance
30
-
-**cookie** - A global mutable signal store for interacting with Cookie (including get/set)
31
-
-**set** - Property to apply to Response:
32
-
-**status** - [HTTP status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status), default to 200 if not set.
33
-
-**headers** - Response headers
34
-
-**redirect** - Response as a path to redirect to
18
+
19
+
Context is information of each request passed to a [route handler](/essential/handler).
20
+
21
+
Context is unique for each request, and is not shared unless it's a `store` property which is a global mutable state object, (aka state).
22
+
23
+
Elysia context consists of:
24
+
25
+
-**path** - Pathname of the request
26
+
-**body** - [HTTP message](https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages), form or file upload.
27
+
-**query** - [Query String](https://en.wikipedia.org/wiki/Query_string), include additional parameters for search query as JavaScript Object. (Query is extracted from a value after pathname starting from '?' question mark sign)
28
+
-**params** - Elysia's path parameters parsed as JavaScript object
29
+
-**headers** - [HTTP Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers), additional information about the request like User-Agent, Content-Type, Cache Hint.
30
+
-**request** - [Web Standard Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)
31
+
-**store** - A global mutable store for Elysia instance
32
+
-**cookie** - A global mutable signal store for interacting with Cookie (including get/set)
33
+
-**set** - Property to apply to Response:
34
+
-**status** - [HTTP status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status), defaults to 200 if not set.
35
+
-**headers** - Response headers
36
+
-**redirect** - Response as a path to redirect to
35
37
36
38
## Extending context
37
39
@@ -40,17 +42,19 @@ Because Elysia only provides essential information about the Request, you can cu
40
42
Extraction of a user ID or another frequently used function related to the request, for example, into Context itself.
41
43
42
44
You can extend Elysia's context by using:
43
-
-**state** - Create a global mutable state into **Context.store**
44
-
-**decorate** - Add additional function or property assigned to **Context**
45
-
-**derive** - Add additional property based on existing property or request which is uniquely assigned to every request.
45
+
46
+
-**state** - Create a global mutable state into **Context.store**
47
+
-**decorate** - Add additional function or property assigned to **Context**
48
+
-**derive** - Add additional property based on existing property or request which is uniquely assigned to every request.
46
49
47
50
The following APIs add extra functionality to the Context.
48
51
49
52
::: tip
50
-
It's recommended to assign property related to request and response, or frequently used function to Context for separation of concern.
53
+
It's recommended to assign properties related to request and response, or frequently used functions to Context for separation of concerns.
51
54
:::
52
55
53
56
## Store
57
+
54
58
**State** is a global mutable object shared across the Elysia app.
55
59
56
60
If you are familiar with frontend libraries like React, Vue, or Svelte, there's a concept of Global State Management, which is also partially implemented in Elysia via state and store.
@@ -60,6 +64,7 @@ If you are familiar with frontend libraries like React, Vue, or Svelte, there's
60
64
**state** is a function to assign an initial value to **store**, which could be mutated later.
61
65
62
66
To assign value to `store`, you can use **Elysia.state**:
67
+
63
68
```typescript
64
69
import { Elysia } from'elysia'
65
70
@@ -71,6 +76,7 @@ new Elysia()
71
76
Once you call **state**, value will be added to **store** property, and can be later used after in handler.
72
77
73
78
Beware that you cannot use state value before being assigned.
79
+
74
80
```typescript
75
81
import { Elysia } from'elysia'
76
82
@@ -83,12 +89,13 @@ new Elysia()
83
89
```
84
90
85
91
::: tip
86
-
Elysia registers state value into the store automatically without explicit type or additional TypeScript generic is needed.
92
+
Elysia registers state values into the store automatically without explicit type or additional TypeScript generic needed.
87
93
88
94
This is the magic of the Elysia-type system that does this automatically.
89
95
:::
90
96
91
97
## Decorate
98
+
92
99
Like **store**, **decorate** assigns an additional property to **Context** directly.
93
100
94
101
The only difference is that the value should be read-only and not reassigned later.
@@ -109,6 +116,7 @@ new Elysia()
109
116
```
110
117
111
118
## Derive
119
+
112
120
Like `decorate`, you can assign an additional property to **Context** directly.
113
121
114
122
But instead of setting the property before the server is started. **derive** assigns a property when each request happens. Allowing us to extract a piece of information into a property instead.
@@ -129,17 +137,20 @@ new Elysia()
129
137
130
138
Because **derive** is assigned once a new request starts, **derive** can access Request properties like **headers**, **query**, **body** where **store**, and **decorate** can't.
131
139
132
-
Unlike **state**, and **decorate**. Properties which assigned by **derive**is unique and not shared with another request.
140
+
Unlike **state**, and **decorate**. Properties that are assigned by **derive**are unique and not shared with another request.
133
141
134
142
## Pattern
143
+
135
144
**state**, **decorate** offers a similar APIs pattern for assigning property to Context as the following:
136
-
- key-value
137
-
- object
138
-
- remap
145
+
146
+
- key-value
147
+
- object
148
+
- remap
139
149
140
150
Where **derive** can be only used with **remap** because it depends on existing value.
141
151
142
152
### key-value
153
+
143
154
You can use **state**, and **decorate** to assign a value using a key-value pattern.
144
155
145
156
```typescript
@@ -153,22 +164,23 @@ new Elysia()
153
164
This pattern is great for readability for setting a single property.
154
165
155
166
### Object
167
+
156
168
Assigning multiple properties is better contained in an object for a single assignment.
157
169
158
170
```typescript
159
171
import { Elysia } from'elysia'
160
172
161
-
newElysia()
162
-
.decorate({
163
-
logger: newLogger(),
164
-
trace: newTrace(),
165
-
telemetry: newTelemetry()
166
-
})
173
+
newElysia().decorate({
174
+
logger: newLogger(),
175
+
trace: newTrace(),
176
+
telemetry: newTelemetry()
177
+
})
167
178
```
168
179
169
180
The object offers a less repetitive API for setting multiple values.
170
181
171
182
### Remap
183
+
172
184
Remap is a function reassignment.
173
185
174
186
Allowing us to create a new value from existing value like renaming or removing a property.
@@ -200,6 +212,7 @@ Using remap, Elysia will treat a returned object as a new property, removing any
200
212
:::
201
213
202
214
## Affix
215
+
203
216
To provide a smoother experience, some plugins might have a lot of property value which can be overwhelming to remap one-by-one.
204
217
205
218
The **Affix** function which consists of **prefix** and **suffix**, allowing us to remap all property of an instance.
@@ -225,21 +238,21 @@ Allowing us to bulk remap a property of the plugin effortlessly, preventing the
225
238
By default, **affix** will handle both runtime, type-level code automatically, remapping the property to camelCase as naming convention.
226
239
227
240
In some condition, you can also remap `all` property of the plugin:
241
+
228
242
```ts
229
243
const app =newElysia()
230
-
.use(
231
-
setup
232
-
.prefix('all', 'setup')
233
-
)
244
+
.use(setup.prefix('all', 'setup'))
234
245
.get('/', ({ setupCarbon }) =>setupCarbon)
235
246
```
236
247
237
248
## Reference and value
249
+
238
250
To mutate the state, it's recommended to use **reference** to mutate rather than using an actual value.
239
251
240
252
When accessing the property from JavaScript, if you define a primitive value from an object property as a new value, the reference is lost, the value is treated as new separate value instead.
0 commit comments