@effect/platform 0.68.5 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HttpApiMiddleware/package.json +6 -0
- package/README.md +306 -233
- package/dist/cjs/Headers.js +7 -2
- package/dist/cjs/Headers.js.map +1 -1
- package/dist/cjs/HttpApi.js +90 -78
- package/dist/cjs/HttpApi.js.map +1 -1
- package/dist/cjs/HttpApiBuilder.js +243 -255
- package/dist/cjs/HttpApiBuilder.js.map +1 -1
- package/dist/cjs/HttpApiClient.js +64 -59
- package/dist/cjs/HttpApiClient.js.map +1 -1
- package/dist/cjs/HttpApiEndpoint.js +74 -109
- package/dist/cjs/HttpApiEndpoint.js.map +1 -1
- package/dist/cjs/HttpApiError.js +3 -4
- package/dist/cjs/HttpApiError.js.map +1 -1
- package/dist/cjs/HttpApiGroup.js +103 -100
- package/dist/cjs/HttpApiGroup.js.map +1 -1
- package/dist/cjs/HttpApiMiddleware.js +67 -0
- package/dist/cjs/HttpApiMiddleware.js.map +1 -0
- package/dist/cjs/HttpApiSchema.js +33 -7
- package/dist/cjs/HttpApiSchema.js.map +1 -1
- package/dist/cjs/HttpApiSecurity.js +2 -2
- package/dist/cjs/HttpApiSecurity.js.map +1 -1
- package/dist/cjs/HttpApiSwagger.js +3 -1
- package/dist/cjs/HttpApiSwagger.js.map +1 -1
- package/dist/cjs/HttpBody.js.map +1 -1
- package/dist/cjs/HttpIncomingMessage.js +5 -1
- package/dist/cjs/HttpIncomingMessage.js.map +1 -1
- package/dist/cjs/HttpServer.js +12 -1
- package/dist/cjs/HttpServer.js.map +1 -1
- package/dist/cjs/HttpServerRespondable.js +1 -1
- package/dist/cjs/HttpServerRespondable.js.map +1 -1
- package/dist/cjs/OpenApi.js +102 -63
- package/dist/cjs/OpenApi.js.map +1 -1
- package/dist/cjs/OpenApiJsonSchema.js +58 -47
- package/dist/cjs/OpenApiJsonSchema.js.map +1 -1
- package/dist/cjs/Transferable.js +2 -2
- package/dist/cjs/Transferable.js.map +1 -1
- package/dist/cjs/UrlParams.js +5 -1
- package/dist/cjs/UrlParams.js.map +1 -1
- package/dist/cjs/Worker.js.map +1 -1
- package/dist/cjs/WorkerError.js +1 -5
- package/dist/cjs/WorkerError.js.map +1 -1
- package/dist/cjs/WorkerRunner.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/httpBody.js +1 -1
- package/dist/cjs/internal/httpBody.js.map +1 -1
- package/dist/cjs/internal/httpClientRequest.js.map +1 -1
- package/dist/cjs/internal/httpClientResponse.js +1 -1
- package/dist/cjs/internal/httpClientResponse.js.map +1 -1
- package/dist/cjs/internal/httpRouter.js +1 -1
- package/dist/cjs/internal/httpRouter.js.map +1 -1
- package/dist/cjs/internal/httpServer.js +7 -1
- package/dist/cjs/internal/httpServer.js.map +1 -1
- package/dist/cjs/internal/httpServerRequest.js +1 -1
- package/dist/cjs/internal/httpServerRequest.js.map +1 -1
- package/dist/cjs/internal/httpServerResponse.js.map +1 -1
- package/dist/cjs/internal/keyValueStore.js +1 -1
- package/dist/cjs/internal/keyValueStore.js.map +1 -1
- package/dist/cjs/internal/multipart.js +1 -1
- package/dist/cjs/internal/multipart.js.map +1 -1
- package/dist/cjs/internal/worker.js +6 -7
- package/dist/cjs/internal/worker.js.map +1 -1
- package/dist/cjs/internal/workerRunner.js +3 -4
- package/dist/cjs/internal/workerRunner.js.map +1 -1
- package/dist/dts/Headers.d.ts +4 -6
- package/dist/dts/Headers.d.ts.map +1 -1
- package/dist/dts/HttpApi.d.ts +64 -140
- package/dist/dts/HttpApi.d.ts.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +84 -167
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpApiClient.d.ts +34 -11
- package/dist/dts/HttpApiClient.d.ts.map +1 -1
- package/dist/dts/HttpApiEndpoint.d.ts +119 -273
- package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/dts/HttpApiError.d.ts +5 -2
- package/dist/dts/HttpApiError.d.ts.map +1 -1
- package/dist/dts/HttpApiGroup.d.ts +96 -194
- package/dist/dts/HttpApiGroup.d.ts.map +1 -1
- package/dist/dts/HttpApiMiddleware.d.ts +231 -0
- package/dist/dts/HttpApiMiddleware.d.ts.map +1 -0
- package/dist/dts/HttpApiSchema.d.ts +6 -2
- package/dist/dts/HttpApiSchema.d.ts.map +1 -1
- package/dist/dts/HttpApiSecurity.d.ts +1 -1
- package/dist/dts/HttpApiSecurity.d.ts.map +1 -1
- package/dist/dts/HttpApiSwagger.d.ts +2 -2
- package/dist/dts/HttpApiSwagger.d.ts.map +1 -1
- package/dist/dts/HttpBody.d.ts +2 -2
- package/dist/dts/HttpBody.d.ts.map +1 -1
- package/dist/dts/HttpClientRequest.d.ts +2 -2
- package/dist/dts/HttpClientRequest.d.ts.map +1 -1
- package/dist/dts/HttpClientResponse.d.ts +3 -3
- package/dist/dts/HttpClientResponse.d.ts.map +1 -1
- package/dist/dts/HttpIncomingMessage.d.ts +3 -3
- package/dist/dts/HttpIncomingMessage.d.ts.map +1 -1
- package/dist/dts/HttpRouter.d.ts +3 -3
- package/dist/dts/HttpRouter.d.ts.map +1 -1
- package/dist/dts/HttpServer.d.ts +15 -0
- package/dist/dts/HttpServer.d.ts.map +1 -1
- package/dist/dts/HttpServerRequest.d.ts +3 -3
- package/dist/dts/HttpServerRequest.d.ts.map +1 -1
- package/dist/dts/HttpServerRespondable.d.ts.map +1 -1
- package/dist/dts/HttpServerResponse.d.ts +2 -2
- package/dist/dts/HttpServerResponse.d.ts.map +1 -1
- package/dist/dts/KeyValueStore.d.ts +2 -2
- package/dist/dts/KeyValueStore.d.ts.map +1 -1
- package/dist/dts/Multipart.d.ts +3 -3
- package/dist/dts/Multipart.d.ts.map +1 -1
- package/dist/dts/OpenApi.d.ts +17 -39
- package/dist/dts/OpenApi.d.ts.map +1 -1
- package/dist/dts/OpenApiJsonSchema.d.ts +10 -5
- package/dist/dts/OpenApiJsonSchema.d.ts.map +1 -1
- package/dist/dts/Transferable.d.ts +4 -1
- package/dist/dts/Transferable.d.ts.map +1 -1
- package/dist/dts/UrlParams.d.ts +3 -6
- package/dist/dts/UrlParams.d.ts.map +1 -1
- package/dist/dts/Worker.d.ts +7 -8
- package/dist/dts/Worker.d.ts.map +1 -1
- package/dist/dts/WorkerError.d.ts +1 -1
- package/dist/dts/WorkerError.d.ts.map +1 -1
- package/dist/dts/WorkerRunner.d.ts +2 -3
- package/dist/dts/WorkerRunner.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/httpRouter.d.ts.map +1 -1
- package/dist/esm/Headers.js +7 -2
- package/dist/esm/Headers.js.map +1 -1
- package/dist/esm/HttpApi.js +88 -77
- package/dist/esm/HttpApi.js.map +1 -1
- package/dist/esm/HttpApiBuilder.js +236 -244
- package/dist/esm/HttpApiBuilder.js.map +1 -1
- package/dist/esm/HttpApiClient.js +64 -59
- package/dist/esm/HttpApiClient.js.map +1 -1
- package/dist/esm/HttpApiEndpoint.js +73 -106
- package/dist/esm/HttpApiEndpoint.js.map +1 -1
- package/dist/esm/HttpApiError.js +3 -4
- package/dist/esm/HttpApiError.js.map +1 -1
- package/dist/esm/HttpApiGroup.js +102 -99
- package/dist/esm/HttpApiGroup.js.map +1 -1
- package/dist/esm/HttpApiMiddleware.js +56 -0
- package/dist/esm/HttpApiMiddleware.js.map +1 -0
- package/dist/esm/HttpApiSchema.js +31 -5
- package/dist/esm/HttpApiSchema.js.map +1 -1
- package/dist/esm/HttpApiSecurity.js +1 -1
- package/dist/esm/HttpApiSecurity.js.map +1 -1
- package/dist/esm/HttpApiSwagger.js +4 -2
- package/dist/esm/HttpApiSwagger.js.map +1 -1
- package/dist/esm/HttpBody.js.map +1 -1
- package/dist/esm/HttpIncomingMessage.js +4 -1
- package/dist/esm/HttpIncomingMessage.js.map +1 -1
- package/dist/esm/HttpServer.js +11 -0
- package/dist/esm/HttpServer.js.map +1 -1
- package/dist/esm/HttpServerRespondable.js +1 -1
- package/dist/esm/HttpServerRespondable.js.map +1 -1
- package/dist/esm/OpenApi.js +97 -59
- package/dist/esm/OpenApi.js.map +1 -1
- package/dist/esm/OpenApiJsonSchema.js +56 -46
- package/dist/esm/OpenApiJsonSchema.js.map +1 -1
- package/dist/esm/Transferable.js +2 -2
- package/dist/esm/Transferable.js.map +1 -1
- package/dist/esm/UrlParams.js +4 -1
- package/dist/esm/UrlParams.js.map +1 -1
- package/dist/esm/Worker.js.map +1 -1
- package/dist/esm/WorkerError.js +1 -4
- package/dist/esm/WorkerError.js.map +1 -1
- package/dist/esm/WorkerRunner.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/httpBody.js +1 -1
- package/dist/esm/internal/httpBody.js.map +1 -1
- package/dist/esm/internal/httpClientRequest.js.map +1 -1
- package/dist/esm/internal/httpClientResponse.js +1 -1
- package/dist/esm/internal/httpClientResponse.js.map +1 -1
- package/dist/esm/internal/httpRouter.js +1 -1
- package/dist/esm/internal/httpRouter.js.map +1 -1
- package/dist/esm/internal/httpServer.js +6 -0
- package/dist/esm/internal/httpServer.js.map +1 -1
- package/dist/esm/internal/httpServerRequest.js +1 -1
- package/dist/esm/internal/httpServerRequest.js.map +1 -1
- package/dist/esm/internal/httpServerResponse.js.map +1 -1
- package/dist/esm/internal/keyValueStore.js +1 -1
- package/dist/esm/internal/keyValueStore.js.map +1 -1
- package/dist/esm/internal/multipart.js +1 -1
- package/dist/esm/internal/multipart.js.map +1 -1
- package/dist/esm/internal/worker.js +6 -7
- package/dist/esm/internal/worker.js.map +1 -1
- package/dist/esm/internal/workerRunner.js +3 -4
- package/dist/esm/internal/workerRunner.js.map +1 -1
- package/package.json +10 -3
- package/src/Headers.ts +12 -4
- package/src/HttpApi.ts +183 -258
- package/src/HttpApiBuilder.ts +532 -481
- package/src/HttpApiClient.ts +163 -112
- package/src/HttpApiEndpoint.ts +443 -564
- package/src/HttpApiError.ts +4 -6
- package/src/HttpApiGroup.ts +277 -325
- package/src/HttpApiMiddleware.ts +318 -0
- package/src/HttpApiSchema.ts +39 -2
- package/src/HttpApiSecurity.ts +1 -1
- package/src/HttpApiSwagger.ts +3 -3
- package/src/HttpBody.ts +2 -2
- package/src/HttpClientRequest.ts +2 -2
- package/src/HttpClientResponse.ts +3 -3
- package/src/HttpIncomingMessage.ts +3 -3
- package/src/HttpRouter.ts +3 -3
- package/src/HttpServer.ts +21 -0
- package/src/HttpServerRequest.ts +3 -3
- package/src/HttpServerRespondable.ts +1 -1
- package/src/HttpServerResponse.ts +2 -2
- package/src/KeyValueStore.ts +2 -2
- package/src/Multipart.ts +3 -3
- package/src/OpenApi.ts +113 -104
- package/src/OpenApiJsonSchema.ts +67 -53
- package/src/Transferable.ts +2 -2
- package/src/UrlParams.ts +3 -3
- package/src/Worker.ts +7 -8
- package/src/WorkerError.ts +1 -1
- package/src/WorkerRunner.ts +2 -3
- package/src/index.ts +5 -0
- package/src/internal/httpBody.ts +2 -2
- package/src/internal/httpClientRequest.ts +2 -2
- package/src/internal/httpClientResponse.ts +3 -3
- package/src/internal/httpRouter.ts +2 -2
- package/src/internal/httpServer.ts +13 -0
- package/src/internal/httpServerRequest.ts +3 -3
- package/src/internal/httpServerResponse.ts +2 -2
- package/src/internal/keyValueStore.ts +1 -1
- package/src/internal/multipart.ts +3 -3
- package/src/internal/worker.ts +6 -7
- package/src/internal/workerRunner.ts +3 -4
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Let's define a simple CRUD API for managing users. First, we need to make an
|
|
|
32
32
|
|
|
33
33
|
```ts
|
|
34
34
|
import { HttpApiEndpoint, HttpApiGroup } from "@effect/platform"
|
|
35
|
-
import { Schema } from "
|
|
35
|
+
import { Schema } from "effect"
|
|
36
36
|
|
|
37
37
|
// Our domain "User" Schema
|
|
38
38
|
class User extends Schema.Class<User>("User")({
|
|
@@ -41,58 +41,52 @@ class User extends Schema.Class<User>("User")({
|
|
|
41
41
|
createdAt: Schema.DateTimeUtc
|
|
42
42
|
}) {}
|
|
43
43
|
|
|
44
|
-
const usersApi = HttpApiGroup.make("users")
|
|
45
|
-
|
|
44
|
+
const usersApi = HttpApiGroup.make("users")
|
|
45
|
+
.add(
|
|
46
46
|
// each endpoint has a name and a path
|
|
47
|
-
HttpApiEndpoint.get("findById", "/users/:id")
|
|
47
|
+
HttpApiEndpoint.get("findById", "/users/:id")
|
|
48
48
|
// the endpoint can have a Schema for a successful response
|
|
49
|
-
|
|
49
|
+
.addSuccess(User)
|
|
50
50
|
// and here is a Schema for the path parameters
|
|
51
|
-
|
|
51
|
+
.setPath(
|
|
52
52
|
Schema.Struct({
|
|
53
53
|
id: Schema.NumberFromString
|
|
54
54
|
})
|
|
55
55
|
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
HttpApiEndpoint.setSuccess(User),
|
|
56
|
+
)
|
|
57
|
+
.add(
|
|
58
|
+
HttpApiEndpoint.post("create", "/users")
|
|
59
|
+
.addSuccess(User)
|
|
61
60
|
// and here is a Schema for the request payload / body
|
|
62
61
|
//
|
|
63
62
|
// this is a POST request, so the payload is in the body
|
|
64
63
|
// but for a GET request, the payload would be in the URL search params
|
|
65
|
-
|
|
64
|
+
.setPayload(
|
|
66
65
|
Schema.Struct({
|
|
67
66
|
name: Schema.String
|
|
68
67
|
})
|
|
69
68
|
)
|
|
70
|
-
|
|
71
|
-
),
|
|
69
|
+
)
|
|
72
70
|
// by default, the endpoint will respond with a 204 No Content
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
HttpApiEndpoint.patch("update", "/users/:id")
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
.add(HttpApiEndpoint.del("delete", "/users/:id"))
|
|
72
|
+
.add(
|
|
73
|
+
HttpApiEndpoint.patch("update", "/users/:id")
|
|
74
|
+
.addSuccess(User)
|
|
75
|
+
.setPayload(
|
|
78
76
|
Schema.Struct({
|
|
79
77
|
name: Schema.String
|
|
80
78
|
})
|
|
81
79
|
)
|
|
82
|
-
)
|
|
83
80
|
)
|
|
84
|
-
)
|
|
85
81
|
```
|
|
86
82
|
|
|
87
83
|
You can also extend the `HttpApiGroup` with a class to gain an opaque type.
|
|
88
84
|
We will use this API style in the following examples:
|
|
89
85
|
|
|
90
86
|
```ts
|
|
91
|
-
class UsersApi extends HttpApiGroup.make("users").
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// ... same as above
|
|
95
|
-
)
|
|
87
|
+
class UsersApi extends HttpApiGroup.make("users").add(
|
|
88
|
+
HttpApiEndpoint.get("findById", "/users/:id")
|
|
89
|
+
// ... same as above
|
|
96
90
|
) {}
|
|
97
91
|
```
|
|
98
92
|
|
|
@@ -103,13 +97,13 @@ Once you have defined your groups, you can combine them into a single `HttpApi`.
|
|
|
103
97
|
```ts
|
|
104
98
|
import { HttpApi } from "@effect/platform"
|
|
105
99
|
|
|
106
|
-
class MyApi extends HttpApi.empty.
|
|
100
|
+
class MyApi extends HttpApi.empty.add(UsersApi) {}
|
|
107
101
|
```
|
|
108
102
|
|
|
109
103
|
Or with the non-opaque style:
|
|
110
104
|
|
|
111
105
|
```ts
|
|
112
|
-
const api = HttpApi.empty.
|
|
106
|
+
const api = HttpApi.empty.add(usersApi)
|
|
113
107
|
```
|
|
114
108
|
|
|
115
109
|
### Adding OpenApi annotations
|
|
@@ -121,17 +115,21 @@ Let's add a title to our `UsersApi` group:
|
|
|
121
115
|
```ts
|
|
122
116
|
import { OpenApi } from "@effect/platform"
|
|
123
117
|
|
|
124
|
-
class UsersApi extends HttpApiGroup.make("users")
|
|
125
|
-
|
|
118
|
+
class UsersApi extends HttpApiGroup.make("users")
|
|
119
|
+
.add(
|
|
126
120
|
HttpApiEndpoint.get("findById", "/users/:id")
|
|
127
121
|
// ... same as above
|
|
128
|
-
)
|
|
122
|
+
)
|
|
129
123
|
// add an OpenApi title & description
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
// You can set one attribute at a time
|
|
125
|
+
.annotate(OpenApi.Title, "Users API")
|
|
126
|
+
// or multiple at once
|
|
127
|
+
.annotateContext(
|
|
128
|
+
OpenApi.annotations({
|
|
129
|
+
title: "Users API",
|
|
130
|
+
description: "API for managing users"
|
|
131
|
+
})
|
|
132
|
+
) {}
|
|
135
133
|
```
|
|
136
134
|
|
|
137
135
|
Now when you generate OpenApi documentation, the title and description will be
|
|
@@ -140,13 +138,9 @@ included.
|
|
|
140
138
|
You can also add OpenApi annotations to the top-level `HttpApi`:
|
|
141
139
|
|
|
142
140
|
```ts
|
|
143
|
-
class MyApi extends HttpApi.empty
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
title: "My API",
|
|
147
|
-
description: "My awesome API"
|
|
148
|
-
})
|
|
149
|
-
) {}
|
|
141
|
+
class MyApi extends HttpApi.empty
|
|
142
|
+
.add(UsersApi)
|
|
143
|
+
.annotate(OpenApi.Title, "My API") {}
|
|
150
144
|
```
|
|
151
145
|
|
|
152
146
|
### Adding errors
|
|
@@ -174,18 +168,16 @@ class Unauthorized extends Schema.TaggedError<Unauthorized>()(
|
|
|
174
168
|
{}
|
|
175
169
|
) {}
|
|
176
170
|
|
|
177
|
-
class UsersApi extends HttpApiGroup.make("users")
|
|
178
|
-
|
|
179
|
-
HttpApiEndpoint.get("findById", "/users/:id")
|
|
171
|
+
class UsersApi extends HttpApiGroup.make("users")
|
|
172
|
+
.add(
|
|
173
|
+
HttpApiEndpoint.get("findById", "/users/:id")
|
|
180
174
|
// here we are adding our error response
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
),
|
|
175
|
+
.addError(UserNotFound, { status: 404 })
|
|
176
|
+
.addSuccess(User)
|
|
177
|
+
.setPath(Schema.Struct({ id: Schema.NumberFromString }))
|
|
178
|
+
)
|
|
186
179
|
// or we could add an error to the group
|
|
187
|
-
|
|
188
|
-
) {}
|
|
180
|
+
.addError(Unauthorized, { status: 401 }) {}
|
|
189
181
|
```
|
|
190
182
|
|
|
191
183
|
It is worth noting that you can add multiple error responses to an endpoint,
|
|
@@ -202,62 +194,18 @@ shape of the multipart request.
|
|
|
202
194
|
```ts
|
|
203
195
|
import { HttpApiSchema, Multipart } from "@effect/platform"
|
|
204
196
|
|
|
205
|
-
class UsersApi extends HttpApiGroup.make("users").
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
files: Multipart.FilesSchema
|
|
213
|
-
})
|
|
214
|
-
)
|
|
215
|
-
)
|
|
197
|
+
class UsersApi extends HttpApiGroup.make("users").add(
|
|
198
|
+
HttpApiEndpoint.post("upload", "/users/upload").setPayload(
|
|
199
|
+
HttpApiSchema.Multipart(
|
|
200
|
+
Schema.Struct({
|
|
201
|
+
// add a "files" field to the schema
|
|
202
|
+
files: Multipart.FilesSchema
|
|
203
|
+
})
|
|
216
204
|
)
|
|
217
205
|
)
|
|
218
206
|
) {}
|
|
219
207
|
```
|
|
220
208
|
|
|
221
|
-
### Adding security annotations
|
|
222
|
-
|
|
223
|
-
The `HttpApiSecurity` module provides a way to add security annotations to your
|
|
224
|
-
API.
|
|
225
|
-
|
|
226
|
-
It offers the following authorization types:
|
|
227
|
-
|
|
228
|
-
- `HttpApiSecurity.apiKey` - API key authorization through headers, query
|
|
229
|
-
parameters, or cookies.
|
|
230
|
-
- `HttpApiSecurity.basicAuth` - HTTP Basic authentication.
|
|
231
|
-
- `HttpApiSecurity.bearerAuth` - Bearer token authentication.
|
|
232
|
-
|
|
233
|
-
You can annotate your API with these security types using the
|
|
234
|
-
`OpenApi.annotate` api as before.
|
|
235
|
-
|
|
236
|
-
```ts
|
|
237
|
-
import { HttpApiSecurity } from "@effect/platform"
|
|
238
|
-
|
|
239
|
-
const security = HttpApiSecurity.apiKey({
|
|
240
|
-
in: "cookie",
|
|
241
|
-
key: "token"
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
class UsersApi extends HttpApiGroup.make("users").pipe(
|
|
245
|
-
HttpApiGroup.add(
|
|
246
|
-
HttpApiEndpoint.get("findById", "/users/:id").pipe(
|
|
247
|
-
// add the security annotation to the endpoint
|
|
248
|
-
OpenApi.annotate({ security })
|
|
249
|
-
)
|
|
250
|
-
),
|
|
251
|
-
// or at the group level
|
|
252
|
-
OpenApi.annotate({ security }),
|
|
253
|
-
|
|
254
|
-
// or just for the endpoints above this line
|
|
255
|
-
HttpApiGroup.annotateEndpoints(OpenApi.Security, security),
|
|
256
|
-
// this endpoint will not have the security annotation
|
|
257
|
-
HttpApiGroup.add(HttpApiEndpoint.get("list", "/users"))
|
|
258
|
-
) {}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
209
|
### Changing the response encoding
|
|
262
210
|
|
|
263
211
|
By default, the response is encoded as JSON. You can change the encoding using
|
|
@@ -266,17 +214,13 @@ the `HttpApiSchema.withEncoding` api.
|
|
|
266
214
|
Here is an example of changing the encoding to text/csv:
|
|
267
215
|
|
|
268
216
|
```ts
|
|
269
|
-
class UsersApi extends HttpApiGroup.make("users").
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
contentType: "text/csv"
|
|
277
|
-
})
|
|
278
|
-
)
|
|
279
|
-
)
|
|
217
|
+
class UsersApi extends HttpApiGroup.make("users").add(
|
|
218
|
+
HttpApiEndpoint.get("csv", "/users/csv").addSuccess(
|
|
219
|
+
Schema.String.pipe(
|
|
220
|
+
HttpApiSchema.withEncoding({
|
|
221
|
+
kind: "Text",
|
|
222
|
+
contentType: "text/csv"
|
|
223
|
+
})
|
|
280
224
|
)
|
|
281
225
|
)
|
|
282
226
|
) {}
|
|
@@ -306,8 +250,7 @@ import {
|
|
|
306
250
|
HttpApiEndpoint,
|
|
307
251
|
HttpApiGroup
|
|
308
252
|
} from "@effect/platform"
|
|
309
|
-
import { Schema } from "
|
|
310
|
-
import { DateTime, Effect } from "effect"
|
|
253
|
+
import { DateTime, Effect, Layer, Schema } from "effect"
|
|
311
254
|
|
|
312
255
|
// here is our api definition
|
|
313
256
|
class User extends Schema.Class<User>("User")({
|
|
@@ -316,31 +259,28 @@ class User extends Schema.Class<User>("User")({
|
|
|
316
259
|
createdAt: Schema.DateTimeUtc
|
|
317
260
|
}) {}
|
|
318
261
|
|
|
319
|
-
class UsersApi extends HttpApiGroup.make("users").
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
Schema.
|
|
325
|
-
|
|
326
|
-
})
|
|
327
|
-
)
|
|
262
|
+
class UsersApi extends HttpApiGroup.make("users").add(
|
|
263
|
+
HttpApiEndpoint.get("findById", "/users/:id")
|
|
264
|
+
.addSuccess(User)
|
|
265
|
+
.setPath(
|
|
266
|
+
Schema.Struct({
|
|
267
|
+
id: Schema.NumberFromString
|
|
268
|
+
})
|
|
328
269
|
)
|
|
329
|
-
)
|
|
330
270
|
) {}
|
|
331
271
|
|
|
332
|
-
class MyApi extends HttpApi.empty.
|
|
272
|
+
class MyApi extends HttpApi.empty.add(UsersApi) {}
|
|
333
273
|
|
|
334
274
|
// --------------------------------------------
|
|
335
275
|
// Implementation
|
|
336
276
|
// --------------------------------------------
|
|
337
277
|
|
|
338
278
|
// the `HttpApiBuilder.group` api returns a `Layer`
|
|
339
|
-
const UsersApiLive: Layer.Layer<HttpApiGroup.
|
|
279
|
+
const UsersApiLive: Layer.Layer<HttpApiGroup.Group<"users">> =
|
|
340
280
|
HttpApiBuilder.group(MyApi, "users", (handlers) =>
|
|
341
|
-
handlers
|
|
281
|
+
handlers
|
|
342
282
|
// the parameters & payload are passed to the handler function.
|
|
343
|
-
|
|
283
|
+
.handle("findById", ({ path: { id } }) =>
|
|
344
284
|
Effect.succeed(
|
|
345
285
|
new User({
|
|
346
286
|
id,
|
|
@@ -349,7 +289,6 @@ const UsersApiLive: Layer.Layer<HttpApiGroup.HttpApiGroup.Service<"users">> =
|
|
|
349
289
|
})
|
|
350
290
|
)
|
|
351
291
|
)
|
|
352
|
-
)
|
|
353
292
|
)
|
|
354
293
|
```
|
|
355
294
|
|
|
@@ -368,17 +307,15 @@ class UsersRepository extends Context.Tag("UsersRepository")<
|
|
|
368
307
|
|
|
369
308
|
// the dependencies will show up in the resulting `Layer`
|
|
370
309
|
const UsersApiLive: Layer.Layer<
|
|
371
|
-
HttpApiGroup.
|
|
310
|
+
HttpApiGroup.Group<"users">,
|
|
372
311
|
never,
|
|
373
312
|
UsersRepository
|
|
374
313
|
> = HttpApiBuilder.group(MyApi, "users", (handlers) =>
|
|
375
314
|
// we can return an Effect that creates our handlers
|
|
376
315
|
Effect.gen(function* () {
|
|
377
316
|
const repository = yield* UsersRepository
|
|
378
|
-
return handlers.
|
|
379
|
-
|
|
380
|
-
repository.findById(id)
|
|
381
|
-
)
|
|
317
|
+
return handlers.handle("findById", ({ path: { id } }) =>
|
|
318
|
+
repository.findById(id)
|
|
382
319
|
)
|
|
383
320
|
})
|
|
384
321
|
)
|
|
@@ -392,9 +329,9 @@ This is done using the `HttpApiBuilder.api` api, and then using `Layer.provide`
|
|
|
392
329
|
to add all the group implementations.
|
|
393
330
|
|
|
394
331
|
```ts
|
|
395
|
-
const MyApiLive: Layer.Layer<HttpApi.
|
|
396
|
-
|
|
397
|
-
)
|
|
332
|
+
const MyApiLive: Layer.Layer<HttpApi.Api> = HttpApiBuilder.api(MyApi).pipe(
|
|
333
|
+
Layer.provide(UsersApiLive)
|
|
334
|
+
)
|
|
398
335
|
```
|
|
399
336
|
|
|
400
337
|
### Serving the API
|
|
@@ -426,71 +363,241 @@ const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
|
|
|
426
363
|
Layer.launch(HttpLive).pipe(NodeRuntime.runMain)
|
|
427
364
|
```
|
|
428
365
|
|
|
429
|
-
|
|
366
|
+
### Serving Swagger documentation
|
|
430
367
|
|
|
431
|
-
|
|
432
|
-
definition to implement a middleware that will protect your endpoints.
|
|
368
|
+
You can add Swagger documentation to your API using the `HttpApiSwagger` module.
|
|
433
369
|
|
|
434
|
-
|
|
435
|
-
|
|
370
|
+
You just need to provide the `HttpApiSwagger.layer` to your server
|
|
371
|
+
implementation:
|
|
436
372
|
|
|
437
|
-
|
|
373
|
+
```ts
|
|
374
|
+
import { HttpApiSwagger } from "@effect/platform"
|
|
375
|
+
|
|
376
|
+
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
|
|
377
|
+
// add the swagger documentation layer
|
|
378
|
+
Layer.provide(
|
|
379
|
+
HttpApiSwagger.layer({
|
|
380
|
+
// "/docs" is the default path for the swagger documentation
|
|
381
|
+
path: "/docs"
|
|
382
|
+
})
|
|
383
|
+
),
|
|
384
|
+
Layer.provide(HttpApiBuilder.middlewareCors()),
|
|
385
|
+
Layer.provide(MyApiLive),
|
|
386
|
+
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
|
|
387
|
+
)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Adding middleware
|
|
391
|
+
|
|
392
|
+
### Defining middleware
|
|
393
|
+
|
|
394
|
+
The `HttpApiMiddleware` module provides a way to add middleware to your API.
|
|
395
|
+
|
|
396
|
+
You can create a `HttpApiMiddleware.Tag` that represents your middleware, which
|
|
397
|
+
allows you to set:
|
|
398
|
+
|
|
399
|
+
- `failure` - a Schema for any errors that the middleware can return
|
|
400
|
+
- `provides` - a `Context.Tag` that the middleware will provide
|
|
401
|
+
- `security` - `HttpApiSecurity` definitions that the middleware will
|
|
402
|
+
implement
|
|
403
|
+
- `optional` - a boolean that indicates that if the middleware fails with an
|
|
404
|
+
expected error, the request should continue. When using optional middleware,
|
|
405
|
+
`provides` & `failure` options will not affect the handlers or final error type.
|
|
406
|
+
|
|
407
|
+
Here is an example of defining a simple logger middleware:
|
|
438
408
|
|
|
439
409
|
```ts
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
410
|
+
import {
|
|
411
|
+
HttpApiEndpoint,
|
|
412
|
+
HttpApiGroup,
|
|
413
|
+
HttpApiMiddleware
|
|
414
|
+
} from "@effect/platform"
|
|
415
|
+
import { Schema } from "effect"
|
|
445
416
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
>() {
|
|
417
|
+
class LoggerError extends Schema.TaggedError<LoggerError>()(
|
|
418
|
+
"LoggerError",
|
|
419
|
+
{}
|
|
420
|
+
) {}
|
|
421
|
+
|
|
422
|
+
// first extend the HttpApiMiddleware.Tag class
|
|
423
|
+
class Logger extends HttpApiMiddleware.Tag<Logger>()("Http/Logger", {
|
|
424
|
+
// optionally define any errors that the middleware can return
|
|
425
|
+
failure: LoggerError
|
|
426
|
+
}) {}
|
|
427
|
+
|
|
428
|
+
// apply the middleware to an `HttpApiGroup`
|
|
429
|
+
class UsersApi extends HttpApiGroup.make("users")
|
|
430
|
+
.add(
|
|
431
|
+
HttpApiEndpoint.get("findById", "/:id")
|
|
432
|
+
// apply the middleware to a single endpoint
|
|
433
|
+
.middleware(Logger)
|
|
434
|
+
)
|
|
435
|
+
// or apply the middleware to the group
|
|
436
|
+
.middleware(Logger) {}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Defining security middleware
|
|
440
|
+
|
|
441
|
+
The `HttpApiSecurity` module provides a way to add security annotations to your
|
|
442
|
+
API.
|
|
443
|
+
|
|
444
|
+
It offers the following authorization types:
|
|
445
|
+
|
|
446
|
+
- `HttpApiSecurity.apiKey` - API key authorization through headers, query
|
|
447
|
+
parameters, or cookies.
|
|
448
|
+
- `HttpApiSecurity.basicAuth` - HTTP Basic authentication.
|
|
449
|
+
- `HttpApiSecurity.bearerAuth` - Bearer token authentication.
|
|
450
|
+
|
|
451
|
+
You can then use these security annotations in combination with `HttpApiMiddleware`
|
|
452
|
+
to define middleware that will protect your endpoints.
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
import {
|
|
456
|
+
HttpApiGroup,
|
|
457
|
+
HttpApiEndpoint,
|
|
458
|
+
HttpApiMiddleware,
|
|
459
|
+
HttpApiSchema,
|
|
460
|
+
HttpApiSecurity
|
|
461
|
+
} from "@effect/platform"
|
|
462
|
+
import { Context, Schema } from "effect"
|
|
463
|
+
|
|
464
|
+
class User extends Schema.Class<User>("User")({ id: Schema.Number }) {}
|
|
465
|
+
|
|
466
|
+
class Unauthorized extends Schema.TaggedError<Unauthorized>()(
|
|
467
|
+
"Unauthorized",
|
|
468
|
+
{},
|
|
469
|
+
HttpApiSchema.annotations({ status: 401 })
|
|
470
|
+
) {}
|
|
453
471
|
|
|
454
|
-
// the security middleware will supply the current user to the handlers
|
|
455
472
|
class CurrentUser extends Context.Tag("CurrentUser")<CurrentUser, User>() {}
|
|
456
473
|
|
|
457
|
-
//
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
// the security
|
|
466
|
-
security
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
474
|
+
// first extend the HttpApiMiddleware.Tag class
|
|
475
|
+
class Authorization extends HttpApiMiddleware.Tag<Authorization>()(
|
|
476
|
+
"Authorization",
|
|
477
|
+
{
|
|
478
|
+
// add your error schema
|
|
479
|
+
failure: Unauthorized,
|
|
480
|
+
// add the Context.Tag that the middleware will provide
|
|
481
|
+
provides: CurrentUser,
|
|
482
|
+
// add the security definitions
|
|
483
|
+
security: {
|
|
484
|
+
// the object key is a custom name for the security definition
|
|
485
|
+
myBearer: HttpApiSecurity.bearer
|
|
486
|
+
// You can add more security definitions here.
|
|
487
|
+
// They will attempt to be resolved in the order they are defined
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
) {}
|
|
491
|
+
|
|
492
|
+
// apply the middleware to an `HttpApiGroup`
|
|
493
|
+
class UsersApi extends HttpApiGroup.make("users")
|
|
494
|
+
.add(
|
|
495
|
+
HttpApiEndpoint.get("findById", "/:id")
|
|
496
|
+
// apply the middleware to a single endpoint
|
|
497
|
+
.middleware(Authorization)
|
|
471
498
|
)
|
|
472
|
-
|
|
499
|
+
// or apply the middleware to the group
|
|
500
|
+
.middleware(Authorization) {}
|
|
501
|
+
```
|
|
473
502
|
|
|
474
|
-
|
|
475
|
-
const UsersApiLive = HttpApiBuilder.group(MyApi, "users", (handlers) =>
|
|
476
|
-
Effect.gen(function* () {
|
|
477
|
-
// construct the security middleware
|
|
478
|
-
const securityMiddleware = yield* makeSecurityMiddleware
|
|
503
|
+
### Implementing `HttpApiMiddleware`
|
|
479
504
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
505
|
+
Once your `HttpApiMiddleware` is defined, you can use the
|
|
506
|
+
`HttpApiMiddleware.Tag` definition to implement your middleware.
|
|
507
|
+
|
|
508
|
+
By using the `Layer` apis, you can create a Layer that implements your
|
|
509
|
+
middleware.
|
|
510
|
+
|
|
511
|
+
Here is an example:
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
import { HttpApiMiddleware, HttpServerRequest } from "@effect/platform"
|
|
515
|
+
import { Effect, Layer } from "effect"
|
|
516
|
+
|
|
517
|
+
class Logger extends HttpApiMiddleware.Tag<Logger>()("Http/Logger") {}
|
|
518
|
+
|
|
519
|
+
const LoggerLive = Layer.effect(
|
|
520
|
+
Logger,
|
|
521
|
+
Effect.gen(function* () {
|
|
522
|
+
yield* Effect.log("creating Logger middleware")
|
|
523
|
+
|
|
524
|
+
// standard middleware is just an Effect, that can access the `HttpRouter`
|
|
525
|
+
// context.
|
|
526
|
+
return Logger.of(
|
|
527
|
+
Effect.gen(function* () {
|
|
528
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
529
|
+
yield* Effect.log(`Request: ${request.method} ${request.url}`)
|
|
530
|
+
})
|
|
489
531
|
)
|
|
490
532
|
})
|
|
491
533
|
)
|
|
492
534
|
```
|
|
493
535
|
|
|
536
|
+
When the `Layer` is created, you can then provide it to your group layers:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
const UsersApiLive = HttpApiBuilder.group(...).pipe(
|
|
540
|
+
Layer.provide(LoggerLive)
|
|
541
|
+
)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### Implementing `HttpApiSecurity` middleware
|
|
545
|
+
|
|
546
|
+
If you are using `HttpApiSecurity` in your middleware, implementing the `Layer`
|
|
547
|
+
looks a bit different.
|
|
548
|
+
|
|
549
|
+
Here is an example of implementing a `HttpApiSecurity.bearer` middleware:
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
import {
|
|
553
|
+
HttpApiMiddleware,
|
|
554
|
+
HttpApiSchema,
|
|
555
|
+
HttpApiSecurity
|
|
556
|
+
} from "@effect/platform"
|
|
557
|
+
import { Context, Effect, Layer, Redacted, Schema } from "effect"
|
|
558
|
+
|
|
559
|
+
class User extends Schema.Class<User>("User")({ id: Schema.Number }) {}
|
|
560
|
+
|
|
561
|
+
class Unauthorized extends Schema.TaggedError<Unauthorized>()(
|
|
562
|
+
"Unauthorized",
|
|
563
|
+
{},
|
|
564
|
+
HttpApiSchema.annotations({ status: 401 })
|
|
565
|
+
) {}
|
|
566
|
+
|
|
567
|
+
class CurrentUser extends Context.Tag("CurrentUser")<CurrentUser, User>() {}
|
|
568
|
+
|
|
569
|
+
class Authorization extends HttpApiMiddleware.Tag<Authorization>()(
|
|
570
|
+
"Authorization",
|
|
571
|
+
{
|
|
572
|
+
failure: Unauthorized,
|
|
573
|
+
provides: CurrentUser,
|
|
574
|
+
security: { myBearer: HttpApiSecurity.bearer }
|
|
575
|
+
}
|
|
576
|
+
) {}
|
|
577
|
+
|
|
578
|
+
const AuthorizationLive = Layer.effect(
|
|
579
|
+
Authorization,
|
|
580
|
+
Effect.gen(function* () {
|
|
581
|
+
yield* Effect.log("creating Authorization middleware")
|
|
582
|
+
|
|
583
|
+
// return the security handlers
|
|
584
|
+
return Authorization.of({
|
|
585
|
+
myBearer: (bearerToken) =>
|
|
586
|
+
Effect.gen(function* () {
|
|
587
|
+
yield* Effect.log(
|
|
588
|
+
"checking bearer token",
|
|
589
|
+
Redacted.value(bearerToken)
|
|
590
|
+
)
|
|
591
|
+
// return the `User` that will be provided as the `CurrentUser`
|
|
592
|
+
return new User({ id: 1 })
|
|
593
|
+
})
|
|
594
|
+
})
|
|
595
|
+
})
|
|
596
|
+
)
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Setting `HttpApiSecurity` cookies
|
|
600
|
+
|
|
494
601
|
If you need to set the security cookie from within a handler, you can use the
|
|
495
602
|
`HttpApiBuilder.securitySetCookie` api.
|
|
496
603
|
|
|
@@ -503,42 +610,13 @@ const security = HttpApiSecurity.apiKey({
|
|
|
503
610
|
})
|
|
504
611
|
|
|
505
612
|
const UsersApiLive = HttpApiBuilder.group(MyApi, "users", (handlers) =>
|
|
506
|
-
handlers.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
HttpApiBuilder.securitySetCookie(
|
|
510
|
-
security,
|
|
511
|
-
Redacted.make("keep me secret")
|
|
512
|
-
)
|
|
513
|
-
)
|
|
613
|
+
handlers.handle("login", () =>
|
|
614
|
+
// set the security cookie
|
|
615
|
+
HttpApiBuilder.securitySetCookie(security, Redacted.make("keep me secret"))
|
|
514
616
|
)
|
|
515
617
|
)
|
|
516
618
|
```
|
|
517
619
|
|
|
518
|
-
### Serving Swagger documentation
|
|
519
|
-
|
|
520
|
-
You can add Swagger documentation to your API using the `HttpApiSwagger` module.
|
|
521
|
-
|
|
522
|
-
You just need to provide the `HttpApiSwagger.layer` to your server
|
|
523
|
-
implementation:
|
|
524
|
-
|
|
525
|
-
```ts
|
|
526
|
-
import { HttpApiSwagger } from "@effect/platform"
|
|
527
|
-
|
|
528
|
-
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger).pipe(
|
|
529
|
-
// add the swagger documentation layer
|
|
530
|
-
Layer.provide(
|
|
531
|
-
HttpApiSwagger.layer({
|
|
532
|
-
// "/docs" is the default path for the swagger documentation
|
|
533
|
-
path: "/docs"
|
|
534
|
-
})
|
|
535
|
-
),
|
|
536
|
-
Layer.provide(HttpApiBuilder.middlewareCors()),
|
|
537
|
-
Layer.provide(MyApiLive),
|
|
538
|
-
Layer.provide(NodeHttpServer.layer(createServer, { port: 3000 }))
|
|
539
|
-
)
|
|
540
|
-
```
|
|
541
|
-
|
|
542
620
|
## Deriving a client
|
|
543
621
|
|
|
544
622
|
Once you have defined your API, you can derive a client that can interact with
|
|
@@ -1161,7 +1239,7 @@ string {
|
|
|
1161
1239
|
|
|
1162
1240
|
### Decoding Data with Schemas
|
|
1163
1241
|
|
|
1164
|
-
A common use case when fetching data is to validate the received format. For this purpose, the `HttpClientResponse` module is integrated with
|
|
1242
|
+
A common use case when fetching data is to validate the received format. For this purpose, the `HttpClientResponse` module is integrated with `effect/Schema`.
|
|
1165
1243
|
|
|
1166
1244
|
```ts
|
|
1167
1245
|
import {
|
|
@@ -1170,8 +1248,7 @@ import {
|
|
|
1170
1248
|
HttpClientResponse
|
|
1171
1249
|
} from "@effect/platform"
|
|
1172
1250
|
import { NodeRuntime } from "@effect/platform-node"
|
|
1173
|
-
import { Schema } from "
|
|
1174
|
-
import { Console, Effect } from "effect"
|
|
1251
|
+
import { Console, Effect, Schema } from "effect"
|
|
1175
1252
|
|
|
1176
1253
|
const Post = Schema.Struct({
|
|
1177
1254
|
id: Schema.Number,
|
|
@@ -1329,7 +1406,7 @@ Output:
|
|
|
1329
1406
|
|
|
1330
1407
|
### Decoding Data with Schemas
|
|
1331
1408
|
|
|
1332
|
-
A common use case when fetching data is to validate the received format. For this purpose, the `HttpClientResponse` module is integrated with
|
|
1409
|
+
A common use case when fetching data is to validate the received format. For this purpose, the `HttpClientResponse` module is integrated with `effect/Schema`.
|
|
1333
1410
|
|
|
1334
1411
|
```ts
|
|
1335
1412
|
import {
|
|
@@ -1339,8 +1416,7 @@ import {
|
|
|
1339
1416
|
HttpClientResponse
|
|
1340
1417
|
} from "@effect/platform"
|
|
1341
1418
|
import { NodeRuntime } from "@effect/platform-node"
|
|
1342
|
-
import { Schema } from "
|
|
1343
|
-
import { Console, Effect } from "effect"
|
|
1419
|
+
import { Console, Effect, Schema } from "effect"
|
|
1344
1420
|
|
|
1345
1421
|
const Post = Schema.Struct({
|
|
1346
1422
|
id: Schema.Number,
|
|
@@ -1717,8 +1793,7 @@ To define routes with parameters, include the parameter names in the path and us
|
|
|
1717
1793
|
|
|
1718
1794
|
```ts
|
|
1719
1795
|
import { HttpRouter, HttpServer, HttpServerResponse } from "@effect/platform"
|
|
1720
|
-
import { Schema } from "
|
|
1721
|
-
import { Effect } from "effect"
|
|
1796
|
+
import { Effect, Schema } from "effect"
|
|
1722
1797
|
import { listen } from "./listen.js"
|
|
1723
1798
|
|
|
1724
1799
|
// Define the schema for route parameters
|
|
@@ -2408,7 +2483,7 @@ curl -i http://localhost:3000/fail
|
|
|
2408
2483
|
|
|
2409
2484
|
## Validations
|
|
2410
2485
|
|
|
2411
|
-
Validation is a critical aspect of handling HTTP requests to ensure that the data your server receives is as expected. We'll explore how to validate headers and cookies using the `@effect/platform` and
|
|
2486
|
+
Validation is a critical aspect of handling HTTP requests to ensure that the data your server receives is as expected. We'll explore how to validate headers and cookies using the `@effect/platform` and `effect/Schema` libraries, which provide structured and robust methods for these tasks.
|
|
2412
2487
|
|
|
2413
2488
|
### Headers
|
|
2414
2489
|
|
|
@@ -2421,8 +2496,7 @@ import {
|
|
|
2421
2496
|
HttpServerRequest,
|
|
2422
2497
|
HttpServerResponse
|
|
2423
2498
|
} from "@effect/platform"
|
|
2424
|
-
import { Schema } from "
|
|
2425
|
-
import { Effect } from "effect"
|
|
2499
|
+
import { Effect, Schema } from "effect"
|
|
2426
2500
|
import { listen } from "./listen.js"
|
|
2427
2501
|
|
|
2428
2502
|
const router = HttpRouter.empty.pipe(
|
|
@@ -2472,8 +2546,7 @@ import {
|
|
|
2472
2546
|
HttpServerRequest,
|
|
2473
2547
|
HttpServerResponse
|
|
2474
2548
|
} from "@effect/platform"
|
|
2475
|
-
import { Schema } from "
|
|
2476
|
-
import { Effect } from "effect"
|
|
2549
|
+
import { Effect, Schema } from "effect"
|
|
2477
2550
|
import { listen } from "./listen.js"
|
|
2478
2551
|
|
|
2479
2552
|
const router = HttpRouter.empty.pipe(
|