Skip to content

Commit

Permalink
Merge branch 'main' into optimise/handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil authored Dec 24, 2024
2 parents e453ac9 + 47bb96a commit 5647dd6
Show file tree
Hide file tree
Showing 13 changed files with 611 additions and 9 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ lazy val zioHttpGen = (project in file("zio-http-gen"))
scalafmt.cross(CrossVersion.for3Use2_13),
scalametaParsers
.cross(CrossVersion.for3Use2_13)
.exclude("org.scala-lang.modules", "scala-collection-compat_2.13"),
.exclude("org.scala-lang.modules", "scala-collection-compat_2.13")
.exclude("com.lihaoyi", "sourcecode_2.13"),
`zio-json-yaml` % Test,
),
)
Expand Down
36 changes: 36 additions & 0 deletions docs/examples/endpoint-scala3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: endpoint-scala3
title: "Endpoint Scala 3 Syntax"
sidebar_label: "Endpoint Scala 3 Syntax"
---

```scala
import zio.http.*
import zio.http.codec.*
import zio.http.endpoint.*

import java.util.UUID

type NotFound[EntityId] = EntityId
type EntityId = UUID

val union: ContentCodec[String | UUID | Boolean] =
HttpCodec.content[String] || HttpCodec.content[UUID] || HttpCodec.content[Boolean]

val unionEndpoint =
Endpoint(Method.GET / "api" / "complex-union")
.outCodec(union)

val unionWithErrorEndpoint
: Endpoint[Unit, Unit, NotFound[EntityId] | String, UUID | Unit, AuthType.None] =
Endpoint(Method.GET / "api" / "union-with-error")
.out[UUID]
.orOut[Unit](Status.NoContent)
.outError[NotFound[EntityId]](Status.NotFound)
.orOutError[String](Status.BadRequest)

val impl = unionWithErrorEndpoint.implementEither { _ =>
val result: Either[NotFound[EntityId] | String, UUID | Unit] = Left("error")
result
}
```
33 changes: 33 additions & 0 deletions docs/reference/endpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ object EndpointWithMultipleOutputTypes extends ZIOAppDefault {
}
```

For Scala 3, we can use a union type instead of an `Either` by calling `Endpoint#orOut` for more than one output:

```scala
val endpoint: Endpoint[Unit, Unit, ZNothing, Course | Quiz, AuthType.None] =
Endpoint(RoutePattern.GET / "resources")
.out[Course]
.orOut[Quiz]
```

In the above example, we defined an endpoint that describes a path parameter `id` as input and returns either a `Book` or an `Article` as output.

With multiple outputs, we can define if all of them or just some should add an output header, by the order of calling `out` and `outHeader` methods:
Expand Down Expand Up @@ -472,6 +481,30 @@ utils.printSource("zio-http-example/src/main/scala/example/endpoint/EndpointWith
```
</details>

### Multiple Failure Outputs Using Union Types

The `Endpoint#orOutError` method can be used to describe multiple failure outputs using union types:

```scala
import zio.schema.DeriveSchema

case class Book(title: String, authors: List[String])
implicit val bookSchema = DeriveSchema.gen[Book]

case class BookNotFound(message: String, bookId: Int)
case class AuthenticationError(message: String, userId: Int)

implicit val notFoundSchema = DeriveSchema.gen[BookNotFound]
implicit val authSchema = DeriveSchema.gen[AuthenticationError]

val endpoint: Endpoint[Int, (Int, Header.Authorization), BookNotFound | AuthenticationError, Book, AuthType.None] =
Endpoint(RoutePattern.GET / "books" / PathCodec.int("id"))
.header(HeaderCodec.authorization)
.out[Book]
.outError[BookNotFound](Status.NotFound)
.orOutError[AuthenticationError](Status.Unauthorized)
```

## Transforming Endpoint Input/Output and Error Types

To transform the input, output, and error types of an endpoint, we can use the `Endpoint#transformIn`, `Endpoint#transformOut`, and `Endpoint#transformError` methods, respectively. Let's see an example:
Expand Down
13 changes: 11 additions & 2 deletions docs/reference/http-codec.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ There is also a `|` operator that allows us to create a codec that can decode ei
```scala mdoc:silent
import zio.http.codec._

val eitherQueryCodec: QueryCodec[String] = HttpCodec.query[String]("q") | HttpCodec.query[String]("query")
val eitherQueryCodec: QueryCodec[Either[Boolean, String]] = HttpCodec.query[Boolean]("q") | HttpCodec.query[String]("query")
```

Assume we have a request
Expand All @@ -229,7 +229,16 @@ We can decode the query parameter using the `decodeRequest` method:
```scala mdoc:silent
import zio._

val result: Task[String] = eitherQueryCodec.decodeRequest(request)
val result: Task[Either[Boolean, String]] = eitherQueryCodec.decodeRequest(request)
```

#### Scala 3 Union Type Syntax
For Scala 3 the `||` operator is available will return a union type instead of an `Either`.

```scala
import zio.http.codec._

val unionQueryCodec: QueryCodec[Boolean | String] = HttpCodec.query[Boolean]("q") || HttpCodec.query[String]("query")
```

```scala mdoc:invisible:reset
Expand Down
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const sidebars = {
"examples/websocket",
"examples/streaming",
"examples/endpoint",
"examples/endpoint-scala3",
"examples/middleware-cors-handling",
"examples/authentication",
"examples/graceful-shutdown",
Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import sbt.*

object Dependencies {
val JwtCoreVersion = "10.0.1"
val NettyVersion = "4.1.112.Final"
val NettyVersion = "4.1.116.Final"
val NettyIncubatorVersion = "0.0.25.Final"
val ScalaCompactCollectionVersion = "2.12.0"
val ZioVersion = "2.1.11"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private[zio] class ServerSSLDecoder(sslConfig: SSLConfig, cfg: Server.Config) ex
val httpBehaviour = sslConfig.behaviour
if (in.readableBytes < 5)
()
else if (SslHandler.isEncrypted(in)) {
else if (SslHandler.isEncrypted(in, false)) {
pipeline.replace(this, Names.SSLHandler, sslContext.newHandler(context.alloc()))
()
} else {
Expand Down
Loading

2 comments on commit 5647dd6

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 : Performance Benchmarks (SimpleEffectBenchmarkServer)

concurrency: 256
requests/sec: 353151

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 : Performance Benchmarks (PlainTextBenchmarkServer)

concurrency: 256
requests/sec: 359369

Please sign in to comment.