@effect/platform 0.72.2 → 0.73.1
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/README.md +637 -0
- package/Url/package.json +6 -0
- package/dist/cjs/HttpApi.js.map +1 -1
- package/dist/cjs/HttpApiEndpoint.js.map +1 -1
- package/dist/cjs/HttpApiGroup.js.map +1 -1
- package/dist/cjs/HttpClient.js +8 -1
- package/dist/cjs/HttpClient.js.map +1 -1
- package/dist/cjs/HttpMethod.js +24 -1
- package/dist/cjs/HttpMethod.js.map +1 -1
- package/dist/cjs/OpenApi.js +82 -42
- package/dist/cjs/OpenApi.js.map +1 -1
- package/dist/cjs/Runtime.js.map +1 -1
- package/dist/cjs/Url.js +259 -0
- package/dist/cjs/Url.js.map +1 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/httpClient.js +3 -1
- package/dist/cjs/internal/httpClient.js.map +1 -1
- package/dist/dts/HttpApi.d.ts +1 -2
- package/dist/dts/HttpApi.d.ts.map +1 -1
- package/dist/dts/HttpApiBuilder.d.ts +1 -1
- package/dist/dts/HttpApiBuilder.d.ts.map +1 -1
- package/dist/dts/HttpApiEndpoint.d.ts +16 -8
- package/dist/dts/HttpApiEndpoint.d.ts.map +1 -1
- package/dist/dts/HttpApiGroup.d.ts +1 -2
- package/dist/dts/HttpApiGroup.d.ts.map +1 -1
- package/dist/dts/HttpClient.d.ts +22 -0
- package/dist/dts/HttpClient.d.ts.map +1 -1
- package/dist/dts/HttpMethod.d.ts +22 -0
- package/dist/dts/HttpMethod.d.ts.map +1 -1
- package/dist/dts/OpenApi.d.ts +100 -110
- package/dist/dts/OpenApi.d.ts.map +1 -1
- package/dist/dts/Runtime.d.ts +48 -0
- package/dist/dts/Runtime.d.ts.map +1 -1
- package/dist/dts/Url.d.ts +591 -0
- package/dist/dts/Url.d.ts.map +1 -0
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/HttpApi.js.map +1 -1
- package/dist/esm/HttpApiEndpoint.js.map +1 -1
- package/dist/esm/HttpApiGroup.js.map +1 -1
- package/dist/esm/HttpClient.js +7 -0
- package/dist/esm/HttpClient.js.map +1 -1
- package/dist/esm/HttpMethod.js +22 -0
- package/dist/esm/HttpMethod.js.map +1 -1
- package/dist/esm/OpenApi.js +82 -41
- package/dist/esm/OpenApi.js.map +1 -1
- package/dist/esm/Runtime.js.map +1 -1
- package/dist/esm/Url.js +248 -0
- package/dist/esm/Url.js.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/httpClient.js +2 -0
- package/dist/esm/internal/httpClient.js.map +1 -1
- package/package.json +10 -2
- package/src/HttpApi.ts +2 -3
- package/src/HttpApiBuilder.ts +1 -1
- package/src/HttpApiEndpoint.ts +22 -13
- package/src/HttpApiGroup.ts +2 -3
- package/src/HttpClient.ts +28 -0
- package/src/HttpMethod.ts +24 -0
- package/src/OpenApi.ts +174 -181
- package/src/Runtime.ts +48 -0
- package/src/Url.ts +632 -0
- package/src/index.ts +5 -0
- package/src/internal/httpClient.ts +11 -0
package/README.md
CHANGED
|
@@ -5,6 +5,111 @@ Welcome to the documentation for `@effect/platform`, a library designed for crea
|
|
|
5
5
|
> [!WARNING]
|
|
6
6
|
> This documentation focuses on **unstable modules**. For stable modules, refer to the [official website documentation](https://effect.website/docs/guides/platform/introduction).
|
|
7
7
|
|
|
8
|
+
# Running Your Main Program with runMain
|
|
9
|
+
|
|
10
|
+
`runMain` helps you execute a main effect with built-in error handling, logging, and signal management. You can concentrate on your effect while `runMain` looks after finalizing resources, logging errors, and setting exit codes.
|
|
11
|
+
|
|
12
|
+
- **Exit Codes**
|
|
13
|
+
If your effect fails or is interrupted, `runMain` assigns a suitable exit code (for example, `1` for errors and `0` for success).
|
|
14
|
+
- **Logs**
|
|
15
|
+
By default, it records errors. This can be turned off if needed.
|
|
16
|
+
- **Pretty Logging**
|
|
17
|
+
By default, error messages are recorded using a "pretty" format. You can switch this off when required.
|
|
18
|
+
- **Interrupt Handling**
|
|
19
|
+
If the application receives `SIGINT` (Ctrl+C) or a similar signal, `runMain` will interrupt the effect and still run any necessary teardown steps.
|
|
20
|
+
- **Teardown Logic**
|
|
21
|
+
You can rely on the default teardown or define your own. The default sets an exit code of `1` for a non-interrupted failure.
|
|
22
|
+
|
|
23
|
+
## Usage Options
|
|
24
|
+
|
|
25
|
+
When calling `runMain`, pass in a configuration object with these fields (all optional):
|
|
26
|
+
|
|
27
|
+
- `disableErrorReporting`: If `true`, errors are not automatically logged.
|
|
28
|
+
- `disablePrettyLogger`: If `true`, it avoids adding the "pretty" logger.
|
|
29
|
+
- `teardown`: Provide a custom function for finalizing the program. If missing, the default sets exit code `1` for a non-interrupted failure.
|
|
30
|
+
|
|
31
|
+
**Example** (Running a Successful Program)
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { NodeRuntime } from "@effect/platform-node"
|
|
35
|
+
import { Effect } from "effect"
|
|
36
|
+
|
|
37
|
+
const success = Effect.succeed("Hello, World!")
|
|
38
|
+
|
|
39
|
+
NodeRuntime.runMain(success)
|
|
40
|
+
// No Output
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Example** (Running a Failing Program)
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { NodeRuntime } from "@effect/platform-node"
|
|
47
|
+
import { Effect } from "effect"
|
|
48
|
+
|
|
49
|
+
const failure = Effect.fail("Uh oh!")
|
|
50
|
+
|
|
51
|
+
NodeRuntime.runMain(failure)
|
|
52
|
+
/*
|
|
53
|
+
Output:
|
|
54
|
+
[12:43:07.186] ERROR (#0):
|
|
55
|
+
Error: Uh oh!
|
|
56
|
+
*/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Example** (Running a Failing Program Without Pretty Logger)
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { NodeRuntime } from "@effect/platform-node"
|
|
63
|
+
import { Effect } from "effect"
|
|
64
|
+
|
|
65
|
+
const failure = Effect.fail("Uh oh!")
|
|
66
|
+
|
|
67
|
+
NodeRuntime.runMain(failure, { disablePrettyLogger: true })
|
|
68
|
+
/*
|
|
69
|
+
Output:
|
|
70
|
+
timestamp=2025-01-14T11:43:46.276Z level=ERROR fiber=#0 cause="Error: Uh oh!"
|
|
71
|
+
*/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Example** (Running a Failing Program Without Error Reporting)
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { NodeRuntime } from "@effect/platform-node"
|
|
78
|
+
import { Effect } from "effect"
|
|
79
|
+
|
|
80
|
+
const failure = Effect.fail("Uh oh!")
|
|
81
|
+
|
|
82
|
+
NodeRuntime.runMain(failure, { disableErrorReporting: true })
|
|
83
|
+
// No Output
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Example** (Running a Failing Program With Custom Teardown)
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { NodeRuntime } from "@effect/platform-node"
|
|
90
|
+
import { Effect } from "effect"
|
|
91
|
+
|
|
92
|
+
const failure = Effect.fail("Uh oh!")
|
|
93
|
+
|
|
94
|
+
NodeRuntime.runMain(failure, {
|
|
95
|
+
teardown: function customTeardown(exit, onExit) {
|
|
96
|
+
if (exit._tag === "Failure") {
|
|
97
|
+
console.error("Program ended with an error.")
|
|
98
|
+
onExit(1)
|
|
99
|
+
} else {
|
|
100
|
+
console.log("Program finished successfully.")
|
|
101
|
+
onExit(0)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
/*
|
|
106
|
+
Output:
|
|
107
|
+
[12:46:39.871] ERROR (#0):
|
|
108
|
+
Error: Uh oh!
|
|
109
|
+
Program ended with an error.
|
|
110
|
+
*/
|
|
111
|
+
```
|
|
112
|
+
|
|
8
113
|
# HTTP API
|
|
9
114
|
|
|
10
115
|
## Overview
|
|
@@ -4310,3 +4415,535 @@ const handler = HttpApp.toWebHandler(router)
|
|
|
4310
4415
|
const response = await handler(new Request("http://localhost:3000/foo"))
|
|
4311
4416
|
console.log(await response.text()) // Output: content 2
|
|
4312
4417
|
```
|
|
4418
|
+
|
|
4419
|
+
# Url
|
|
4420
|
+
|
|
4421
|
+
The `Url` module provides utilities for constructing and working with `URL` objects in a functional style. It includes:
|
|
4422
|
+
|
|
4423
|
+
- A safe constructor for parsing URLs from strings.
|
|
4424
|
+
- Functions for immutably updating `URL` properties like `host`, `href`, and `search`.
|
|
4425
|
+
- Tools for reading and modifying URL parameters using the `UrlParams` module.
|
|
4426
|
+
- A focus on immutability, creating new `URL` instances for every change.
|
|
4427
|
+
|
|
4428
|
+
## Creating a URL
|
|
4429
|
+
|
|
4430
|
+
### fromString
|
|
4431
|
+
|
|
4432
|
+
This function takes a string and attempts to parse it into a `URL` object. If the string is invalid, it returns an `Either.Left` containing an `IllegalArgumentException` with the error details. Otherwise, it returns an `Either.Right` containing the parsed `URL`.
|
|
4433
|
+
|
|
4434
|
+
You can optionally provide a `base` parameter to resolve relative URLs. When supplied, the function treats the input `url` as relative to the `base`.
|
|
4435
|
+
|
|
4436
|
+
**Example** (Parsing a URL with Optional Base)
|
|
4437
|
+
|
|
4438
|
+
```ts
|
|
4439
|
+
import { Url } from "@effect/platform"
|
|
4440
|
+
import { Either } from "effect"
|
|
4441
|
+
|
|
4442
|
+
// Parse an absolute URL
|
|
4443
|
+
//
|
|
4444
|
+
// ┌─── Either<URL, IllegalArgumentException>
|
|
4445
|
+
// ▼
|
|
4446
|
+
const parsed = Url.fromString("https://example.com/path")
|
|
4447
|
+
|
|
4448
|
+
if (Either.isRight(parsed)) {
|
|
4449
|
+
console.log("Parsed URL:", parsed.right.toString())
|
|
4450
|
+
} else {
|
|
4451
|
+
console.log("Error:", parsed.left.message)
|
|
4452
|
+
}
|
|
4453
|
+
// Output: Parsed URL: https://example.com/path
|
|
4454
|
+
|
|
4455
|
+
// Parse a relative URL with a base
|
|
4456
|
+
const relativeParsed = Url.fromString("/relative-path", "https://example.com")
|
|
4457
|
+
|
|
4458
|
+
if (Either.isRight(relativeParsed)) {
|
|
4459
|
+
console.log("Parsed relative URL:", relativeParsed.right.toString())
|
|
4460
|
+
} else {
|
|
4461
|
+
console.log("Error:", relativeParsed.left.message)
|
|
4462
|
+
}
|
|
4463
|
+
// Output: Parsed relative URL: https://example.com/relative-path
|
|
4464
|
+
```
|
|
4465
|
+
|
|
4466
|
+
## Immutably Changing URL Properties
|
|
4467
|
+
|
|
4468
|
+
The `Url` module offers a set of functions for updating properties of a `URL` object without modifying the original instance. These functions create and return a new `URL` with the specified updates, preserving the immutability of the original.
|
|
4469
|
+
|
|
4470
|
+
### Available Setters
|
|
4471
|
+
|
|
4472
|
+
| Setter | Description |
|
|
4473
|
+
| ------------- | --------------------------------------------------------- |
|
|
4474
|
+
| `setHash` | Updates the hash fragment of the URL. |
|
|
4475
|
+
| `setHost` | Updates the host (domain and port) of the URL. |
|
|
4476
|
+
| `setHostname` | Updates the domain of the URL without modifying the port. |
|
|
4477
|
+
| `setHref` | Replaces the entire URL string. |
|
|
4478
|
+
| `setPassword` | Updates the password used for authentication. |
|
|
4479
|
+
| `setPathname` | Updates the path of the URL. |
|
|
4480
|
+
| `setPort` | Updates the port of the URL. |
|
|
4481
|
+
| `setProtocol` | Updates the protocol (e.g., `http`, `https`). |
|
|
4482
|
+
| `setSearch` | Updates the query string of the URL. |
|
|
4483
|
+
| `setUsername` | Updates the username used for authentication. |
|
|
4484
|
+
|
|
4485
|
+
**Example** (Using Setters to Modify URL Properties)
|
|
4486
|
+
|
|
4487
|
+
```ts
|
|
4488
|
+
import { Url } from "@effect/platform"
|
|
4489
|
+
import { pipe } from "effect"
|
|
4490
|
+
|
|
4491
|
+
const myUrl = new URL("https://example.com")
|
|
4492
|
+
|
|
4493
|
+
// Changing protocol, host, and port
|
|
4494
|
+
const newUrl = pipe(
|
|
4495
|
+
myUrl,
|
|
4496
|
+
Url.setProtocol("http:"),
|
|
4497
|
+
Url.setHost("google.com"),
|
|
4498
|
+
Url.setPort("8080")
|
|
4499
|
+
)
|
|
4500
|
+
|
|
4501
|
+
console.log("Original:", myUrl.toString())
|
|
4502
|
+
// Output: Original: https://example.com/
|
|
4503
|
+
|
|
4504
|
+
console.log("New:", newUrl.toString())
|
|
4505
|
+
// Output: New: http://google.com:8080/
|
|
4506
|
+
```
|
|
4507
|
+
|
|
4508
|
+
### mutate
|
|
4509
|
+
|
|
4510
|
+
For more advanced modifications, use the `mutate` function. It clones the original `URL` object and applies a callback to the clone, allowing multiple updates at once.
|
|
4511
|
+
|
|
4512
|
+
**Example** (Applying Multiple Changes with `mutate`)
|
|
4513
|
+
|
|
4514
|
+
```ts
|
|
4515
|
+
import { Url } from "@effect/platform"
|
|
4516
|
+
|
|
4517
|
+
const myUrl = new URL("https://example.com")
|
|
4518
|
+
|
|
4519
|
+
const mutatedUrl = Url.mutate(myUrl, (url) => {
|
|
4520
|
+
url.username = "user"
|
|
4521
|
+
url.password = "pass"
|
|
4522
|
+
})
|
|
4523
|
+
|
|
4524
|
+
console.log("Mutated:", mutatedUrl.toString())
|
|
4525
|
+
// Output: Mutated: https://user:pass@example.com/
|
|
4526
|
+
```
|
|
4527
|
+
|
|
4528
|
+
## Reading and Writing URL Parameters
|
|
4529
|
+
|
|
4530
|
+
The `Url` module provides utilities for working with URL query parameters. These utilities allow you to read existing parameters and write new ones, all while maintaining immutability. This functionality is supported by the `UrlParams` module.
|
|
4531
|
+
|
|
4532
|
+
You can extract the query parameters from a `URL` object using the `urlParams` function.
|
|
4533
|
+
|
|
4534
|
+
To modify or add query parameters, use the `setUrlParams` function. This function creates a new `URL` with the updated query string.
|
|
4535
|
+
|
|
4536
|
+
**Example** (Reading and Writing Parameters)
|
|
4537
|
+
|
|
4538
|
+
```ts
|
|
4539
|
+
import { Url, UrlParams } from "@effect/platform"
|
|
4540
|
+
|
|
4541
|
+
const myUrl = new URL("https://example.com?foo=bar")
|
|
4542
|
+
|
|
4543
|
+
// Read parameters
|
|
4544
|
+
const params = Url.urlParams(myUrl)
|
|
4545
|
+
|
|
4546
|
+
console.log(params)
|
|
4547
|
+
// Output: [ [ 'foo', 'bar' ] ]
|
|
4548
|
+
|
|
4549
|
+
// Write parameters
|
|
4550
|
+
const updatedUrl = Url.setUrlParams(
|
|
4551
|
+
myUrl,
|
|
4552
|
+
UrlParams.fromInput([["key", "value"]])
|
|
4553
|
+
)
|
|
4554
|
+
|
|
4555
|
+
console.log(updatedUrl.toString())
|
|
4556
|
+
// Output: https://example.com/?key=value
|
|
4557
|
+
```
|
|
4558
|
+
|
|
4559
|
+
### Modifying URL Parameters
|
|
4560
|
+
|
|
4561
|
+
The `modifyUrlParams` function allows you to read, modify, and overwrite URL parameters in a single operation.
|
|
4562
|
+
|
|
4563
|
+
**Example** (Appending a Parameter to a URL)
|
|
4564
|
+
|
|
4565
|
+
```ts
|
|
4566
|
+
import { Url, UrlParams } from "@effect/platform"
|
|
4567
|
+
|
|
4568
|
+
const myUrl = new URL("https://example.com?foo=bar")
|
|
4569
|
+
|
|
4570
|
+
const changedUrl = Url.modifyUrlParams(myUrl, UrlParams.append("key", "value"))
|
|
4571
|
+
|
|
4572
|
+
console.log(changedUrl.toString())
|
|
4573
|
+
// Output: https://example.com/?foo=bar&key=value
|
|
4574
|
+
```
|
|
4575
|
+
|
|
4576
|
+
# OpenApiJsonSchema
|
|
4577
|
+
|
|
4578
|
+
The `OpenApiJsonSchema` module provides utilities to transform `Schema` objects into JSON schemas that comply with the OpenAPI Specification. These utilities are especially helpful for generating OpenAPI documentation or working with tools that require OpenAPI-compliant schemas.
|
|
4579
|
+
|
|
4580
|
+
## Creating a JSON Schema from a Schema
|
|
4581
|
+
|
|
4582
|
+
This module enables you to convert `Schema` objects into OpenAPI-compatible JSON schemas, making it easy to integrate with tools like Swagger or other OpenAPI-based frameworks.
|
|
4583
|
+
|
|
4584
|
+
**Example** (Generating a JSON Schema from a String Schema)
|
|
4585
|
+
|
|
4586
|
+
```ts
|
|
4587
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4588
|
+
import { Schema } from "effect"
|
|
4589
|
+
|
|
4590
|
+
const schema = Schema.String
|
|
4591
|
+
|
|
4592
|
+
// Convert the schema to OpenAPI JSON Schema
|
|
4593
|
+
const openApiSchema = OpenApiJsonSchema.make(schema)
|
|
4594
|
+
|
|
4595
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4596
|
+
/*
|
|
4597
|
+
Output:
|
|
4598
|
+
{
|
|
4599
|
+
"type": "string"
|
|
4600
|
+
}
|
|
4601
|
+
*/
|
|
4602
|
+
```
|
|
4603
|
+
|
|
4604
|
+
## Differences from JSONSchema
|
|
4605
|
+
|
|
4606
|
+
The `OpenApiJsonSchema` module differs from the `JSONSchema` module in several ways. These differences are tailored to align with the OpenAPI Specification.
|
|
4607
|
+
|
|
4608
|
+
### `$schema` Property Omission
|
|
4609
|
+
|
|
4610
|
+
OpenAPI schemas do not include the `$schema` property, while JSON schemas do.
|
|
4611
|
+
|
|
4612
|
+
**Example** (Comparison of `$schema` Property)
|
|
4613
|
+
|
|
4614
|
+
```ts
|
|
4615
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4616
|
+
import { JSONSchema, Schema } from "effect"
|
|
4617
|
+
|
|
4618
|
+
const schema = Schema.String
|
|
4619
|
+
|
|
4620
|
+
const openApiSchema = OpenApiJsonSchema.make(schema)
|
|
4621
|
+
const jsonSchema = JSONSchema.make(schema)
|
|
4622
|
+
|
|
4623
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4624
|
+
/*
|
|
4625
|
+
Output:
|
|
4626
|
+
{
|
|
4627
|
+
"type": "string"
|
|
4628
|
+
}
|
|
4629
|
+
*/
|
|
4630
|
+
|
|
4631
|
+
console.log(JSON.stringify(jsonSchema, null, 2))
|
|
4632
|
+
/*
|
|
4633
|
+
Output:
|
|
4634
|
+
{
|
|
4635
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4636
|
+
"type": "string"
|
|
4637
|
+
}
|
|
4638
|
+
*/
|
|
4639
|
+
```
|
|
4640
|
+
|
|
4641
|
+
### Handling of `null` Values
|
|
4642
|
+
|
|
4643
|
+
OpenAPI does not support `{ "type": "null" }`. Instead, it uses an `enum` containing `null` to represent nullable values.
|
|
4644
|
+
|
|
4645
|
+
**Example** (Representation of `null` Values)
|
|
4646
|
+
|
|
4647
|
+
```ts
|
|
4648
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4649
|
+
import { JSONSchema, Schema } from "effect"
|
|
4650
|
+
|
|
4651
|
+
const schema = Schema.Null
|
|
4652
|
+
|
|
4653
|
+
const openApiSchema = OpenApiJsonSchema.make(schema)
|
|
4654
|
+
const jsonSchema = JSONSchema.make(schema)
|
|
4655
|
+
|
|
4656
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4657
|
+
/*
|
|
4658
|
+
Output:
|
|
4659
|
+
{
|
|
4660
|
+
"enum": [
|
|
4661
|
+
null
|
|
4662
|
+
]
|
|
4663
|
+
}
|
|
4664
|
+
*/
|
|
4665
|
+
|
|
4666
|
+
console.log(JSON.stringify(jsonSchema, null, 2))
|
|
4667
|
+
/*
|
|
4668
|
+
Output:
|
|
4669
|
+
{
|
|
4670
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4671
|
+
"type": "null"
|
|
4672
|
+
}
|
|
4673
|
+
*/
|
|
4674
|
+
```
|
|
4675
|
+
|
|
4676
|
+
### Nullable Values
|
|
4677
|
+
|
|
4678
|
+
OpenAPI uses the `nullable` property to indicate that a value can be `null`, whereas JSON schemas use an `anyOf` structure.
|
|
4679
|
+
|
|
4680
|
+
**Example** (Nullable Property Representation)
|
|
4681
|
+
|
|
4682
|
+
```ts
|
|
4683
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4684
|
+
import { JSONSchema, Schema } from "effect"
|
|
4685
|
+
|
|
4686
|
+
const schema = Schema.NullOr(Schema.String)
|
|
4687
|
+
|
|
4688
|
+
const openApiSchema = OpenApiJsonSchema.make(schema)
|
|
4689
|
+
const jsonSchema = JSONSchema.make(schema)
|
|
4690
|
+
|
|
4691
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4692
|
+
/*
|
|
4693
|
+
Output:
|
|
4694
|
+
{
|
|
4695
|
+
"type": "string",
|
|
4696
|
+
"nullable": true
|
|
4697
|
+
}
|
|
4698
|
+
*/
|
|
4699
|
+
|
|
4700
|
+
console.log(JSON.stringify(jsonSchema, null, 2))
|
|
4701
|
+
/*
|
|
4702
|
+
Output:
|
|
4703
|
+
{
|
|
4704
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4705
|
+
"anyOf": [
|
|
4706
|
+
{
|
|
4707
|
+
"type": "string"
|
|
4708
|
+
},
|
|
4709
|
+
{
|
|
4710
|
+
"type": "null"
|
|
4711
|
+
}
|
|
4712
|
+
]
|
|
4713
|
+
}
|
|
4714
|
+
*/
|
|
4715
|
+
```
|
|
4716
|
+
|
|
4717
|
+
### `contentSchema` Support
|
|
4718
|
+
|
|
4719
|
+
OpenAPI schemas include a `contentSchema` property, which allows you to describe the structure of the content for a media type (e.g., `application/json`). This feature is not available in JSON schemas (Draft 7), making `contentSchema` particularly useful for defining structured payloads in OpenAPI documentation.
|
|
4720
|
+
|
|
4721
|
+
**Note**: Use `contentSchema` to define the internal structure of media types like `application/json` in OpenAPI specifications. This property provides clarity and detail for tools and users interacting with the API, especially when handling structured payloads.
|
|
4722
|
+
|
|
4723
|
+
**Example** (Defining a Schema with `contentSchema` for JSON Content)
|
|
4724
|
+
|
|
4725
|
+
```ts
|
|
4726
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4727
|
+
import { JSONSchema, Schema } from "effect"
|
|
4728
|
+
|
|
4729
|
+
// Define a schema for parsing JSON content
|
|
4730
|
+
const schema = Schema.parseJson(Schema.Struct({ a: Schema.String }))
|
|
4731
|
+
|
|
4732
|
+
const openApiSchema = OpenApiJsonSchema.make(schema)
|
|
4733
|
+
const jsonSchema = JSONSchema.make(schema)
|
|
4734
|
+
|
|
4735
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4736
|
+
/*
|
|
4737
|
+
Output:
|
|
4738
|
+
{
|
|
4739
|
+
"type": "string",
|
|
4740
|
+
"contentMediaType": "application/json",
|
|
4741
|
+
"contentSchema": {
|
|
4742
|
+
"type": "object",
|
|
4743
|
+
"required": [
|
|
4744
|
+
"a"
|
|
4745
|
+
],
|
|
4746
|
+
"properties": {
|
|
4747
|
+
"a": {
|
|
4748
|
+
"type": "string"
|
|
4749
|
+
}
|
|
4750
|
+
},
|
|
4751
|
+
"additionalProperties": false
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
*/
|
|
4755
|
+
|
|
4756
|
+
console.log(JSON.stringify(jsonSchema, null, 2))
|
|
4757
|
+
/*
|
|
4758
|
+
Output:
|
|
4759
|
+
{
|
|
4760
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4761
|
+
"type": "object",
|
|
4762
|
+
"required": [
|
|
4763
|
+
"a"
|
|
4764
|
+
],
|
|
4765
|
+
"properties": {
|
|
4766
|
+
"a": {
|
|
4767
|
+
"type": "string"
|
|
4768
|
+
}
|
|
4769
|
+
},
|
|
4770
|
+
"additionalProperties": false
|
|
4771
|
+
}
|
|
4772
|
+
*/
|
|
4773
|
+
```
|
|
4774
|
+
|
|
4775
|
+
### makeWithDefs
|
|
4776
|
+
|
|
4777
|
+
The `makeWithDefs` function generates OpenAPI-compatible JSON schemas and collects schema definitions in a shared object. This is especially useful for consolidating multiple schemas into a single OpenAPI specification, enabling schema reuse across your API.
|
|
4778
|
+
|
|
4779
|
+
**Example** (Generating OpenAPI Schema with Definitions)
|
|
4780
|
+
|
|
4781
|
+
```ts
|
|
4782
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4783
|
+
import { Schema } from "effect"
|
|
4784
|
+
|
|
4785
|
+
// Define a schema with an identifier annotation
|
|
4786
|
+
const schema = Schema.Struct({ a: Schema.String }).annotations({
|
|
4787
|
+
identifier: "MyStruct"
|
|
4788
|
+
})
|
|
4789
|
+
|
|
4790
|
+
// Create a definitions object
|
|
4791
|
+
const defs = {}
|
|
4792
|
+
|
|
4793
|
+
// Generate the OpenAPI schema while collecting definitions
|
|
4794
|
+
const openApiSchema = OpenApiJsonSchema.makeWithDefs(schema, { defs })
|
|
4795
|
+
|
|
4796
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4797
|
+
/*
|
|
4798
|
+
Output:
|
|
4799
|
+
{
|
|
4800
|
+
"$ref": "#/components/schemas/MyStruct"
|
|
4801
|
+
}
|
|
4802
|
+
*/
|
|
4803
|
+
|
|
4804
|
+
console.log(JSON.stringify(defs, null, 2))
|
|
4805
|
+
/*
|
|
4806
|
+
Output:
|
|
4807
|
+
{
|
|
4808
|
+
"MyStruct": {
|
|
4809
|
+
"type": "object",
|
|
4810
|
+
"required": [
|
|
4811
|
+
"a"
|
|
4812
|
+
],
|
|
4813
|
+
"properties": {
|
|
4814
|
+
"a": {
|
|
4815
|
+
"type": "string"
|
|
4816
|
+
}
|
|
4817
|
+
},
|
|
4818
|
+
"additionalProperties": false
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
*/
|
|
4822
|
+
```
|
|
4823
|
+
|
|
4824
|
+
**Example** (Combining Multiple Schemas into One OpenAPI Specification)
|
|
4825
|
+
|
|
4826
|
+
```ts
|
|
4827
|
+
import { OpenApiJsonSchema } from "@effect/platform"
|
|
4828
|
+
import { Schema } from "effect"
|
|
4829
|
+
|
|
4830
|
+
// Define multiple schemas with unique identifiers
|
|
4831
|
+
const schema1 = Schema.Struct({ a: Schema.String }).annotations({
|
|
4832
|
+
identifier: "MyStruct1"
|
|
4833
|
+
})
|
|
4834
|
+
const schema2 = Schema.Struct({ b: Schema.Number }).annotations({
|
|
4835
|
+
identifier: "MyStruct2"
|
|
4836
|
+
})
|
|
4837
|
+
|
|
4838
|
+
// Create a shared definitions object
|
|
4839
|
+
const defs = {}
|
|
4840
|
+
|
|
4841
|
+
// Use `makeWithDefs` to generate schemas for API paths
|
|
4842
|
+
const paths = {
|
|
4843
|
+
paths: {
|
|
4844
|
+
"/path1": {
|
|
4845
|
+
get: {
|
|
4846
|
+
responses: {
|
|
4847
|
+
"200": {
|
|
4848
|
+
content: {
|
|
4849
|
+
"application/json": {
|
|
4850
|
+
schema: OpenApiJsonSchema.makeWithDefs(schema1, { defs })
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
},
|
|
4857
|
+
"/path2": {
|
|
4858
|
+
get: {
|
|
4859
|
+
responses: {
|
|
4860
|
+
"200": {
|
|
4861
|
+
content: {
|
|
4862
|
+
"application/json": {
|
|
4863
|
+
schema: OpenApiJsonSchema.makeWithDefs(schema2, { defs })
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
}
|
|
4872
|
+
|
|
4873
|
+
// Combine paths and definitions into a single OpenAPI schema
|
|
4874
|
+
const openApiSchema = {
|
|
4875
|
+
components: {
|
|
4876
|
+
schemas: defs
|
|
4877
|
+
},
|
|
4878
|
+
paths
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4881
|
+
console.log(JSON.stringify(openApiSchema, null, 2))
|
|
4882
|
+
/*
|
|
4883
|
+
Output:
|
|
4884
|
+
{
|
|
4885
|
+
"components": {
|
|
4886
|
+
"schemas": {
|
|
4887
|
+
"MyStruct1": {
|
|
4888
|
+
"type": "object",
|
|
4889
|
+
"required": [
|
|
4890
|
+
"a"
|
|
4891
|
+
],
|
|
4892
|
+
"properties": {
|
|
4893
|
+
"a": {
|
|
4894
|
+
"type": "string"
|
|
4895
|
+
}
|
|
4896
|
+
},
|
|
4897
|
+
"additionalProperties": false
|
|
4898
|
+
},
|
|
4899
|
+
"MyStruct2": {
|
|
4900
|
+
"type": "object",
|
|
4901
|
+
"required": [
|
|
4902
|
+
"b"
|
|
4903
|
+
],
|
|
4904
|
+
"properties": {
|
|
4905
|
+
"b": {
|
|
4906
|
+
"type": "number"
|
|
4907
|
+
}
|
|
4908
|
+
},
|
|
4909
|
+
"additionalProperties": false
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
},
|
|
4913
|
+
"paths": {
|
|
4914
|
+
"paths": {
|
|
4915
|
+
"/path1": {
|
|
4916
|
+
"get": {
|
|
4917
|
+
"responses": {
|
|
4918
|
+
"200": {
|
|
4919
|
+
"content": {
|
|
4920
|
+
"application/json": {
|
|
4921
|
+
"schema": {
|
|
4922
|
+
"$ref": "#/components/schemas/MyStruct1"
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
},
|
|
4930
|
+
"/path2": {
|
|
4931
|
+
"get": {
|
|
4932
|
+
"responses": {
|
|
4933
|
+
"200": {
|
|
4934
|
+
"content": {
|
|
4935
|
+
"application/json": {
|
|
4936
|
+
"schema": {
|
|
4937
|
+
"$ref": "#/components/schemas/MyStruct2"
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
}
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
*/
|
|
4949
|
+
```
|