Skip to content

Commit

Permalink
Merge branch 'zio:main' into fix/mimetype-binary-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
varshith257 authored Nov 9, 2024
2 parents 6883910 + dc1f3f4 commit 4f7388c
Show file tree
Hide file tree
Showing 40 changed files with 3,535 additions and 168 deletions.
174 changes: 115 additions & 59 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion .github/workflows/site.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file was autogenerated using `zio-sbt-website` via `sbt generateGithubWorkflow`
# This file was autogenerated using `zio-sbt-website` via `sbt generateGithubWorkflow`
# task and should be included in the git repository. Please do not edit it manually.

name: Website
Expand All @@ -23,6 +23,7 @@ jobs:
uses: actions/[email protected]
with:
fetch-depth: '0'
- uses: coursier/setup-action@v1
- name: Setup Scala
uses: actions/[email protected]
with:
Expand All @@ -48,6 +49,7 @@ jobs:
distribution: temurin
java-version: 17
check-latest: true
- uses: coursier/setup-action@v1
- name: Setup NodeJs
uses: actions/setup-node@v3
with:
Expand All @@ -67,6 +69,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: '0'
- uses: coursier/setup-action@v1
- name: Install libuv
run: sudo apt-get update && sudo apt-get install -y libuv1-dev
- name: Setup Scala
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Some of the key features of ZIO HTTP are:
Setup via `build.sbt`:

```scala
libraryDependencies += "dev.zio" %% "zio-http" % "3.0.0"
libraryDependencies += "dev.zio" %% "zio-http" % "3.0.1"
```

**NOTES ON VERSIONING:**
Expand Down
7 changes: 6 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ ThisBuild / githubWorkflowAddedJobs :=
WorkflowJob(
id = "mima_check",
name = "Mima Check",
steps = WorkflowStep.CheckoutFull +: WorkflowStep.SetupJava(List(JavaSpec.temurin("21"))) :+ WorkflowStep.Sbt(List("mimaChecks")),
steps = List(
WorkflowStep.Use(UseRef.Public("actions", "checkout", "v4"), Map("fetch-depth" -> "0")),
WorkflowStep.Use(UseRef.Public("coursier", "setup-action", "v1")),
) ++ WorkflowStep.SetupJava(List(JavaSpec.temurin("21"))) :+ WorkflowStep.Sbt(List("mimaChecks")),
cond = Option("${{ github.event_name == 'pull_request' }}"),
javas = List(JavaSpec.temurin("21")),
),
Expand Down Expand Up @@ -75,6 +78,7 @@ ThisBuild / githubWorkflowPublish :=
//scala fix isn't available for scala 3 so ensure we only run the fmt check
//using the latest scala 2.13
ThisBuild / githubWorkflowBuildPreamble := Seq(
WorkflowStep.Use(UseRef.Public("coursier", "setup-action", "v1")),
WorkflowStep.Run(
name = Some("Check formatting"),
commands = List(s"sbt ++${Scala213} fmtCheck"),
Expand All @@ -87,6 +91,7 @@ ThisBuild / githubWorkflowBuildPostamble :=
"checkDocGeneration",
"Check doc generation",
List(
WorkflowStep.Use(UseRef.Public("coursier", "setup-action", "v1")),
WorkflowStep.Run(
commands = List(s"sbt ++${Scala213} doc"),
name = Some("Check doc generation"),
Expand Down
6 changes: 2 additions & 4 deletions docs/guides/testing-http-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,10 @@ object TestServerExampleSpec extends ZIOSpecDefault {
fallbackResponse <- client.batched(Request.get(testRequest.url / "any"))
fallbackBody <- fallbackResponse.body.asString
} yield assertTrue(helloBody == "Hey there!", fallbackBody == "fallback")
}.provideSome[Client with Driver](TestServer.layer)
}
}.provide(
ZLayer.succeed(Server.Config.default.onAnyOpenPort),
TestServer.default,
Client.default,
NettyDriver.customized,
ZLayer.succeed(NettyConfig.defaultWithFastShutdown),
)
}
```
11 changes: 11 additions & 0 deletions docs/reference/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,17 @@ In this example, the type of the handler before applying the `sandbox` operator

Without the `sandbox` operator, the compiler would complain about the unhandled `Throwable` error.

By default, sandboxed errors will result in a `500 Internal Server Error` response without a body. If you want to have all information about the error in the response body you can use a different (`ErrorResponseConfig`)[response/response.md#failure-responses-with-details] like `ErrorResponseConfig.debug`:

```scala mdoc:compile-only
import zio.http._
import java.nio.file._

Routes(
Method.GET / "file" ->
Handler.fromFile(Paths.get("file.txt").toFile).sandbox,
) @@ ErrorResponseConfig.debug
```
### Converting a `Handler` to an `Routes`

The `Handler#toRoutes` operator, converts a handler to an `Routes` to be served by the `Server`. The following example, shows an HTTP application that serves a simple "Hello, World!" response for all types of incoming requests:
Expand Down
50 changes: 50 additions & 0 deletions docs/reference/response/response.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,56 @@ val failedHandler = Handler.fail(new IOException())
failedHandler.mapErrorCause(Response.fromCause)
```

#### Failure Responses with Details

By default, the `Response.fromThrowable` and `Response.fromCause` methods create a response with a status code only. If we want to include additional details in the response, we have to hand over a `ErrorResponseConfig`.

```scala
/**
* Configuration for the response generation
*
* @param withErrorBody
* if true, includes the error message in the response body
* @param withStackTrace
* if true, includes the stack trace in the response body
* @param maxStackTraceDepth
* maximum number of stack trace lines to include in the response body. Set to
* 0 to include all lines.
* @param errorFormat
* the preferred format for the error response.
* If the context in which the response is created has access to an Accept header,
* the header will be used preferably to determine the format.
*/
final case class ErrorResponseConfig(
withErrorBody: Boolean = false,
withStackTrace: Boolean = false,
maxStackTraceDepth: Int = 10,
errorFormat: ErrorResponseConfig.ErrorFormat = ErrorResponseConfig.ErrorFormat.Html,
)
```

This config can not only be used directly, but can also configure how ZIO-HTTP internally converts a `Cause` or `Throwable` to a `Response`.
You can configure error responses globally by providing a custom `ErrorResponseConfig` via layer for example in the bootstrap of your application.
Or you can apply the config locally to some routes via middleware.

```scala mdoc
import zio.http._

object MyHttpApp extends ZIOAppDefault {
// Provide a custom ErrorResponseConfig via layer
// Equivalent to: val bootstrap = ErrorResponseConfig.configLayer(ErrorResponseConfig.debugConfig)
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] = ErrorResponseConfig.debugLayer

// Apply the ErrorResponseConfig.debug middleware to routes
// Equivalent to: val myRoutes = Handler.ok.toRoutes @@ ErrorResponseConfig.withConfig(ErrorResponseConfig.debugConfig)
val myRoutes = Handler.ok.toRoutes @@ ErrorResponseConfig.debug

override def run = ???
}
```

The debug config will include the error message and full stack trace in the response body.

:::note
In many cases, it is more convenient to use the `sandbox` method to automatically convert all failures into a corresponding `Response`. But in some cases, to have more granular control over the error handling, we may want to use `Response.fromCause` and `Response.fromThrowable` directly.
:::
Expand Down
6 changes: 3 additions & 3 deletions project/BenchmarkWorkFlow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ object BenchmarkWorkFlow {
commands = List("sudo rm -rf *"),
),
WorkflowStep.Use(
UseRef.Public("actions", "checkout", s"v2"),
UseRef.Public("actions", "checkout", s"v4"),
Map(
"path" -> "zio-http",
),
),
WorkflowStep.Use(
UseRef.Public("actions", "checkout", s"v2"),
UseRef.Public("actions", "checkout", s"v4"),
Map(
"repository" -> "khajavi/FrameworkBenchmarks",
"path" -> "FrameworkBenchMarks",
Expand Down Expand Up @@ -103,7 +103,7 @@ object BenchmarkWorkFlow {
|if (( REQUESTS_PER_SECOND > PERFORMANCE_FLOOR )); then
| echo "Woohoo! Performance is good! $REQUESTS_PER_SECOND requests/sec exceeds the performance floor of $PERFORMANCE_FLOOR requests/sec."
|else
|else
| echo "Performance benchmark failed with $REQUESTS_PER_SECOND req/sec! Performance must exceed $PERFORMANCE_FLOOR req/sec."
| exit 1
|fi""".stripMargin,
Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Dependencies {
val NettyVersion = "4.1.112.Final"
val NettyIncubatorVersion = "0.0.25.Final"
val ScalaCompactCollectionVersion = "2.12.0"
val ZioVersion = "2.1.9"
val ZioVersion = "2.1.11"
val ZioCliVersion = "0.5.0"
val ZioJsonVersion = "0.7.1"
val ZioParserVersion = "0.1.10"
Expand Down
13 changes: 7 additions & 6 deletions project/JmhBenchmarkWorkflow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object JmhBenchmarkWorkflow {
Glob("zio-http-benchmarks/src/main/scala-2.13/**"),
Glob("zio-http-benchmarks/src/main/scala/**")),scalaSources
)

/**
* Get zioHttpBenchmark file names
*/
Expand Down Expand Up @@ -45,7 +45,7 @@ object JmhBenchmarkWorkflow {
def downloadArtifacts(branch: String, batchSize: Int) = groupedBenchmarks(batchSize).flatMap(l => {
Seq(
WorkflowStep.Use(
ref = UseRef.Public("actions", "download-artifact", "v3"),
ref = UseRef.Public("actions", "download-artifact", "v4"),
Map(
"name" -> s"Jmh_${branch}_${l.head}",
),
Expand Down Expand Up @@ -84,7 +84,7 @@ object JmhBenchmarkWorkflow {
steps = downloadArtifacts("Main", batchSize) ++
Seq(
WorkflowStep.Use(
UseRef.Public("actions", "checkout", "v2"),
UseRef.Public("actions", "checkout", "v4"),
Map(
"path" -> "zio-http"
)
Expand Down Expand Up @@ -113,14 +113,15 @@ object JmhBenchmarkWorkflow {
),
scalas = List(Scala213),
steps = List(
WorkflowStep.Use(UseRef.Public("coursier", "setup-action","v1"), Map("apps" -> "sbt")),
WorkflowStep.Use(
UseRef.Public("actions", "checkout", "v2"),
UseRef.Public("actions", "checkout", "v4"),
Map(
"path" -> "zio-http",
),
),
WorkflowStep.Use(
UseRef.Public("actions", "setup-java", "v2"),
UseRef.Public("actions", "setup-java", "v4"),
Map(
"distribution" -> "temurin",
"java-version" -> "11",
Expand All @@ -137,7 +138,7 @@ object JmhBenchmarkWorkflow {
name = Some("Benchmark_Main"),
),
WorkflowStep.Use(
UseRef.Public("actions", "upload-artifact", "v3"),
UseRef.Public("actions", "upload-artifact", "v4"),
Map(
"name" -> s"Jmh_Main_${l.head}",
"path" -> s"Main_${l.head}.txt",
Expand Down
5 changes: 3 additions & 2 deletions project/ScoverageWorkFlow.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BuildHelper.{Scala213, ScoverageVersion}
import sbtghactions.GenerativePlugin.autoImport.{WorkflowJob, WorkflowStep}
import sbtghactions.GenerativePlugin.autoImport.{UseRef, WorkflowJob, WorkflowStep}

object ScoverageWorkFlow {
// TODO move plugins to plugins.sbt after scoverage's support for Scala 3
Expand All @@ -15,7 +15,8 @@ object ScoverageWorkFlow {
name = "Unsafe Scoverage",
scalas = List(Scala213),
steps = List(
WorkflowStep.CheckoutFull,
WorkflowStep.Use(UseRef.Public("actions", "checkout", "v4"), Map("fetch-depth" -> "0")),
WorkflowStep.Use(UseRef.Public("coursier", "setup-action","v1"), Map("apps" -> "sbt")),
WorkflowStep.Run(
commands = List(s"sed -i -e '$$a${scoveragePlugin}' project/plugins.sbt"),
id = Some("add_plugin"),
Expand Down
9 changes: 9 additions & 0 deletions zio-http-gen/src/test/resources/ComponentAliasKey.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package test.component

import zio.prelude.Newtype
import zio.schema.Schema
import java.util.UUID

object Key extends Newtype[UUID] {
implicit val schema: Schema[Key.Type] = Schema.primitive[UUID].transform(wrap, unwrap)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
info:
title: Dummy Service
version: 0.0.1
servers:
- url: http://127.0.0.1:5000/
tags:
- name: Dummy_API
paths:
/api/text_by_key:
get:
operationId: text_by_key
description: Get a dictionary mapping keys to text
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ObjectWithDictionary'
description: OK
openapi: 3.0.3
components:
schemas:
Key:
type: string
format: uuid
ObjectWithDictionary:
type: object
required:
- dict
properties:
dict:
type: object
additionalProperties:
type: string
x-string-key-schema:
$ref: '#/components/schemas/Key'
23 changes: 23 additions & 0 deletions zio-http-gen/src/test/scala/zio/http/gen/scala/CodeGenSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,29 @@ object CodeGenSpec extends ZIOSpecDefault {
}
}
} @@ TestAspect.exceptScala3,
test("Schema with newtype only referenced as dictionary key") {
val openAPIString = stringFromResource("/inline_schema_alias_only_as_key_schema.yaml")

openApiFromYamlString(openAPIString) { oapi =>
codeGenFromOpenAPI(
oapi,
Config.default.copy(generateSafeTypeAliases = true),
) { testDir =>
allFilesShouldBe(
testDir.toFile,
List(
"api/Text_by_key.scala",
"component/Key.scala",
"component/ObjectWithDictionary.scala",
),
) && fileShouldBe(
testDir,
"component/Key.scala",
"/ComponentAliasKey.scala",
)
}
}
} @@ TestAspect.exceptScala3,
test("Generate all responses") {
val oapi =
OpenAPI(
Expand Down
10 changes: 10 additions & 0 deletions zio-http-testkit/src/main/scala/zio/http/TestServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package zio.http

import zio._

import zio.http.netty.NettyConfig
import zio.http.netty.server.NettyDriver

/**
* Enables tests that make calls against "localhost" with user-specified
* Behavior/Responses.
Expand Down Expand Up @@ -136,4 +139,11 @@ object TestServer {
} yield TestServer(driver, result.port)
}

val default: ZLayer[Any, Nothing, Server with TestServer] = ZLayer.make[Server with TestServer][Nothing](
TestServer.layer.orDie,
ZLayer.succeed(Server.Config.default.onAnyOpenPort),
NettyDriver.customized.orDie,
ZLayer.succeed(NettyConfig.defaultWithFastShutdown),
)

}
Loading

0 comments on commit 4f7388c

Please sign in to comment.