@zio.dev/zio-blocks 0.0.51 → 0.0.56
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/adr/2026-07-18-data-migration.md +123 -0
- package/guides/async-getting-started.md +687 -0
- package/guides/compile-time-resource-safety-with-scope.md +6 -0
- package/guides/getting-started-with-mux.md +0 -112
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +1 -1
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +395 -1
- package/guides/sql-checked-interpolation.md +173 -0
- package/guides/sql-transactions.md +286 -0
- package/guides/telemetry-guide.md +131 -70
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +200 -559
- package/package.json +1 -1
- package/reference/async.md +1379 -531
- package/reference/chunk.md +3 -3
- package/reference/codegen/index.md +1 -1
- package/reference/combinators.md +4 -4
- package/reference/config/config-decoder.md +460 -0
- package/reference/config/config-source.md +489 -0
- package/reference/config/errors.md +278 -0
- package/reference/config/flags.md +369 -0
- package/reference/config/formats.md +314 -0
- package/reference/config/index.md +304 -0
- package/reference/config/rollout.md +336 -0
- package/reference/context.md +6 -49
- package/reference/data-migration.md +269 -0
- package/reference/datastar/attributes.md +302 -0
- package/reference/datastar/events.md +234 -0
- package/reference/datastar/index.md +256 -0
- package/reference/datastar/signals.md +230 -0
- package/reference/datastar/sse.md +295 -0
- package/reference/datastar.md +2 -2
- package/reference/docs.md +2 -2
- package/reference/endpoint/bulk-creation.md +96 -0
- package/reference/endpoint/endpoint.md +1 -0
- package/reference/endpoint/index.md +9 -89
- package/reference/endpoint/path-codec.md +12 -24
- package/reference/endpoint/route-pattern.md +4 -6
- package/reference/endpoint/segment-codec.md +19 -32
- package/reference/html.md +313 -9
- package/reference/htmx/index.md +4 -52
- package/reference/htmx/response-headers.md +240 -0
- package/reference/http-model/headers.md +735 -0
- package/reference/http-model/index.md +3 -1
- package/reference/http-model/model.md +107 -71
- package/reference/http-model/schema-codecs.md +522 -0
- package/reference/http-model/schema.md +6 -3
- package/reference/http-model/server-sent-event.md +341 -0
- package/reference/jwt.md +195 -0
- package/reference/maybe.md +128 -11
- package/reference/media-type.md +2 -2
- package/reference/mux.mdx +7 -2
- package/reference/openapi.md +3 -3
- package/reference/projection.md +654 -0
- package/reference/resource-management/index.md +1 -1
- package/reference/resource-management/resource.md +2 -98
- package/reference/resource-management/scope.md +1 -209
- package/reference/resource-management/wire.md +4 -50
- package/reference/ringbuffer/advanced.mdx +1 -1
- package/reference/ringbuffer/index.mdx +3 -3
- package/reference/ringbuffer/mpmc.mdx +38 -4
- package/reference/ringbuffer/mpsc.mdx +36 -4
- package/reference/ringbuffer/spmc.mdx +1 -1
- package/reference/ringbuffer/spsc.mdx +87 -15
- package/reference/schema/allows.md +0 -96
- package/reference/schema/binding.md +2 -2
- package/reference/schema/built-in-codecs/avro.md +2 -2
- package/reference/schema/built-in-codecs/bson.md +50 -20
- package/reference/schema/built-in-codecs/csv.md +2 -2
- package/reference/schema/built-in-codecs/index.md +3 -3
- package/reference/schema/built-in-codecs/json/index.md +2 -2
- package/reference/schema/built-in-codecs/json/json.md +1 -0
- package/reference/schema/built-in-codecs/messagepack.md +3 -3
- package/reference/schema/built-in-codecs/thrift.md +2 -2
- package/reference/schema/built-in-codecs/toon.md +3 -3
- package/reference/schema/built-in-codecs/yaml.md +2 -2
- package/reference/schema/codec.md +11 -11
- package/reference/schema/dynamic-optic.md +48 -3
- package/reference/schema/dynamic-schema.md +3 -3
- package/reference/schema/index.md +2 -0
- package/reference/schema/path-interpolator.md +2 -0
- package/reference/schema/reflect-transformer.md +140 -0
- package/reference/schema/schema-evolution/as.md +4 -4
- package/reference/schema/schema-evolution/into.md +2 -2
- package/reference/schema/schema-expr.md +2 -2
- package/reference/schema/schema-search.md +263 -0
- package/reference/schema/schema.md +10 -2
- package/reference/schema/type-class-derivation.md +1 -1
- package/reference/smithy.md +502 -3
- package/reference/sql/db-codec-deriver.md +3 -3
- package/reference/sql/db-codec.md +22 -22
- package/reference/sql/db-con.md +4 -4
- package/reference/sql/db-connection.md +1 -1
- package/reference/sql/db-param.md +1 -1
- package/reference/sql/db-result-reader.md +4 -2
- package/reference/sql/db-tx.md +46 -14
- package/reference/sql/ddl.md +1 -1
- package/reference/sql/frag.md +44 -10
- package/reference/sql/index.md +7 -7
- package/reference/sql/repo.md +15 -15
- package/reference/sql/sql-dialect.md +1 -1
- package/reference/sql/sql-logger.md +1 -1
- package/reference/sql/sql-name-mapper.md +3 -3
- package/reference/sql/table-metadata.md +3 -3
- package/reference/sql/table.md +10 -10
- package/reference/sql/transactor-zio.md +1 -1
- package/reference/sql/transactor.md +21 -11
- package/reference/sql-zio.md +2 -2
- package/reference/streams/core/index.md +32 -0
- package/reference/streams/{pipeline.md → core/pipeline.md} +210 -74
- package/reference/streams/{sink.md → core/sink.md} +331 -353
- package/reference/streams/{stream.md → core/stream.md} +919 -209
- package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
- package/reference/streams/execution-and-compatibility/index.md +35 -0
- package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
- package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
- package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
- package/reference/streams/index.md +140 -67
- package/reference/streams/primitives/index.md +30 -0
- package/reference/streams/primitives/reader.md +1992 -0
- package/reference/streams/{writer.md → primitives/writer.md} +254 -98
- package/reference/telemetry/common/any-value.md +90 -0
- package/reference/telemetry/common/attribute-key.md +87 -0
- package/reference/telemetry/common/attributes.md +118 -0
- package/reference/telemetry/common/index.md +39 -0
- package/reference/telemetry/common/instrumentation-scope.md +24 -0
- package/reference/telemetry/common/resource.md +34 -0
- package/reference/telemetry/index.md +311 -0
- package/reference/telemetry/logging/index.md +197 -0
- package/reference/telemetry/logging/log-enrichment.md +72 -0
- package/reference/telemetry/logging/log-formatter.md +100 -0
- package/reference/telemetry/logging/log-record-processor.md +56 -0
- package/reference/telemetry/logging/log-record.md +44 -0
- package/reference/telemetry/logging/log-writer.md +64 -0
- package/reference/telemetry/logging/logger-provider.md +142 -0
- package/reference/telemetry/logging/logger.md +83 -0
- package/reference/telemetry/logging/severity.md +62 -0
- package/reference/telemetry/metrics/index.md +150 -0
- package/reference/telemetry/metrics/instruments.md +183 -0
- package/reference/telemetry/metrics/labeled-instruments.md +74 -0
- package/reference/telemetry/metrics/meter-provider.md +76 -0
- package/reference/telemetry/metrics/meter.md +98 -0
- package/reference/telemetry/metrics/metric-data.md +57 -0
- package/reference/telemetry/otel/custom-exporter.md +216 -0
- package/reference/telemetry/otel/index.md +212 -0
- package/reference/telemetry/tracing/index.md +155 -0
- package/reference/telemetry/tracing/sampler.md +89 -0
- package/reference/telemetry/tracing/span-builder.md +57 -0
- package/reference/telemetry/tracing/span-context.md +39 -0
- package/reference/telemetry/tracing/span-data.md +32 -0
- package/reference/telemetry/tracing/span-kind.md +55 -0
- package/reference/telemetry/tracing/span-processor.md +53 -0
- package/reference/telemetry/tracing/span-status.md +47 -0
- package/reference/telemetry/tracing/span.md +117 -0
- package/reference/telemetry/tracing/tracer-provider.md +91 -0
- package/reference/telemetry/tracing/tracer.md +52 -0
- package/reference/typeid.md +0 -64
- package/sidebars.js +365 -185
- package/undocumented-report.md +528 -270
- package/reference/config.md +0 -158
- package/reference/streams/concurrent-operators.md +0 -106
- package/reference/streams/reader.md +0 -1284
- package/reference/streams/scala-2-compatibility.md +0 -55
- package/reference/streams/zero-boxing.md +0 -275
- package/reference/telemetry.md +0 -693
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: index
|
|
3
|
-
title: "Endpoint
|
|
3
|
+
title: "Endpoint"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
`zio-blocks-endpoint` is a **pure, type-safe HTTP endpoint descriptor** for building clients, servers, and API documentation from a single source of truth. It provides composable types that describe every part of an HTTP surface — routes, query parameters, headers, request bodies, response bodies, error shapes, and authentication — without committing to any particular server or client implementation.
|
|
@@ -41,18 +41,18 @@ The endpoint module is a cross-platform library (JVM + Scala.js). Add the depend
|
|
|
41
41
|
|
|
42
42
|
**JVM (Scala 3.x):**
|
|
43
43
|
```scala
|
|
44
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-endpoint" % "0.0.
|
|
44
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-endpoint" % "0.0.56"
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
**Scala.js (Scala 3.x):**
|
|
48
48
|
```scala
|
|
49
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-endpoint" % "0.0.
|
|
49
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-endpoint" % "0.0.56"
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
**For Scala 3.7+**, the module name is rewritten to `zio-blocks-next-endpoint`:
|
|
53
53
|
```scala
|
|
54
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-next-endpoint" % "0.0.
|
|
55
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-next-endpoint" % "0.0.
|
|
54
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-next-endpoint" % "0.0.56" // JVM
|
|
55
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-next-endpoint" % "0.0.56" // Scala.js
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
Supported Scala versions: 3.x (Scala 3 only — the endpoint module uses Scala 3-only DSL and macro code).
|
|
@@ -227,22 +227,6 @@ cd zio-blocks
|
|
|
227
227
|
Constructs `Endpoint` values from `RoutePattern` and chains request body, query parameters, headers, success outputs, response headers, and typed error variants using the builder DSL.
|
|
228
228
|
|
|
229
229
|
```scala title="endpoint-examples/src/main/scala/endpointexamples/BasicEndpointDefinition.scala"
|
|
230
|
-
/*
|
|
231
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
232
|
-
*
|
|
233
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
234
|
-
* you may not use this file except in compliance with the License.
|
|
235
|
-
* You may obtain a copy of the License at
|
|
236
|
-
*
|
|
237
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
238
|
-
*
|
|
239
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
240
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
241
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
242
|
-
* See the License for the specific language governing permissions and
|
|
243
|
-
* limitations under the License.
|
|
244
|
-
*/
|
|
245
|
-
|
|
246
230
|
package endpointexamples
|
|
247
231
|
|
|
248
232
|
import scala.language.implicitConversions
|
|
@@ -316,22 +300,6 @@ sbt "endpoint-examples/runMain endpointexamples.BasicEndpointDefinition"
|
|
|
316
300
|
Builds `HttpCodec` atoms for query parameters, request headers, response headers, request bodies, response bodies, and status codes. Shows sequential composition with `++` and alternative composition with `|`.
|
|
317
301
|
|
|
318
302
|
```scala title="endpoint-examples/src/main/scala/endpointexamples/HttpCodecConstruction.scala"
|
|
319
|
-
/*
|
|
320
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
321
|
-
*
|
|
322
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
323
|
-
* you may not use this file except in compliance with the License.
|
|
324
|
-
* You may obtain a copy of the License at
|
|
325
|
-
*
|
|
326
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
327
|
-
*
|
|
328
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
329
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
330
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
331
|
-
* See the License for the specific language governing permissions and
|
|
332
|
-
* limitations under the License.
|
|
333
|
-
*/
|
|
334
|
-
|
|
335
303
|
package endpointexamples
|
|
336
304
|
|
|
337
305
|
import zio.blocks.chunk.Chunk
|
|
@@ -432,22 +400,6 @@ sbt "endpoint-examples/runMain endpointexamples.HttpCodecConstruction"
|
|
|
432
400
|
Demonstrates all `SegmentCodec` kinds, intra-segment composition with `~` for patterns like `v42`, bidirectional `PathCodec` decode and format, `RoutePattern` matching, `nest` for version prefixes, and `transform`/`transformOrFail` for domain type mapping.
|
|
433
401
|
|
|
434
402
|
```scala title="endpoint-examples/src/main/scala/endpointexamples/PathAndSegmentCodecs.scala"
|
|
435
|
-
/*
|
|
436
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
437
|
-
*
|
|
438
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
439
|
-
* you may not use this file except in compliance with the License.
|
|
440
|
-
* You may obtain a copy of the License at
|
|
441
|
-
*
|
|
442
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
443
|
-
*
|
|
444
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
445
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
446
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
447
|
-
* See the License for the specific language governing permissions and
|
|
448
|
-
* limitations under the License.
|
|
449
|
-
*/
|
|
450
|
-
|
|
451
403
|
package endpointexamples
|
|
452
404
|
|
|
453
405
|
import scala.language.implicitConversions
|
|
@@ -535,7 +487,7 @@ import zio.http.{Method, Path}
|
|
|
535
487
|
final case class UserId(value: Int)
|
|
536
488
|
|
|
537
489
|
val userIdCodec: PathCodec[UserId] =
|
|
538
|
-
PathCodec.int("id").transform
|
|
490
|
+
PathCodec.int("id").transform(UserId(_), _.value)
|
|
539
491
|
|
|
540
492
|
val decodedUserId = userIdCodec.decode(Path("/99"))
|
|
541
493
|
println(s"UserId decoded: $decodedUserId")
|
|
@@ -544,9 +496,9 @@ import zio.http.{Method, Path}
|
|
|
544
496
|
val positiveInt: PathCodec[Int] =
|
|
545
497
|
PathCodec
|
|
546
498
|
.int("count")
|
|
547
|
-
.transformOrFail
|
|
499
|
+
.transformOrFail(
|
|
548
500
|
n => if (n > 0) Right(n) else Left(s"Expected positive, got $n"),
|
|
549
|
-
n => Right(n)
|
|
501
|
+
(n: Int) => Right(n)
|
|
550
502
|
)
|
|
551
503
|
|
|
552
504
|
println(s"Positive decode 5: ${positiveInt.decode(Path("/5"))}")
|
|
@@ -567,22 +519,6 @@ sbt "endpoint-examples/runMain endpointexamples.PathAndSegmentCodecs"
|
|
|
567
519
|
Shows all built-in `AuthType` variants (None, Basic, Bearer, Digest), a custom API-key variant, OR composition with `|`, scoped bearer tokens for OAuth scope metadata, and overriding the default unauthorized status.
|
|
568
520
|
|
|
569
521
|
```scala title="endpoint-examples/src/main/scala/endpointexamples/AuthTypePatterns.scala"
|
|
570
|
-
/*
|
|
571
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
572
|
-
*
|
|
573
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
574
|
-
* you may not use this file except in compliance with the License.
|
|
575
|
-
* You may obtain a copy of the License at
|
|
576
|
-
*
|
|
577
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
578
|
-
*
|
|
579
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
580
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
581
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
582
|
-
* See the License for the specific language governing permissions and
|
|
583
|
-
* limitations under the License.
|
|
584
|
-
*/
|
|
585
|
-
|
|
586
522
|
package endpointexamples
|
|
587
523
|
|
|
588
524
|
import scala.language.implicitConversions
|
|
@@ -673,22 +609,6 @@ sbt "endpoint-examples/runMain endpointexamples.AuthTypePatterns"
|
|
|
673
609
|
Assembles a full users CRUD API combining `Endpoint`, `RoutePattern`, `PathCodec`, `SegmentCodec`, `HttpCodec`, `AuthType`, and `RouteTree`. Demonstrates versioned routes via `nest`, Scala 3 union error types via `orOutError`, and `RouteTree` lookup priority for efficient O(depth) dispatch.
|
|
674
610
|
|
|
675
611
|
```scala title="endpoint-examples/src/main/scala/endpointexamples/CompleteApiDefinition.scala"
|
|
676
|
-
/*
|
|
677
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
678
|
-
*
|
|
679
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
680
|
-
* you may not use this file except in compliance with the License.
|
|
681
|
-
* You may obtain a copy of the License at
|
|
682
|
-
*
|
|
683
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
684
|
-
*
|
|
685
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
686
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
687
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
688
|
-
* See the License for the specific language governing permissions and
|
|
689
|
-
* limitations under the License.
|
|
690
|
-
*/
|
|
691
|
-
|
|
692
612
|
package endpointexamples
|
|
693
613
|
|
|
694
614
|
import scala.language.implicitConversions
|
|
@@ -715,7 +635,7 @@ import zio.http.{Method, Path, Status}
|
|
|
715
635
|
final case class UserId(value: Int)
|
|
716
636
|
|
|
717
637
|
val userIdPath: PathCodec[UserId] =
|
|
718
|
-
PathCodec.int("id").transform
|
|
638
|
+
PathCodec.int("id").transform(UserId(_), _.value)
|
|
719
639
|
|
|
720
640
|
// --- Endpoint definitions ---
|
|
721
641
|
|
|
@@ -3,16 +3,12 @@ id: path-codec
|
|
|
3
3
|
title: "PathCodec"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`PathCodec[A]` is a composable descriptor for URL path structures. It holds a tree of segment codecs connected by concatenation and fallback nodes, and provides bidirectional path conversion: `PathCodec#decode` extracts a typed value from a `Path`, returning `Either[String, A]` (the typed value or error), and `PathCodec#format` formats a typed value back to a `Path`, returning `Either[String, Path]` (the path or error).
|
|
6
|
+
`PathCodec[A]` is a composable descriptor for URL path structures. It holds a tree of segment codecs connected by concatenation and fallback nodes, and provides bidirectional path conversion: `PathCodec#decode` extracts a typed value from a `Path`, returning `Either[String, A]` (the typed value or error), and `PathCodec#format` formats a typed value back to a `Path`, returning `Either[String, Path]` (the path or error). Its definition begins:
|
|
7
7
|
|
|
8
8
|
```scala
|
|
9
|
-
sealed trait PathCodec[A]
|
|
10
|
-
type PathVars
|
|
11
|
-
}
|
|
9
|
+
sealed trait PathCodec[A]
|
|
12
10
|
```
|
|
13
11
|
|
|
14
|
-
`PathVars` is purely type-level: it has zero runtime footprint and does not affect decoding or formatting. It exists so downstream tooling (for example, handler macros or static checks) can recover which named path variables a route declared, in order, and whether any of them were explicitly marked as ignored.
|
|
15
|
-
|
|
16
12
|
## Motivation
|
|
17
13
|
|
|
18
14
|
URL paths need both matching and generation. A routing library that only matches paths requires a separate URL-builder for links and redirects, leading to duplication and drift. `PathCodec` is bidirectional: every codec that can decode `/users/42` into `42: Int` can also format `42` back into `/users/42`. This makes it safe to use the same path definition for routing, link generation, and OpenAPI path parameter documentation.
|
|
@@ -49,9 +45,7 @@ val boolFlag: PathCodec[Boolean] = PathCodec.bool("enabled")
|
|
|
49
45
|
val rest: PathCodec[zio.http.Path] = PathCodec.trailing
|
|
50
46
|
```
|
|
51
47
|
|
|
52
|
-
`PathCodec.literal`
|
|
53
|
-
|
|
54
|
-
For literal names like `PathCodec.int("id")`, the name is preserved as a singleton type inside `PathVars`, so the phantom track remembers not just that the codec captures an `Int`, but that it came from the path variable named `"id"`.
|
|
48
|
+
`PathCodec.literal` validates the value — it rejects empty strings and strings containing `/` or characters requiring URL encoding.
|
|
55
49
|
|
|
56
50
|
### From a string
|
|
57
51
|
|
|
@@ -79,27 +73,21 @@ val combined = PathCodec(SegmentCodec.literal("v") ~ SegmentCodec.int("version")
|
|
|
79
73
|
|
|
80
74
|
There is also an implicit conversion from `SegmentCodec[A]` to `PathCodec[A]` and from `String` to `PathCodec[Unit]`, so both can appear directly in `/` expressions.
|
|
81
75
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
Every dynamic path segment contributes one phantom marker to `PathCodec#PathVars`:
|
|
76
|
+
## Marking a capture as unused with `.unused`
|
|
85
77
|
|
|
86
|
-
|
|
87
|
-
- `PathCodec.uuid("orderId")` contributes `PathVar["orderId", UUID]`
|
|
88
|
-
- literal segments and `PathCodec.trailing` contribute no markers
|
|
89
|
-
|
|
90
|
-
Sequential composition with `/` or `++` concatenates those markers in declaration order, matching the left-to-right route shape.
|
|
91
|
-
|
|
92
|
-
Sometimes a route needs to capture a segment for matching or formatting, but a downstream handler intentionally does not consume that variable. For that case, single-variable codecs expose `.unused`, which keeps the runtime behavior identical while relabeling the phantom marker to `PathVar.Ignored[Name, Type]`:
|
|
78
|
+
Sometimes a route needs to capture a segment for matching or formatting, but a downstream handler intentionally does not consume that variable. `PathCodec` instances expose `.unused`, which converts the value type to `Unit` while keeping the same path shape:
|
|
93
79
|
|
|
94
80
|
```scala
|
|
95
81
|
import zio.blocks.endpoint._
|
|
96
82
|
import zio.blocks.endpoint.RoutePattern._
|
|
97
83
|
|
|
98
84
|
val userId: PathCodec[Int] = PathCodec.int("id")
|
|
99
|
-
val ignoredUserId: PathCodec[
|
|
85
|
+
val ignoredUserId: PathCodec[Unit] = PathCodec.int("id").unused
|
|
100
86
|
```
|
|
101
87
|
|
|
102
|
-
`.unused`
|
|
88
|
+
`.unused` converts the path codec's value type to `Unit`: the route still matches the same shape and renders `{name}` placeholders, but decoding yields `Unit` instead of the captured value, so no handler parameter is required. `format` on an unused path fails because there is no value to encode back into the ignored segment.
|
|
89
|
+
|
|
90
|
+
`PathCodec.unused` composes normally with `/` and is unaffected by `transform` / `transformOrFail` lifting.
|
|
103
91
|
|
|
104
92
|
## Composition
|
|
105
93
|
|
|
@@ -204,7 +192,7 @@ import zio.blocks.endpoint.PathCodec._
|
|
|
204
192
|
final case class UserId(value: Int)
|
|
205
193
|
|
|
206
194
|
val userIdCodec: PathCodec[UserId] =
|
|
207
|
-
PathCodec.int("id").transform
|
|
195
|
+
PathCodec.int("id").transform(UserId(_), _.value)
|
|
208
196
|
```
|
|
209
197
|
|
|
210
198
|
### `PathCodec#transformOrFail`
|
|
@@ -216,9 +204,9 @@ import zio.blocks.endpoint._
|
|
|
216
204
|
import zio.blocks.endpoint.RoutePattern._
|
|
217
205
|
|
|
218
206
|
val nonNegativeInt: PathCodec[Int] =
|
|
219
|
-
PathCodec.int("count").transformOrFail
|
|
207
|
+
PathCodec.int("count").transformOrFail(
|
|
220
208
|
n => if (n >= 0) Right(n) else Left(s"Expected non-negative, got $n"),
|
|
221
|
-
n => Right(n)
|
|
209
|
+
(n: Int) => Right(n)
|
|
222
210
|
)
|
|
223
211
|
```
|
|
224
212
|
|
|
@@ -3,7 +3,7 @@ id: route-pattern
|
|
|
3
3
|
title: "RoutePattern"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`RoutePattern[A]` pairs an HTTP method with a typed path pattern. It is the primary routing descriptor in `zio-blocks-endpoint`: every `Endpoint` carries a `RoutePattern` that determines which HTTP method and URL path it matches.
|
|
6
|
+
`RoutePattern[A]` pairs an HTTP method with a typed path pattern. It is the primary routing descriptor in `zio-blocks-endpoint`: every `Endpoint` carries a `RoutePattern` that determines which HTTP method and URL path it matches. Its shape is:
|
|
7
7
|
|
|
8
8
|
```scala
|
|
9
9
|
final case class RoutePattern[A](
|
|
@@ -13,13 +13,11 @@ final case class RoutePattern[A](
|
|
|
13
13
|
)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
The `PathVars` track is not a constructor parameter because it is purely type-level: it has zero runtime footprint and is derived from `pathCodec`. A literal-only route contributes no path-variable markers; a route with dynamic segments preserves them in declaration order.
|
|
17
|
-
|
|
18
16
|
## Motivation
|
|
19
17
|
|
|
20
18
|
HTTP routing requires matching both a method (GET, POST, …) and a path (`/users/42`). `RoutePattern` holds both in a single typed value. The type parameter `A` is the type of values extracted from the dynamic path segments — `Unit` for fully-literal paths, `Int` for a single integer segment, `(String, UUID)` for two dynamic segments, and so on.
|
|
21
19
|
|
|
22
|
-
Using a typed route pattern means route construction and path extraction are verified at compile time: the type of the extracted path value is always consistent with the path codec definition.
|
|
20
|
+
Using a typed route pattern means route construction and path extraction are verified at compile time: the type of the extracted path value is always consistent with the path codec definition.
|
|
23
21
|
|
|
24
22
|
## Construction
|
|
25
23
|
|
|
@@ -85,7 +83,7 @@ val catchAll: RoutePattern[Path] = RoutePattern.any
|
|
|
85
83
|
val getAny: RoutePattern[Path] = RoutePattern.any(Method.GET)
|
|
86
84
|
```
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
A trailing catch-all captures a `zio.http.Path` runtime value without declaring any named path variables.
|
|
89
87
|
|
|
90
88
|
## Path Composition with `/`
|
|
91
89
|
|
|
@@ -99,7 +97,7 @@ import zio.http.Method
|
|
|
99
97
|
val route = Method.GET / "users" / PathCodec.int("id") / "posts"
|
|
100
98
|
```
|
|
101
99
|
|
|
102
|
-
Each `/` call produces a new `RoutePattern` with a widened type. The type is automatically flattened, eliminating `Unit` components: `Unit / Int / Unit` becomes `Int`, not `((Unit, Int), Unit)`.
|
|
100
|
+
Each `/` call produces a new `RoutePattern` with a widened type. The type is automatically flattened, eliminating `Unit` components: `Unit / Int / Unit` becomes `Int`, not `((Unit, Int), Unit)`.
|
|
103
101
|
|
|
104
102
|
## Decoding and Encoding
|
|
105
103
|
|
|
@@ -3,19 +3,13 @@ id: segment-codec
|
|
|
3
3
|
title: "SegmentCodec"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`SegmentCodec[A]` describes a single URL path segment. It supports basic typed segment kinds — `SegmentCodec.bool`, `SegmentCodec.int`, `SegmentCodec.long`, `SegmentCodec.string`, `SegmentCodec.uuid`, and `SegmentCodec.literal` — as well as intra-segment composition via `~`, which combines multiple typed parts within a single path segment (for example, `v42` as a literal prefix followed by an integer). Ambiguous
|
|
6
|
+
`SegmentCodec[A]` describes a single URL path segment. It supports basic typed segment kinds — `SegmentCodec.bool`, `SegmentCodec.int`, `SegmentCodec.long`, `SegmentCodec.string`, `SegmentCodec.uuid`, and `SegmentCodec.literal` — as well as intra-segment composition via `~`, which combines multiple typed parts within a single path segment (for example, `v42` as a literal prefix followed by an integer). Ambiguous adjacencies (`string ~ string`, numeric ~ numeric in any `Int`/`Long` order, anything involving `Trailing`) are rejected at runtime with `IllegalArgumentException`. Combine representation first, then transform: `transform` / `transformOrFail` lift a segment into a `PathCodec`, ending intra-segment composition. The core type-level shape is:
|
|
7
7
|
|
|
8
8
|
```scala
|
|
9
|
-
sealed trait SegmentCodec[A]
|
|
10
|
-
type Prefix <: SegmentCodec.BoundaryTag
|
|
11
|
-
type Suffix <: SegmentCodec.BoundaryTag
|
|
12
|
-
type PathVars
|
|
13
|
-
}
|
|
9
|
+
sealed trait SegmentCodec[A]
|
|
14
10
|
```
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
(The trait also includes additional members for documentation, examples, formatting, and rendering.)
|
|
12
|
+
(The trait also includes methods for `~` composition, `transform` lifting, documentation, examples, formatting, and rendering.)
|
|
19
13
|
|
|
20
14
|
## Motivation
|
|
21
15
|
|
|
@@ -23,7 +17,7 @@ Standard routing libraries treat path segments as plain strings, deferring all p
|
|
|
23
17
|
|
|
24
18
|
- **Type-safe path building**: `PathCodec.int("id")` produces a `PathCodec[Int]`, not `PathCodec[String]`.
|
|
25
19
|
- **Bidirectional conversion**: every `SegmentCodec` can both decode a string into `A` and format an `A` back to a string.
|
|
26
|
-
- **
|
|
20
|
+
- **Fail-fast combination validation**: the `~` operator rejects ambiguous adjacencies (`string ~ string`, numeric ~ numeric) at composition time, so bad splits surface immediately instead of misrouting.
|
|
27
21
|
|
|
28
22
|
## Segment Kinds
|
|
29
23
|
|
|
@@ -57,19 +51,16 @@ val stringSeg: SegmentCodec[String] = SegmentCodec.string("slug")
|
|
|
57
51
|
val uuidSeg: SegmentCodec[java.util.UUID] = SegmentCodec.uuid("id")
|
|
58
52
|
```
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
If a route should keep a captured segment for matching/formatting but explicitly mark it as intentionally unused for downstream tooling, the leaf dynamic segment codecs expose `.unused`:
|
|
54
|
+
If a route should capture a segment for matching or formatting but the handler intentionally does not consume the variable, the leaf dynamic segment codecs expose `.unused`:
|
|
63
55
|
|
|
64
56
|
```scala
|
|
65
|
-
import zio.blocks.endpoint.
|
|
66
|
-
import zio.blocks.endpoint.RoutePattern._
|
|
57
|
+
import zio.blocks.endpoint.SegmentCodec
|
|
67
58
|
|
|
68
|
-
val requiredId
|
|
69
|
-
val ignoredId
|
|
59
|
+
val requiredId = SegmentCodec.int("id")
|
|
60
|
+
val ignoredId = SegmentCodec.int("id").unused
|
|
70
61
|
```
|
|
71
62
|
|
|
72
|
-
`.unused` keeps decoding, formatting, rendering, and composition identical
|
|
63
|
+
`.unused` keeps decoding, formatting, rendering, and composition identical. The only difference is at the type level: downstream tooling (handler macros, static checks) sees the variable as intentionally unused and does not require the handler to bind it.
|
|
73
64
|
|
|
74
65
|
The ordering of match priority in the routing trie follows the kind: `Literal` matches first, then `Int`, `Long`, `UUID`, `Bool`, `String`, `Combined`, and `Trailing` last.
|
|
75
66
|
|
|
@@ -99,14 +90,14 @@ val versionSeg: SegmentCodec[Int] =
|
|
|
99
90
|
|
|
100
91
|
The type is automatically flattened (eliminating `Unit` from the literal), so the resulting codec decodes `"v42"` into `42` and formats `42` back to `"v42"`.
|
|
101
92
|
|
|
102
|
-
###
|
|
93
|
+
### Runtime adjacency validation
|
|
103
94
|
|
|
104
|
-
The `~` operator
|
|
95
|
+
The `~` operator checks the physical adjacency at composition time. Two categories of combination are always rejected with `IllegalArgumentException`:
|
|
105
96
|
|
|
106
97
|
- **Two string segments**: `SegmentCodec.string("a") ~ SegmentCodec.string("b")` — both are unbounded greedy matchers; the parser cannot know where one ends and the other begins.
|
|
107
|
-
- **Two numeric segments**: `SegmentCodec.int("a") ~ SegmentCodec.int("b")` — numeric segments are also ambiguously bounded.
|
|
98
|
+
- **Two numeric segments**: `SegmentCodec.int("a") ~ SegmentCodec.int("b")` — numeric segments are also ambiguously bounded (any `Int`/`Long` order, including through a flattened combined tail).
|
|
108
99
|
|
|
109
|
-
Combinations that are safe
|
|
100
|
+
Anything involving `Trailing` is likewise rejected. Combinations that are safe compose normally:
|
|
110
101
|
|
|
111
102
|
```scala
|
|
112
103
|
import zio.blocks.endpoint._
|
|
@@ -122,11 +113,11 @@ val prefixedUuid =
|
|
|
122
113
|
SegmentCodec.string("prefix") ~ SegmentCodec.uuid("id") ~ SegmentCodec.string("suffix")
|
|
123
114
|
```
|
|
124
115
|
|
|
125
|
-
Attempting an ambiguous combination like `string ~ string`
|
|
116
|
+
Attempting an ambiguous combination like `string ~ string` throws `IllegalArgumentException` at composition time, not a silent misroute.
|
|
126
117
|
|
|
127
118
|
## Type Transformations
|
|
128
119
|
|
|
129
|
-
|
|
120
|
+
Combine representation first, then transform: `transform` / `transformOrFail` map the decoded segment value into a domain type and lift the segment into a `PathCodec`, ending intra-segment composition (a transformed codec no longer offers `~`; compose with `/` instead).
|
|
130
121
|
|
|
131
122
|
### `SegmentCodec#transform`
|
|
132
123
|
|
|
@@ -138,14 +129,10 @@ import zio.blocks.endpoint.RoutePattern._
|
|
|
138
129
|
|
|
139
130
|
final case class UserId(value: java.util.UUID)
|
|
140
131
|
|
|
141
|
-
val
|
|
142
|
-
SegmentCodec.uuid("id").transform
|
|
132
|
+
val userIdCodec: PathCodec[UserId] =
|
|
133
|
+
SegmentCodec.uuid("id").transform(UserId(_), _.value)
|
|
143
134
|
```
|
|
144
135
|
|
|
145
|
-
`SegmentCodec#transform` preserves the `BoundaryTag` types of the original codec, so transformed codecs still participate in compile-time `~` boundary validation.
|
|
146
|
-
|
|
147
|
-
It also preserves the original `PathVars` marker unchanged: transforming a captured `SegmentCodec.int("id")` into a domain type still records that the segment came from the declared `"id"` path variable.
|
|
148
|
-
|
|
149
136
|
### `SegmentCodec#transformOrFail`
|
|
150
137
|
|
|
151
138
|
When decoding can fail, use `SegmentCodec#transformOrFail`. A `Left` result causes segment matching to fail for that candidate:
|
|
@@ -156,8 +143,8 @@ import zio.blocks.endpoint.RoutePattern._
|
|
|
156
143
|
|
|
157
144
|
final case class PositiveInt(value: Int)
|
|
158
145
|
|
|
159
|
-
val
|
|
160
|
-
SegmentCodec.int("count").transformOrFail
|
|
146
|
+
val positiveIntCodec: PathCodec[PositiveInt] =
|
|
147
|
+
SegmentCodec.int("count").transformOrFail(
|
|
161
148
|
n => if (n > 0) Right(PositiveInt(n)) else Left(s"Expected positive, got $n"),
|
|
162
149
|
p => Right(p.value)
|
|
163
150
|
)
|