From a6e9282dc1d6fdc3040a4ab633c904f55b0f6280 Mon Sep 17 00:00:00 2001 From: Nabil Abdel-Hafeez <7283535+987Nabil@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:15:43 +0200 Subject: [PATCH] Remove HttpApp from internal API and examples --- README.md | 6 +- docs/dsl/body.md | 4 +- docs/dsl/cookies.md | 12 +- docs/dsl/endpoint.md | 2 +- docs/dsl/flash.md | 18 +- docs/dsl/handler.md | 34 +-- docs/dsl/handler_aspect.md | 4 +- docs/dsl/headers.md | 21 +- docs/dsl/middleware.md | 28 +-- docs/dsl/path_codec.md | 14 +- docs/dsl/request.md | 8 +- docs/dsl/response.md | 24 +- docs/dsl/routes.md | 38 +--- docs/dsl/server.md | 42 ++-- docs/dsl/socket/socket.md | 2 +- .../http/benchmarks/EndpointBenchmark.scala | 47 ++-- .../zhttp.benchmarks/HttpCollectEval.scala | 4 +- .../zhttp.benchmarks/HttpCombineEval.scala | 2 +- .../ServerInboundHandlerBenchmark.scala | 2 +- .../scala/zio/http/endpoint/cli/CliSpec.scala | 6 +- .../scala/example/AuthenticationServer.scala | 4 +- .../src/main/scala/example/BasicAuth.scala | 4 +- .../src/main/scala/example/ClientServer.scala | 2 +- .../main/scala/example/ConcreteEntity.scala | 4 +- .../main/scala/example/CookieServerSide.scala | 2 +- .../main/scala/example/EndpointExamples.scala | 2 +- .../main/scala/example/FileStreaming.scala | 2 +- .../main/scala/example/GracefulShutdown.scala | 4 +- .../src/main/scala/example/HelloWorld.scala | 2 +- .../scala/example/HelloWorldAdvanced.scala | 4 +- .../scala/example/HelloWorldWithCORS.scala | 8 +- .../scala/example/HelloWorldWithMetrics.scala | 8 +- .../example/HelloWorldWithMiddlewares.scala | 4 +- .../main/scala/example/HtmlTemplating.scala | 4 +- .../main/scala/example/HttpsHelloWorld.scala | 4 +- .../src/main/scala/example/Interrupt.scala | 2 +- .../scala/example/MultipartFormData.scala | 4 +- .../example/MultipartFormDataStreaming.scala | 4 +- .../example/PlainTextBenchmarkServer.scala | 10 +- .../main/scala/example/RequestStreaming.scala | 2 +- .../src/main/scala/example/SSEServer.scala | 4 +- .../scala/example/ServeOnAnyOpenPort.scala | 2 +- .../example/ServerConfigurationExample.scala | 2 +- .../example/ServerResponseCompression.scala | 2 +- .../example/ServerSentEventEndpoint.scala | 4 +- .../src/main/scala/example/SignCookies.scala | 2 +- .../example/SimpleEffectBenchmarkServer.scala | 4 +- .../src/main/scala/example/StaticFiles.scala | 2 +- .../src/main/scala/example/StaticServer.scala | 2 +- .../scala/example/StreamingResponse.scala | 4 +- .../scala/example/WebSocketAdvanced.scala | 4 +- .../main/scala/example/WebSocketEcho.scala | 4 +- .../endpoint/BooksEndpointExample.scala | 2 +- .../scala/example/endpoint/CliExamples.scala | 2 +- .../example/endpoint/EndpointWithError.scala | 4 +- ...ndpointWithMultipleErrorsUsingEither.scala | 4 +- .../EndpointWithMultipleUnifiedErrors.scala | 4 +- .../src/main/scala/zio/http/TestClient.scala | 16 +- .../src/main/scala/zio/http/TestServer.scala | 10 +- .../scala/zio/http/SocketContractSpec.scala | 2 +- .../test/scala/zio/http/TestClientSpec.scala | 2 +- .../zio/http/netty/server/NettyDriver.scala | 10 +- .../netty/server/ServerInboundHandler.scala | 2 +- .../scala/zio/http/netty/server/package.scala | 2 +- .../test/scala/zio/http/ClientProxySpec.scala | 20 +- .../src/test/scala/zio/http/ClientSpec.scala | 18 +- .../scala/zio/http/ClientStreamingSpec.scala | 2 +- .../test/scala/zio/http/ContentTypeSpec.scala | 19 +- .../test/scala/zio/http/DynamicAppTest.scala | 8 +- .../src/test/scala/zio/http/FlashSpec.scala | 2 +- .../test/scala/zio/http/KeepAliveSpec.scala | 17 +- .../http/LogAnnotationMiddlewareSpec.scala | 6 +- .../scala/zio/http/MultipartMixedSpec.scala | 2 +- .../zio/http/NettyMaxHeaderLengthSpec.scala | 7 +- .../http/NettyMaxInitialLineLengthSpec.scala | 7 +- .../zio/http/RequestStreamingServerSpec.scala | 11 +- .../zio/http/ResponseCompressionSpec.scala | 6 +- .../src/test/scala/zio/http/RouteSpec.scala | 14 +- ...eSpec.scala => RoutesMiddlewareSpec.scala} | 2 +- .../{HttpAppSpec.scala => RoutesSpec.scala} | 10 +- .../jvm/src/test/scala/zio/http/SSLSpec.scala | 2 +- .../src/test/scala/zio/http/ServerSpec.scala | 136 ++++++------ .../test/scala/zio/http/ServerStartSpec.scala | 4 +- .../scala/zio/http/StaticFileServerSpec.scala | 16 +- .../scala/zio/http/StaticServerSpec.scala | 8 +- .../src/test/scala/zio/http/StatusSpec.scala | 2 +- .../test/scala/zio/http/WebSocketConfig.scala | 2 +- .../test/scala/zio/http/WebSocketSpec.scala | 10 +- .../scala/zio/http/ZClientAspectSpec.scala | 21 +- .../zio/http/endpoint/BadRequestSpec.scala | 18 +- .../zio/http/endpoint/CustomErrorSpec.scala | 31 +-- .../zio/http/endpoint/EndpointSpec.scala | 4 +- .../zio/http/endpoint/MultipartSpec.scala | 10 +- .../zio/http/endpoint/NotFoundSpec.scala | 10 +- .../http/endpoint/QueryParameterSpec.scala | 48 ++-- .../scala/zio/http/endpoint/RequestSpec.scala | 59 ++--- .../zio/http/endpoint/RoundtripSpec.scala | 79 ++++--- .../http/endpoint/openapi/SwaggerUISpec.scala | 2 +- .../zio/http/internal/DynamicServer.scala | 18 +- .../http/internal/HttpAppTestExtensions.scala | 2 +- .../zio/http/internal/HttpRunnableSpec.scala | 13 +- .../http/internal/middlewares/AuthSpec.scala | 16 +- .../http/internal/middlewares/CorsSpec.scala | 2 +- .../internal/middlewares/MetricsSpec.scala | 14 +- .../middlewares/RequestLoggingSpec.scala | 2 +- .../http/internal/middlewares/WebSpec.scala | 20 +- .../zio/http/netty/NettyStreamBodySpec.scala | 2 +- .../client/NettyConnectionPoolSpec.scala | 2 +- .../zio/http/HttpAppVersionSpecific.scala | 14 -- .../zio/http/HttpAppVersionSpecific.scala | 10 - .../src/main/scala/zio/http/Driver.scala | 2 +- .../src/main/scala/zio/http/Handler.scala | 18 +- .../main/scala/zio/http/HandlerAspect.scala | 23 +- .../src/main/scala/zio/http/HttpApp.scala | 210 +++--------------- .../src/main/scala/zio/http/Middleware.scala | 12 +- .../src/main/scala/zio/http/Route.scala | 7 +- .../src/main/scala/zio/http/Routes.scala | 193 ++++++++++------ .../src/main/scala/zio/http/Server.scala | 32 ++- .../src/main/scala/zio/http/Status.scala | 5 +- .../main/scala/zio/http/WebSocketApp.scala | 6 +- .../main/scala/zio/http/codec/PathCodec.scala | 4 +- .../zio/http/endpoint/openapi/SwaggerUI.scala | 92 -------- .../http/multipart/mixed/MultipartMixed.scala | 31 ++- 123 files changed, 807 insertions(+), 1050 deletions(-) rename zio-http/jvm/src/test/scala/zio/http/{HttpAppMiddlewareSpec.scala => RoutesMiddlewareSpec.scala} (97%) rename zio-http/jvm/src/test/scala/zio/http/{HttpAppSpec.scala => RoutesSpec.scala} (88%) delete mode 100644 zio-http/shared/src/main/scala-2/zio/http/HttpAppVersionSpecific.scala delete mode 100644 zio-http/shared/src/main/scala-3/zio/http/HttpAppVersionSpecific.scala diff --git a/README.md b/README.md index e706c44e5a..62a9bd6c61 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,10 @@ import zio.http._ object HelloWorld extends ZIOAppDefault { - val app: HttpApp[Any, Response] = - HttpApp( + val app: Routes[Any, Response] = + Routes( Method.GET / "text" -> handler(Response.text("Hello World!")) - ).toHttpApp + ) override val run = Server.serve(app).provide(Server.default) diff --git a/docs/dsl/body.md b/docs/dsl/body.md index e1a94d6c0a..929cac3e97 100644 --- a/docs/dsl/body.md +++ b/docs/dsl/body.md @@ -20,8 +20,8 @@ import zio._ import zio.http._ object HelloExample extends ZIOAppDefault { - val app: HttpApp[Any, Response] = - HttpApp( + val app: Routes[Any, Response] = + Routes( Method.GET / "hello" -> handler { req: Request => for { diff --git a/docs/dsl/cookies.md b/docs/dsl/cookies.md index cff5746e5b..6a0b1d53df 100644 --- a/docs/dsl/cookies.md +++ b/docs/dsl/cookies.md @@ -69,7 +69,7 @@ Let's write a simple example to see how it works: import zio.http._ object ResponseCookieExample extends ZIOAppDefault { - val httpApp = HttpApp( + val routes = Routes( Method.GET / "cookie" -> handler { Response.ok.addCookie( Cookie.Response(name = "user_id", content = "user123", maxAge = Some(5.days)) @@ -77,7 +77,7 @@ object ResponseCookieExample extends ZIOAppDefault { }, ) - def run = Server.serve(httpApp).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } ``` @@ -150,7 +150,7 @@ The cookies can be signed with a signature: ```scala mdoc:silent:nest val cookie = Cookie.Response("key", "hello", maxAge = Some(5.days)) val app = - HttpApp( + Routes( Method.GET / "cookie" -> handler { Response.ok.addCookie(cookie.sign("secret")) } @@ -164,7 +164,7 @@ To sign all the cookies in your routes, we can use `signCookies` middleware: ```scala mdoc:silent:nest import Middleware.signCookies -val app = HttpApp( +val app = Routes( Method.GET / "cookie" -> handler(Response.ok.addCookie(cookie)), Method.GET / "secure-cookie" -> handler(Response.ok.addCookie(cookie.copy(isSecure = true))) ) @@ -205,7 +205,7 @@ From HTTP requests, a single cookie can be retrieved with `Request#cookie`: ```scala mdoc:compile-only private val app4 = - HttpApp( + Routes( Method.GET / "cookie" -> handler { (req: Request) => val cookieContent = req.cookie("sessionId").map(_.content) Response.text(s"cookie content: $cookieContent") @@ -219,7 +219,7 @@ In HTTP requests, cookies are stored in the `Header.cookie` header: ```scala mdoc:compile-only private val app3 = - HttpApp( + Routes( Method.GET / "cookie" -> handler { (req: Request) => Response.text( req.header(Header.Cookie) diff --git a/docs/dsl/endpoint.md b/docs/dsl/endpoint.md index fa3176f378..34a7e6f554 100644 --- a/docs/dsl/endpoint.md +++ b/docs/dsl/endpoint.md @@ -268,7 +268,7 @@ object EndpointWithMultipleOutputTypes extends ZIOAppDefault { else Left(Quiz("What is the boiling point of water in Celsius?", 2)), ) }) - .toHttpApp).provide(Server.default, Scope.default) + .toRoutes).provide(Server.default, Scope.default) } ``` diff --git a/docs/dsl/flash.md b/docs/dsl/flash.md index 034914588a..eae8c561fd 100644 --- a/docs/dsl/flash.md +++ b/docs/dsl/flash.md @@ -157,7 +157,7 @@ object NotificationWithoutFlash extends ZIOAppDefault { } - def run = Server.serve(HttpApp(saveUserRoute, homeRoute)) + def run = Server.serve(Routes(saveUserRoute, homeRoute)) .provide(Server.default, ZLayer(Ref.make(List.empty[User]))) } ``` @@ -350,7 +350,7 @@ val getUsersRoute: Route[Ref[List[User]] with Flash.Backend, Nothing] = } yield Response.html(html ++ usersHTML) } - val app = HttpApp(saveUserRoute, getUsersRoute, homeRoute) + val app = Routes(saveUserRoute, getUsersRoute, homeRoute) def run = Server.serve(app).provide(Server.default, Flash.Backend.inMemory, ZLayer(Ref.make(List.empty[User]))) } @@ -520,7 +520,7 @@ object ui { } object SetGetBothFlashExample extends ZIOAppDefault { - val httpApp = HttpApp( + val routes = Routes( Method.GET / "set-flash" -> handler { val setBoth: Flash.Setter[(String, String)] = Flash.setNotice("The form was submitted successfully!") ++ @@ -538,7 +538,7 @@ object SetGetBothFlashExample extends ZIOAppDefault { }, ).sandbox - def run = Server.serve(httpApp).provide(Server.default, Flash.Backend.inMemory) + def run = Server.serve(routes).provide(Server.default, Flash.Backend.inMemory) } ``` @@ -555,7 +555,7 @@ import zio._ import zio.http._ object CookieBasedFlashExample extends ZIOAppDefault { - val httpApp = HttpApp( + val routes = Routes( Method.GET / "set-flash" -> handler { Response .seeOther(URL.root / "get-flash") @@ -570,7 +570,7 @@ object CookieBasedFlashExample extends ZIOAppDefault { }, ).sandbox - def run = Server.serve(httpApp).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } ``` @@ -609,7 +609,7 @@ import zio.http._ import zio.http.template._ object FlashBackendExample extends ZIOAppDefault { - val httpApp = HttpApp( + val routes = Routes( Method.GET / "set-flash" -> handler { for { flashBackend <- ZIO.service[Flash.Backend] @@ -627,7 +627,7 @@ object FlashBackendExample extends ZIOAppDefault { }, ).sandbox - def run = Server.serve(httpApp).provide(Server.default, Flash.Backend.inMemory) + def run = Server.serve(routes).provide(Server.default, Flash.Backend.inMemory) } ``` @@ -649,7 +649,7 @@ HTTP/1.1 200 OK content-type: text/plain content-length: 28 -The form was submitted successfully!⏎ +The form was submitted successfully! ``` :::note diff --git a/docs/dsl/handler.md b/docs/dsl/handler.md index f6aebf660f..acea8e010d 100644 --- a/docs/dsl/handler.md +++ b/docs/dsl/handler.md @@ -39,7 +39,7 @@ Let's look at some examples of creating handlers, using the `handler` smart cons import zio._ import zio.http._ -HttpApp( +Routes( // 1. A simple handler that returns a "Hello, World!" response Method.GET / "hello" -> @@ -202,7 +202,7 @@ Let's try an example: import zio.http._ import zio.stream._ -HttpApp( +Routes( Method.GET / "stream" -> Handler .fromStream( @@ -239,7 +239,7 @@ Now, let's try another example, this time using `fromStreamChunked`: import zio.http._ import zio.stream._ -HttpApp( +Routes( Method.GET / "stream" -> Handler .fromStreamChunked( @@ -273,7 +273,7 @@ import zio.http._ import zio.stream._ import zio.http.template._ -HttpApp( +Routes( Method.GET / "html" -> Handler.html( @@ -320,7 +320,7 @@ ZIP HTTP has a simple built-in template which is useful for creating simple HTML import zio.http._ import zio.http.template._ -HttpApp( +Routes( Method.GET / "hello" -> Handler.template("Hello world!")( html( @@ -396,7 +396,7 @@ import zio.http._ import zio.stream._ import zio.schema.codec.JsonCodec.zioJsonBinaryCodec -HttpApp( +Routes( Method.POST / "bounded-body-consumer" -> handler { (request: Request) => Handler @@ -418,7 +418,7 @@ The following example shows how to create a handler that takes an `Int` and `Req import zio.json._ import zio.http._ -HttpApp( +Routes( Method.GET / "users" / int("userId") -> Handler.fromFunction[(Int, Request)] { case (userId: Int, request: Request) => Response.json( @@ -455,7 +455,7 @@ Let's see an example: import zio.http._ import java.io.File -HttpApp( +Routes( Method.GET / "video" -> Handler.fromFile(new File("src/main/resources/TestVideoFile.mp4")), Method.GET / "text" -> @@ -472,7 +472,7 @@ Here is an example: ```scala mdoc:compile-only import zio.http._ -HttpApp( +Routes( Method.GET / "static" / trailing -> handler { // Path extractor val pathExtractor: Handler[Any, Nothing, (Path, Request), Path] = @@ -513,7 +513,7 @@ The following example shows how to create an echo server using the `Handler.webS import zio.http._ import zio.http.ChannelEvent._ -HttpApp( +Routes( Method.GET / "websocket" -> handler { Handler.webSocket { channel => @@ -548,7 +548,7 @@ Let's try an example: ```scala mdoc:compile-only import zio.http._ -HttpApp( +Routes( Method.GET / "stacktrace" -> handler { for { @@ -575,7 +575,7 @@ To attach a handler aspect to a handler, we use the `@@` operator. For instance, ```scala mdoc:compile-only import zio.http._ -HttpApp( +Routes( Method.GET / "echo" -> handler { req: Request => Handler.fromBody(req.body) }.flatten @@ HandlerAspect.requestLogging() @@ -602,7 +602,7 @@ Let's see an example: import zio.http._ import java.nio.file._ -HttpApp( +Routes( Method.GET / "file" -> Handler.fromFile(Paths.get("file.txt").toFile).sandbox, ) @@ -612,9 +612,9 @@ 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. -### Converting a `Handler` to an `HttpApp` +### Converting a `Handler` to an `Routes` -The `Handler#toHttpApp` operator, converts a handler to an `HttpApp` 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: +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: ```scala mdoc:compile-only import zio._ @@ -623,7 +623,7 @@ import zio.http._ object HelloWorldServer extends ZIOAppDefault { def run = Server - .serve(Handler.fromResponse(Response.text("Hello, world!")).toHttpApp) + .serve(Handler.fromResponse(Response.text("Hello, world!")).toRoutes) .provide(Server.default) } ``` @@ -714,7 +714,7 @@ The are similar to the `ZIO` ones, but they are specialized for the `Handler` ty The first type parameter of the `Handler` is the environment type. This means that a `Handler` can require an environment to run, like a `ZIO` effect. When we create a `Handler`, we can get access to the environment using `ZIO.service*` methods, and finally, we can provide the environment using `Handler#provide*` methods. :::note -Please note that in most cases, we are not required to provide the environment of the handler in the middle of the routes definition. It is usually done at the end when we are creating the `HttpApp` using the `Server#serve` method. +Please note that in most cases, we are not required to provide the environment of the handler in the middle of the routes definition. It is usually done at the end when we are creating the `Routes` using the `Server#serve` method. ::: :::note diff --git a/docs/dsl/handler_aspect.md b/docs/dsl/handler_aspect.md index 21e41209cd..bed8cd66bf 100644 --- a/docs/dsl/handler_aspect.md +++ b/docs/dsl/handler_aspect.md @@ -125,10 +125,10 @@ val statsMiddleware: Middleware[Ref[Map[String, Long]]] = } ``` -After attaching these two handler aspects to our `HttpApp`, we have to provide the initial state for the `Ref[Map[String, Long]]` to the whole application's environment: +After attaching these two handler aspects to our `Routes`, we have to provide the initial state for the `Ref[Map[String, Long]]` to the whole application's environment: ```scala -Server.serve(app @@ counterMiddleware @@ statsMiddleware) +Server.serve(routes @@ counterMiddleware @@ statsMiddleware) .provide( Server.default, ZLayer.fromZIO(Ref.make(Map.empty[String, Long])) diff --git a/docs/dsl/headers.md b/docs/dsl/headers.md index addfd0980c..ba20c954be 100644 --- a/docs/dsl/headers.md +++ b/docs/dsl/headers.md @@ -168,7 +168,7 @@ Response( ```scala mdoc import Middleware.addHeader -HttpApp(Method.GET / "hello" -> Handler.ok) @@ addHeader(Header.ContentLength(0L)) +Routes(Method.GET / "hello" -> Handler.ok) @@ addHeader(Header.ContentLength(0L)) ``` ### Reading Headers from Request @@ -176,7 +176,7 @@ HttpApp(Method.GET / "hello" -> Handler.ok) @@ addHeader(Header.ContentLength(0L On the Server-side you can read Request headers as given below: ```scala mdoc -HttpApp( +Routes( Method.GET / "streamOrNot" -> handler { (req: Request) => Response.text(req.headers.map(_.toString).mkString("\n")) } @@ -195,33 +195,32 @@ import zio.stream._ object SimpleResponseDispatcher extends ZIOAppDefault { override def run = - // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) - Server.serve(app).provide(Server.default) + // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) + Server.serve(routes).provide(Server.default) // Create a message as a Chunk[Byte] val message = Chunk.fromArray("Hello world !\r\n".getBytes(Charsets.Http)) - // Use `Http.collect` to match on route - val app: HttpApp[Any, Response] = - HttpApp( + val routes: Routes[Any, Response] = + Routes( // Simple (non-stream) based route Method.GET / "health" -> handler(Response.ok), // From Request(req), the headers are accessible. - Method.GET / "streamOrNot" -> - handler { (req: Request) => + Method.GET / "streamOrNot" -> + handler { (req: Request) => // Checking if client is able to handle streaming response val acceptsStreaming: Boolean = req.header(Header.Accept).exists(_.mimeTypes.contains(Header.Accept.MediaTypeWithQFactor(MediaType.application.`octet-stream`, None))) if (acceptsStreaming) Response( status = Status.Ok, body = Body.fromStream(ZStream.fromChunk(message), message.length.toLong), // Encoding content using a ZStream - ) + ) else { // Adding a custom header to Response Response(status = Status.Accepted, body = Body.fromChunk(message)).addHeader("X-MY-HEADER", "test") } } - ).sandbox + ).sandbox } ``` diff --git a/docs/dsl/middleware.md b/docs/dsl/middleware.md index cd8565c00c..cb7c0b5e0c 100644 --- a/docs/dsl/middleware.md +++ b/docs/dsl/middleware.md @@ -7,7 +7,7 @@ A middleware helps in addressing common crosscutting concerns without duplicatin ## Definition -Middleware can be conceptualized as a functional component that accepts a `Routes` and produces a new `Routes`. The defined trait, `Middleware`, is parameterized by a contravariant type `UpperEnv` which denotes it can access the environment of the `HttpApp`: +Middleware can be conceptualized as a functional component that accepts a `Routes` and produces a new `Routes`. The defined trait, `Middleware`, is parameterized by a contravariant type `UpperEnv` which denotes it can access the environment of the `Routes`: ```scala trait Middleware[-UpperEnv] { self => @@ -15,16 +15,16 @@ trait Middleware[-UpperEnv] { self => } ``` -This abstraction allows middleware to engage with the `HttpApp` environment, and also the ability to tweak existing routes or add/remove routes as needed. +This abstraction allows middleware to engage with the `Routes` environment, and also the ability to tweak existing routes or add/remove routes as needed. ## Usage -The `@@` operator attaches middleware to routes and HTTP applications. The example below shows a middleware attached to an `HttpApp`: +The `@@` operator attaches middleware to routes and HTTP applications. The example below shows a middleware attached to an `Routes`: ```scala mdoc:compile-only import zio.http._ -val app = HttpApp( +val app = Routes( Method.GET / string("name") -> handler { (name: String, req: Request) => Response.text(s"Hello $name") } @@ -39,23 +39,23 @@ Logically the code above translates to `Middleware.debug(app)`, which transforms We can attach multiple middlewares by chaining them using more `@@` operators: ```scala -val resultApp = httpApp @@ f1 @@ f2 @@ f3 +val resultApp = routes @@ f1 @@ f2 @@ f3 ``` -In the above code, when a new request comes in, it will first go through the `f3`'s incoming handler, then `f2`, then `f1`, and finally the `httpApp`, when the response is going out, it will go through the `f1`'s outgoing handler, then `f2`, then `f3`, and finally will be sent out. So **the order of the middlewares matters** and if we change the order of the middlewares, the application's behavior may change. +In the above code, when a new request comes in, it will first go through the `f3`'s incoming handler, then `f2`, then `f1`, and finally the `routes`, when the response is going out, it will go through the `f1`'s outgoing handler, then `f2`, then `f3`, and finally will be sent out. So **the order of the middlewares matters** and if we change the order of the middlewares, the application's behavior may change. ## Composing Middlewares Middleware can be combined using the `++` operator: ```scala -httpApp @@ (f1 ++ f2 ++ f3) +routes @@ (f1 ++ f2 ++ f3) ``` The `f1 ++ f2 ++ f3` applies from left to right with `f1` first followed by others, like this: ```scala -f3(f2(f1(httpApp))) +f3(f2(f1(routes))) ``` ## Motivation @@ -70,7 +70,7 @@ Consider the following example where we have two endpoints: * **GET /users** - Get all users ```scala -val routes = HttpApp( +val routes = Routes( Method.GET / "users" / int("id") -> handler { (id: Int, req: Request) => // core business logic @@ -152,7 +152,7 @@ val composedMiddlewares = Middleware.basicAuth("user","pw") ++ And then we can attach our composed bundle of middlewares to an Http using `@@` ```scala - val routes = HttpApp( + val routes = Routes( Method.GET / "users" / int("id") -> handler { (id: Int, req: Request) => // core business logic @@ -267,7 +267,7 @@ import utils._ printSource("zio-http-example/src/main/scala/example/HelloWorldWithMetrics.scala") ``` -Another important thing to note is that the `metrics` middleware only attaches to the `HttpApp` or `Routes`, so if we want to track some custom metrics particular to a handler, we can use the `ZIO#@@` operator to attach a metric of type `ZIOAspect` to the ZIO effect that is returned by the handler. For example, if we want to track the number of requests that have a custom header `X-Custom-Header` in the `/json` route, we can attach a counter metric to the ZIO effect that is returned by the handler using the `@@` operator. +Another important thing to note is that the `metrics` middleware only attaches to the `Routes` or `Routes`, so if we want to track some custom metrics particular to a handler, we can use the `ZIO#@@` operator to attach a metric of type `ZIOAspect` to the ZIO effect that is returned by the handler. For example, if we want to track the number of requests that have a custom header `X-Custom-Header` in the `/json` route, we can attach a counter metric to the ZIO effect that is returned by the handler using the `@@` operator. ### Timeout Middleware @@ -275,11 +275,11 @@ The `Middleware.timeout` middleware is used to set a timeout for the HTTP reques ```scala mdoc:invisible import zio.http._ -val httpApp: HttpApp[Any, Response] = Handler.ok.toHttpApp +val routes: Routes[Any, Response] = Handler.ok.toRoutes ``` ```scala mdoc:compile-only -httpApp @@ Middleware.timeout(5.seconds) +routes @@ Middleware.timeout(5.seconds) ``` ### Log Annotation Middleware @@ -312,7 +312,7 @@ val correlationId = To see the correlation ID in the logs, we need to place the middleware after the request logging middleware: ```scala mdoc:silent -httpApp @@ Middleware.requestLogging() @@ correlationId +routes @@ Middleware.requestLogging() @@ correlationId ``` Now, if we call one of the routes with the `X-Correlation-ID` header, we should see the correlation ID in the logs: diff --git a/docs/dsl/path_codec.md b/docs/dsl/path_codec.md index ad5d1e8bb9..d0521d1549 100644 --- a/docs/dsl/path_codec.md +++ b/docs/dsl/path_codec.md @@ -174,8 +174,8 @@ object Main extends ZIOAppDefault { val userId: PathCodec[UserId] = int("user-id").transformOrFailLeft(UserId.apply)(_.value) - val httpApp: HttpApp[Any, Response] = - HttpApp( + val routes: Routes[Any, Response] = + Routes( Method.GET / "users" / userId -> Handler.fromFunctionHandler[(UserId, Request)] { case (userId: UserId, request: Request) => Handler.text(userId.value.toString) @@ -190,7 +190,7 @@ object Main extends ZIOAppDefault { } } - def run = Server.serve(httpApp).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } ``` @@ -213,15 +213,15 @@ object TrailingExample extends ZIOAppDefault { Handler.notFound } yield http - val app = - HttpApp( + val routes = + Routes( Method.GET / "static" / trailing -> Handler.fromFunctionHandler[(Path, Request)] { case (path: Path, _: Request) => staticFileHandler(path).contramap[(Path, Request)](_._2) }, - ).sandbox @@ HandlerAspect.requestLogging() + ).sandbox @@ HandlerAspect.requestLogging() - val run = Server.serve(app).provide(Server.default) + val run = Server.serve(routes).provide(Server.default) } ``` diff --git a/docs/dsl/request.md b/docs/dsl/request.md index 71d727ff2b..ded9b0e066 100644 --- a/docs/dsl/request.md +++ b/docs/dsl/request.md @@ -13,7 +13,7 @@ To access the incoming request, we can use a `Handler` which takes a `Request` a import zio._ import zio.http._ -HttpApp( +Routes( Method.POST / "echo" -> handler { (req: Request) => req.body.asString(Charsets.Utf8).map(Response.text(_)).sandbox @@ -148,7 +148,7 @@ import zio.http._ object QueryParamExample extends ZIOAppDefault { val app = - HttpApp( + Routes( Method.GET / "search" -> handler { (req: Request) => val queries = req.queryParam("q") queries match { @@ -171,7 +171,7 @@ The typed version of `Request#queryParam` is `Request#queryParamTo` which takes import zio.http._ object TypedQueryParamExample extends ZIOAppDefault { val app = - HttpApp( + Routes( Method.GET / "search" -> Handler.fromFunctionHandler { (req: Request) => val response: ZIO[Any, QueryParamsError, Response] = ZIO.fromEither(req.queryParamTo[Int]("age")) @@ -204,7 +204,7 @@ import zio.http._ object QueryParamsExample extends ZIOAppDefault { val app = - HttpApp( + Routes( Method.GET / "search" -> handler { (req: Request) => val queries = req.queryParams("q") if (queries.nonEmpty) { diff --git a/docs/dsl/response.md b/docs/dsl/response.md index 4282cc2d8c..d86a3e3608 100644 --- a/docs/dsl/response.md +++ b/docs/dsl/response.md @@ -19,15 +19,15 @@ import zio._ import zio.http._ object HelloWorldExample extends ZIOAppDefault { - val app: HttpApp[Any, Response] = - HttpApp( + val routes: Routes[Any, Response] = + Routes( Method.GET / "text" -> handler { Response.text("Hello World!") }, - ) + ) - override val run = Server.serve(app).provide(Server.default) + override val run = Server.serve(routes).provide(Server.default) } ``` @@ -246,7 +246,7 @@ object ServerSentExample extends ZIOAppDefault { ) val app = - HttpApp( + Routes( Method.GET / "events" -> handler { Response.fromServerSentEvents(stream) }, @@ -295,8 +295,8 @@ import zio.http._ object WebsocketExample extends ZIOAppDefault { - val app: HttpApp[Any, Response] = { - HttpApp( + val routes: Routes[Any, Response] = { + Routes( Method.GET / "echo" -> handler { Response.fromSocketApp( WebSocketApp( @@ -304,18 +304,18 @@ object WebsocketExample extends ZIOAppDefault { channel.receiveAll { case ChannelEvent.Read(message) => channel.send(ChannelEvent.read(message)) - case other => + case other => ZIO.debug(other) } }, - ), - ) + ), + ) }, - ) + ) } def run = - Server.serve(app).provide(Server.default) + Server.serve(routes).provide(Server.default) } ``` diff --git a/docs/dsl/routes.md b/docs/dsl/routes.md index e5f6a850d9..bc74461a6f 100644 --- a/docs/dsl/routes.md +++ b/docs/dsl/routes.md @@ -10,7 +10,7 @@ Let's see an example of a simple `Routes` that has two routes: ```scala mdoc:compile-only import zio.http._ -HttpApp( +Routes( Method.GET / "hello" -> Handler.text("hello"), Method.GET / "health-check" -> Handler.ok, ) @@ -23,7 +23,7 @@ To build empty routes we have `Routes.empty` constructor: ```scala mdoc:silent import zio.http._ -val routes1 = HttpApp.empty +val routes1 = Routes.empty ``` We can build routes with the `Routes.apply` constructor, which takes varargs of individual `Route` values: @@ -40,7 +40,7 @@ object Routes { Example: ```scala mdoc:compile-only -HttpApp( +Routes( Method.GET / "hello" -> Handler.text("hello"), Method.GET / "health-check" -> Handler.ok, Method.POST / "echo" -> @@ -61,7 +61,7 @@ Using the `/` operator of `Method`, we can construct route patterns, which can t ```scala mdoc:silent val routes2 = - HttpApp( + Routes( Method.GET / "hello" -> Handler.ok, Method.GET / "goodbye" -> Handler.ok ) @@ -83,17 +83,17 @@ import zio.http.codec.PathCodec._ val routes = literal("nest1") / - HttpApp.fromIterable( + Routes.fromIterable( Chunk( Method.GET / "foo" -> Handler.text("foo"), Method.GET / "bar" -> Handler.text("bar"), ) ++ Chunk( - literal("nest2") / HttpApp( + literal("nest2") / Routes( Method.GET / "baz" -> Handler.text("baz"), Method.GET / "qux" -> Handler.text("qux"), ), - literal("nest2") / HttpApp( + literal("nest2") / Routes( Method.GET / "quux" -> Handler.text("quux"), Method.GET / "corge" -> Handler.text("corge"), ), @@ -195,34 +195,18 @@ trait Routes[-Env, +Err] { } ``` -## Converting `Routes` to `HttpApp` - -`HttpApp[-R]` represents a fully-specified HTTP application that can be executed by the server. - -When we are done building a collection of routes, our next step is typically to convert these routes into an HTTP application using the `Routes#toHttpApp` method, which we can then execute with the server. - -Routes may have handled or unhandled errors. If the error type of `Routes[Env, Err]` is equal to or a subtype of `Response`, we call this a route where all errors are handled. Otherwise, it's a route where some errors are unhandled. - -For instance, a route of type `Route[Env, Throwable]` has not handled its errors by converting them into responses. Consequently, such unfinished routes cannot be converted into HTTP applications. We must first handle errors using the `handleError` or `handleErrorCause` methods. - -By handling our errors, we ensure that clients interacting with our API will not encounter strange or unexpected responses, but will always be able to interact effectively with our web service, even in exceptional cases. - -:::note -If we aim to automatically convert our failures into suitable responses, without revealing details about the specific nature of the errors, we can utilize `Routes#sandbox`. After addressing our errors in this manner, we can proceed to convert our routes into an HTTP application. -::: - ## Running an App -ZIO HTTP server needs an `HttpApp[R]` for running. We can use `Server.serve()` method to bootstrap the server with -an `HttpApp[R]`: +ZIO HTTP server needs `Routes[Env, Response]` for running, so routes that have a `Response` as the error type. +We can use `Server.serve()` method to bootstrap the server with an instance of `Routes[Env, Response]`.: ```scala mdoc:compile-only import zio._ import zio.http._ object HelloWorld extends ZIOAppDefault { - val app: HttpApp[Any, Response] = Handler.ok.toHttpApp + val routes: Routes[Any, Response] = Handler.ok.toRoutes - override def run = Server.serve(app).provide(Server.default) + override def run = Server.serve(routes).provide(Server.default) } ``` diff --git a/docs/dsl/server.md b/docs/dsl/server.md index f8724e1ae2..80efe5ec2d 100644 --- a/docs/dsl/server.md +++ b/docs/dsl/server.md @@ -9,35 +9,35 @@ This section describes, ZIO HTTP Server and different configurations you can pro ## Starting a Server with Default Configurations -Assuming we have written an `HttpApp`: +Assuming we have written a `Routes`: ```scala mdoc:silent import zio.http._ import zio._ -def app: HttpApp[Any, Response] = - HttpApp( - Method.GET / "hello" -> +val routes: Routes[Any, Response] = + Routes( + Method.GET / "hello" -> handler(Response.text("Hello, World!")) - ) + ) ``` We can serve it using the `Server.serve` method: ```scala mdoc:silent -Server.serve(app).provide(Server.default) +Server.serve(routes).provide(Server.default) ``` By default, it will start the server on port `8080`. A quick shortcut to only customize the port is `Server.defaultWithPort`: ```scala mdoc:compile-only -Server.serve(app).provide(Server.defaultWithPort(8081)) +Server.serve(routes).provide(Server.defaultWithPort(8081)) ``` Or to customize more properties of the _default configuration_: ```scala mdoc:compile-only -Server.serve(app).provide( +Server.serve(routes).provide( Server.defaultWith( _.port(8081).enableRequestStreaming ) @@ -45,7 +45,7 @@ Server.serve(app).provide( ``` :::note -Sometimes we may want to have more control over installation of the http application into the server. In such cases, we may want to use the `Server.install` method. This method only installs the `HttpApp` into the server, and the lifecycle of the server can be managed separately. +Sometimes we may want to have more control over installation of the http application into the server. In such cases, we may want to use the `Server.install` method. This method only installs the `Routes` into the server, and the lifecycle of the server can be managed separately. ::: ## Starting a Server with Custom Configurations @@ -54,7 +54,7 @@ The `live` layer expects a `Server.Config` holding the custom configuration for ```scala mdoc:compile-only Server - .serve(app) + .serve(routes) .provide( ZLayer.succeed(Server.Config.default.port(8081)), Server.live @@ -159,10 +159,10 @@ import zio._ import zio.http._ object KeepAliveExample extends ZIOAppDefault { - val httpApp = handler(Response.text("Hello World!")).toHttpApp + val routes = handler(Response.text("Hello World!")).toRoutes override val run = - Server.serve(httpApp).provide(Server.default) + Server.serve(routes).provide(Server.default) } ``` @@ -175,7 +175,7 @@ content-type: text/plain content-length: 12 connection: close -Hello World!⏎ +Hello World! ``` However, with the `Connection: Keep-Alive` header, the client can request that the connection remain open after the initial request, allowing for subsequent requests to be sent over the same connection without needing to establish a new one each time. @@ -224,7 +224,7 @@ The `configured` layer loads the server configuration using the application's _Z ```scala mdoc:compile-only Server - .serve(app) + .serve(routes) .provide( Server.configured() ) @@ -233,9 +233,9 @@ Server For example, to load the server configuration from the hocon file, we should add the `zio-config-typesafe` dependency to our `build.sbt` file: ```scala -libraryDependencies += "dev.zio" %% "zio-config" % "", -libraryDependencies += "dev.zio" %% "zio-config-magnolia" % "", -libraryDependencies += "dev.zio" %% "zio-config-typesafe" % "", +libraryDependencies += "dev.zio" %% "zio-config" % "" +libraryDependencies += "dev.zio" %% "zio-config-magnolia" % "" +libraryDependencies += "dev.zio" %% "zio-config-typesafe" % "" ``` And put the `application.conf` file in the `src/main/resources` directory: @@ -278,7 +278,7 @@ object EchoServerWithDecompression extends ZIOAppDefault { .serve( handler { (req: Request) => req.body.asString.map(Response.text) - }.sandbox.toHttpApp, + }.sandbox.toRoutes, ) .provide(Server.live, ZLayer.succeed(Server.Config.default.requestDecompression(true))) } @@ -405,8 +405,8 @@ import zio.stream.{ZSink, ZStream} object RequestStreamingServerExample extends ZIOAppDefault { def logBytes = (b: Byte) => ZIO.log(s"received byte: $b") - private val app: HttpApp[Any, Response] = - HttpApp( + private val routes: Routes[Any, Response] = + Routes( Method.POST / "upload-stream" / "simple" -> handler { (req: Request) => for { count <- req.body.asStream.tap(logBytes).run(ZSink.count) @@ -442,7 +442,7 @@ object RequestStreamingServerExample extends ZIOAppDefault { override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = Server - .serve(app) + .serve(routes) .provide( ZLayer.succeed(Server.Config.default.enableRequestStreaming), Server.live, diff --git a/docs/dsl/socket/socket.md b/docs/dsl/socket/socket.md index c6c3bdd937..1685da9805 100644 --- a/docs/dsl/socket/socket.md +++ b/docs/dsl/socket/socket.md @@ -18,7 +18,7 @@ val socket = Handler.webSocket { channel => } } -val http = HttpApp( +val http = Routes( Method.GET / "subscriptions" -> handler(socket.toResponse) ) ``` diff --git a/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala b/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala index 9155cdf095..5b1331509a 100644 --- a/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala +++ b/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala @@ -101,10 +101,10 @@ class EndpointBenchmark { } } - val apiHttpApp = handledUsersPosts.toHttpApp + val apiRoutes = handledUsersPosts.toRoutes // Collect DSL - val collectHttpApp = HttpApp( + val collectdRoutes = Routes( Method.GET / "users" / int("userId") / "posts" / int("postId") -> handler { (userIdInt: Int, postIdInt: Int, req: Request) => val query = req.url.queryParam("query").get @@ -171,13 +171,13 @@ class EndpointBenchmark { @Benchmark def benchmarkSmallDataZioApi(): Unit = unsafeRun { - apiHttpApp.runZIO(smallDataRequest).repeatN(REPEAT_N) + apiRoutes.runZIO(smallDataRequest).repeatN(REPEAT_N) } @Benchmark def benchmarkSmallDataZioCollect(): Unit = unsafeRun { - collectHttpApp.runZIO(smallDataRequest).repeatN(REPEAT_N) + collectdRoutes.runZIO(smallDataRequest).repeatN(REPEAT_N) } // @Benchmark @@ -208,7 +208,7 @@ class EndpointBenchmark { // API DSL - val deepPathHttpApp = Endpoint( + val deepPathRoutes = Endpoint( Method.GET / "first" / int("id1") / "second" / int("id2") / "third" / int( @@ -219,11 +219,12 @@ class EndpointBenchmark { ) .out[Unit] .implement(Handler.unit) - .toHttpApp + .toRoutes + // Collect DSL - val deepPathCollectHttpApp = HttpApp( + val deepPathCollectHttpApp = Routes( Method.GET / "first" / int("id1") / "second" / int("id2") / "third" / int("id3") / "fourth" / int( "id4", ) / "fifth" / int("id5") / "sixth" / int("id6") / "seventh" / int("id7") -> @@ -281,7 +282,7 @@ class EndpointBenchmark { @Benchmark def benchmarkDeepPathZioApi(): Unit = unsafeRun { - deepPathHttpApp.runZIO(deepPathRequest).repeatN(REPEAT_N) + deepPathRoutes.runZIO(deepPathRequest).repeatN(REPEAT_N) } @Benchmark @@ -418,7 +419,7 @@ class EndpointBenchmark { .implement(Handler.unit) val broadApiApp = - HttpApp( + Routes( broadUsers, broadUsersId, boardUsersPosts, @@ -439,56 +440,56 @@ class EndpointBenchmark { // Collect DSL - val broadCollectApp = HttpApp( + val broadCollectApp = Routes( Method.GET / "users" / int("userId") / "posts" / int("postId") / "comments" / int("commentId") -> handler { - (userId: Int, postId: Int, commentId: Int, request: Request) => + (_: Int, _: Int, _: Int, _: Request) => Response() }, Method.GET / "users" / int("userId") / "posts" / int("postId") / "comments" -> handler { - (userId: Int, postId: Int, req: Request) => + (_: Int, _: Int, _: Request) => Response() }, Method.GET / "users" / int("userId") / "posts" / int("postId") -> handler { - (userId: Int, postId: Int, req: Request) => + (_: Int, _: Int, _: Request) => Response() }, - Method.GET / "users" / int("userId") / "posts" -> handler { (userId: Int, req: Request) => + Method.GET / "users" / int("userId") / "posts" -> handler { (_: Int, _: Request) => Response() }, - Method.GET / "users" / int("userId") -> handler { (userId: Int, req: Request) => + Method.GET / "users" / int("userId") -> handler { (_: Int, _: Request) => Response() }, Method.GET / "users" -> handler(Response()), Method.GET / "posts" / int("postId") / "comments" / int("commentId") -> handler { - (postId: Int, commentId: Int, req: Request) => + (_: Int, _: Int, _: Request) => Response() }, - Method.GET / "posts" / int("postId") / "comments" -> handler { (postId: Int, req: Request) => + Method.GET / "posts" / int("postId") / "comments" -> handler { (_: Int, _: Request) => Response() }, - Method.GET / "posts" / int("postId") -> handler { (postId: Int, req: Request) => + Method.GET / "posts" / int("postId") -> handler { (_: Int, _: Request) => Response() }, Method.GET / "posts" -> handler(Response()), - Method.GET / "comments" / int("commentId") -> handler { (commentId: Int, req: Request) => + Method.GET / "comments" / int("commentId") -> handler { (_: Int, _: Request) => Response() }, Method.GET / "comments" -> handler(Response()), - Method.GET / "users" / int("userId") / "comments" -> handler { (userId: Int, req: Request) => + Method.GET / "users" / int("userId") / "comments" -> handler { (_: Int, _: Request) => Response() }, Method.GET / "users" / int("userId") / "comments" / int("commentId") -> handler { - (userId: Int, commentId: Int, req: Request) => + (_: Int, _: Int, _: Request) => Response() }, Method.GET / "users" / int("userId") / "posts" / int("postId") / "comments" / int("commentId") / "replies" / int( "replyId", - ) -> handler { (userId: Int, postId: Int, commentId: Int, replyId: Int, req: Request) => + ) -> handler { (_: Int, _: Int, _: Int, _: Int, _: Request) => Response() }, Method.GET / "users" / int("userId") / "posts" / int("postId") / "comments" / int( "commentId", - ) / "replies" -> handler { (userId: Int, postId: Int, commentId: Int, req: Request) => + ) / "replies" -> handler { (_: Int, _: Int, _: Int, _: Request) => Response() }, ) diff --git a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCollectEval.scala b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCollectEval.scala index 5fe7e8362f..ceb15bcf25 100644 --- a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCollectEval.scala +++ b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCollectEval.scala @@ -15,8 +15,8 @@ class HttpCollectEval { private val MAX = 10000 private val req = Request() private val res = Response.ok - private val app = HttpApp.singleton(handler(res)) - private val http = HttpApp(Route.route(Method.ANY / "text")(handler(res))) + private val app = Routes.singleton(handler(res)) + private val http = Routes(Route.route(Method.ANY / "text")(handler(res))) private val base: PartialFunction[Int, Int] = { case 0 => 1 } private val baseTotal: Int => Int = _ => 1 diff --git a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCombineEval.scala b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCombineEval.scala index e65989a71d..884eebca4d 100644 --- a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCombineEval.scala +++ b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpCombineEval.scala @@ -15,7 +15,7 @@ class HttpCombineEval { private val req = Request.get("/foo") private val res = Response.ok private val MAX = 1000 - private val app = HttpApp(Method.GET / "" -> handler(res)) + private val app = Routes(Method.GET / "" -> handler(res)) private val spec = (0 to MAX).foldLeft(app)((a, _) => a ++ app) @Benchmark diff --git a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/ServerInboundHandlerBenchmark.scala b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/ServerInboundHandlerBenchmark.scala index 247b9171e4..9e54956dc5 100644 --- a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/ServerInboundHandlerBenchmark.scala +++ b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/ServerInboundHandlerBenchmark.scala @@ -59,7 +59,7 @@ class ServerInboundHandlerBenchmark { private def shutdownRoute(shutdownSignal: Promise[Nothing, Unit]) = Route.route(Method.GET / shutdownEndpoint)(handler(shutdownSignal.succeed(()).as(shutdownResponse))) private def http(shutdownSignal: Promise[Nothing, Unit]) = - HttpApp(testRoute, arrayRoute, chunkRoute, shutdownRoute(shutdownSignal)) + Routes(testRoute, arrayRoute, chunkRoute, shutdownRoute(shutdownSignal)) @Setup(Level.Trial) def setup(): Unit = { diff --git a/zio-http-cli/src/test/scala/zio/http/endpoint/cli/CliSpec.scala b/zio-http-cli/src/test/scala/zio/http/endpoint/cli/CliSpec.scala index ba86dd84f9..2a3418ff94 100644 --- a/zio-http-cli/src/test/scala/zio/http/endpoint/cli/CliSpec.scala +++ b/zio-http-cli/src/test/scala/zio/http/endpoint/cli/CliSpec.scala @@ -46,11 +46,11 @@ object CliSpec extends ZIOSpecDefault { val testClient: ZLayer[Any, Nothing, TestClient & Client] = ZLayer.scopedEnvironment { for { - behavior <- Ref.make[HttpApp[Any, Response]](HttpApp.empty) + behavior <- Ref.make[Routes[Any, Response]](Routes.empty) socketBehavior <- Ref.make[WebSocketApp[Any]](WebSocketApp(Handler.unit)) driver = TestClient(behavior, socketBehavior) - _ <- driver.addHttpApp { - HttpApp( + _ <- driver.addRoutes { + Routes( Method.GET / "fromURL" -> handler(Response.text("342.76")), Method.GET / trailing -> handler { (_: Path, request: Request) => val headers = request.headers diff --git a/zio-http-example/src/main/scala/example/AuthenticationServer.scala b/zio-http-example/src/main/scala/example/AuthenticationServer.scala index 2958dc2871..7bf79206b5 100644 --- a/zio-http-example/src/main/scala/example/AuthenticationServer.scala +++ b/zio-http-example/src/main/scala/example/AuthenticationServer.scala @@ -43,8 +43,8 @@ object AuthenticationServer extends ZIOAppDefault { } }) - def app: HttpApp[Any, Response] = - HttpApp( + def app: Routes[Any, Response] = + Routes( // A route that is accessible only via a jwt token Method.GET / "profile" / "me" -> handler { (_: Request) => ZIO.serviceWith[String](name => Response.text(s"Welcome $name!")) diff --git a/zio-http-example/src/main/scala/example/BasicAuth.scala b/zio-http-example/src/main/scala/example/BasicAuth.scala index 632feba915..3f3bc9f4ad 100644 --- a/zio-http-example/src/main/scala/example/BasicAuth.scala +++ b/zio-http-example/src/main/scala/example/BasicAuth.scala @@ -9,7 +9,7 @@ import zio.http.codec.PathCodec.string object BasicAuth extends ZIOAppDefault { // Http app that requires a JWT claim - val user: HttpApp[Any, Response] = HttpApp( + val user: Routes[Any, Response] = Routes( Method.GET / "user" / string("name") / "greet" -> handler { (name: String, _: Request) => Response.text(s"Welcome to the ZIO party! ${name}") @@ -17,7 +17,7 @@ object BasicAuth extends ZIOAppDefault { ) // Composing all the HttpApps together - val app: HttpApp[Any, Response] = user @@ basicAuth("admin", "admin") + val app: Routes[Any, Response] = user @@ basicAuth("admin", "admin") // Run it like any simple app val run = Server.serve(app).provide(Server.default) diff --git a/zio-http-example/src/main/scala/example/ClientServer.scala b/zio-http-example/src/main/scala/example/ClientServer.scala index 9a1f9e9eba..c38ada0635 100644 --- a/zio-http-example/src/main/scala/example/ClientServer.scala +++ b/zio-http-example/src/main/scala/example/ClientServer.scala @@ -7,7 +7,7 @@ import zio.http._ object ClientServer extends ZIOAppDefault { val url = URL.decode("http://localhost:8080/hello").toOption.get - val app = HttpApp( + val app = Routes( Method.GET / "hello" -> handler(Response.text("hello")), Method.GET / "" -> handler(ZClient.request(Request.get(url))), ).sandbox diff --git a/zio-http-example/src/main/scala/example/ConcreteEntity.scala b/zio-http-example/src/main/scala/example/ConcreteEntity.scala index 4c7b3edfac..5e2aab6303 100644 --- a/zio-http-example/src/main/scala/example/ConcreteEntity.scala +++ b/zio-http-example/src/main/scala/example/ConcreteEntity.scala @@ -19,11 +19,11 @@ object ConcreteEntity extends ZIOAppDefault { UserCreated(2) } - val app: HttpApp[Any, Response] = + val app: Routes[Any, Response] = user .contramap[Request](req => CreateUser(req.path.encode)) // Http[Any, Nothing, Request, UserCreated] .map(userCreated => Response.text(userCreated.id.toString)) // Http[Any, Nothing, Request, Response] - .toHttpApp + .toRoutes // Run it like any simple app val run = diff --git a/zio-http-example/src/main/scala/example/CookieServerSide.scala b/zio-http-example/src/main/scala/example/CookieServerSide.scala index a596422b6e..0edbddc484 100644 --- a/zio-http-example/src/main/scala/example/CookieServerSide.scala +++ b/zio-http-example/src/main/scala/example/CookieServerSide.scala @@ -13,7 +13,7 @@ object CookieServerSide extends ZIOAppDefault { private val cookie = Cookie.Response("key", "value", maxAge = Some(5 days)) val res = Response.ok.addCookie(cookie) - private val app = HttpApp( + private val app = Routes( Method.GET / "cookie" -> handler(Response.ok.addCookie(cookie.copy(path = Some(Path.root / "cookie"), isHttpOnly = true))), Method.GET / "secure-cookie" -> diff --git a/zio-http-example/src/main/scala/example/EndpointExamples.scala b/zio-http-example/src/main/scala/example/EndpointExamples.scala index ba226bd67d..490cc99bf0 100644 --- a/zio-http-example/src/main/scala/example/EndpointExamples.scala +++ b/zio-http-example/src/main/scala/example/EndpointExamples.scala @@ -39,7 +39,7 @@ object EndpointExamples extends ZIOAppDefault { val openAPI = OpenAPIGen.fromEndpoints(title = "Endpoint Example", version = "1.0", getUser, getUserPosts) - val routes = HttpApp(getUserRoute, getUserPostsRoute) ++ SwaggerUI.app("docs" / "openapi", openAPI) + val routes = Routes(getUserRoute, getUserPostsRoute) ++ SwaggerUI.routes("docs" / "openapi", openAPI) val app = routes // (auth.implement(_ => ZIO.unit)(_ => ZIO.unit)) diff --git a/zio-http-example/src/main/scala/example/FileStreaming.scala b/zio-http-example/src/main/scala/example/FileStreaming.scala index b4aebc57bb..9226ae402a 100644 --- a/zio-http-example/src/main/scala/example/FileStreaming.scala +++ b/zio-http-example/src/main/scala/example/FileStreaming.scala @@ -12,7 +12,7 @@ import zio.http._ object FileStreaming extends ZIOAppDefault { // Create HTTP route - val app = HttpApp( + val app = Routes( Method.GET / "health" -> Handler.ok, // Read the file as ZStream diff --git a/zio-http-example/src/main/scala/example/GracefulShutdown.scala b/zio-http-example/src/main/scala/example/GracefulShutdown.scala index a949c9b90d..d473f89c98 100644 --- a/zio-http-example/src/main/scala/example/GracefulShutdown.scala +++ b/zio-http-example/src/main/scala/example/GracefulShutdown.scala @@ -22,12 +22,12 @@ import zio.http._ object GracefulShutdown extends ZIOAppDefault { - val app: HttpApp[Any, Response] = Handler + val app: Routes[Any, Response] = Handler .fromFunctionZIO[Request] { _ => ZIO.sleep(10.seconds).debug("request handler delay done").as(Response.text("done")) } .sandbox - .toHttpApp + .toRoutes override def run: ZIO[Any, Throwable, Unit] = (for { diff --git a/zio-http-example/src/main/scala/example/HelloWorld.scala b/zio-http-example/src/main/scala/example/HelloWorld.scala index 43904881c1..ac51eb00e0 100644 --- a/zio-http-example/src/main/scala/example/HelloWorld.scala +++ b/zio-http-example/src/main/scala/example/HelloWorld.scala @@ -12,7 +12,7 @@ object HelloWorld extends ZIOAppDefault { Method.GET / "json" -> handler(Response.json("""{"greetings": "Hello World!"}""")) // Create HTTP route - val app = HttpApp(textRoute, jsonRoute) + val app = Routes(textRoute, jsonRoute) // Run it like any simple app override val run = Server.serve(app).provide(Server.default) diff --git a/zio-http-example/src/main/scala/example/HelloWorldAdvanced.scala b/zio-http-example/src/main/scala/example/HelloWorldAdvanced.scala index 325cf715be..c033117c13 100644 --- a/zio-http-example/src/main/scala/example/HelloWorldAdvanced.scala +++ b/zio-http-example/src/main/scala/example/HelloWorldAdvanced.scala @@ -13,12 +13,12 @@ object HelloWorldAdvanced extends ZIOAppDefault { val PORT = 0 val fooBar = - HttpApp( + Routes( Method.GET / "foo" -> Handler.from(Response.text("bar")), Method.GET / "bar" -> Handler.from(Response.text("foo")), ) - val app = HttpApp( + val app = Routes( Method.GET / "random" -> handler(Random.nextString(10).map(Response.text(_))), Method.GET / "utc" -> handler(Clock.currentDateTime.map(s => Response.text(s.toString))), ) diff --git a/zio-http-example/src/main/scala/example/HelloWorldWithCORS.scala b/zio-http-example/src/main/scala/example/HelloWorldWithCORS.scala index d0e88f0e1f..87fa39a258 100644 --- a/zio-http-example/src/main/scala/example/HelloWorldWithCORS.scala +++ b/zio-http-example/src/main/scala/example/HelloWorldWithCORS.scala @@ -18,13 +18,13 @@ object HelloWorldWithCORS extends ZIOAppDefault { }, ) - val backend: HttpApp[Any, Response] = - HttpApp( + val backend: Routes[Any, Response] = + Routes( Method.GET / "json" -> handler(Response.json("""{"message": "Hello World!"}""")), ) @@ cors(config) - val frontend: HttpApp[Any, Response] = - HttpApp( + val frontend: Routes[Any, Response] = + Routes( Method.GET / PathCodec.empty -> handler( Response.html( html( diff --git a/zio-http-example/src/main/scala/example/HelloWorldWithMetrics.scala b/zio-http-example/src/main/scala/example/HelloWorldWithMetrics.scala index 834222fa67..0ba824f884 100644 --- a/zio-http-example/src/main/scala/example/HelloWorldWithMetrics.scala +++ b/zio-http-example/src/main/scala/example/HelloWorldWithMetrics.scala @@ -9,8 +9,8 @@ import zio.http._ object HelloWorldWithMetrics extends ZIOAppDefault { - val backend: HttpApp[Any, Response] = - HttpApp( + val backend: Routes[Any, Response] = + Routes( Method.GET / "json" -> handler((req: Request) => ZIO.succeed(Response.json("""{"message": "Hello World!"}""")) @@ Metric .counter("x_custom_header_total") @@ -19,8 +19,8 @@ object HelloWorldWithMetrics extends ZIOAppDefault { Method.GET / "forbidden" -> handler(ZIO.succeed(Response.forbidden)), ) @@ Middleware.metrics() - val metrics: HttpApp[PrometheusPublisher, Response] = - HttpApp( + val metrics: Routes[PrometheusPublisher, Response] = + Routes( Method.GET / "metrics" -> handler(ZIO.serviceWithZIO[PrometheusPublisher](_.get.map(Response.text))), ) diff --git a/zio-http-example/src/main/scala/example/HelloWorldWithMiddlewares.scala b/zio-http-example/src/main/scala/example/HelloWorldWithMiddlewares.scala index 4d01d2cf7c..b3054adadc 100644 --- a/zio-http-example/src/main/scala/example/HelloWorldWithMiddlewares.scala +++ b/zio-http-example/src/main/scala/example/HelloWorldWithMiddlewares.scala @@ -8,12 +8,12 @@ import zio.http._ object HelloWorldWithMiddlewares extends ZIOAppDefault { - val app: HttpApp[Any, Response] = Routes( + val app: Routes[Any, Response] = Routes( // this will return result instantly Method.GET / "text" -> handler(ZIO.succeed(Response.text("Hello World!"))), // this will return result after 5 seconds, so with 3 seconds timeout it will fail Method.GET / "long-running" -> handler(ZIO.succeed(Response.text("Hello World!")).delay(5 seconds)), - ).toHttpApp + ) val serverTime = Middleware.patchZIO(_ => for { diff --git a/zio-http-example/src/main/scala/example/HtmlTemplating.scala b/zio-http-example/src/main/scala/example/HtmlTemplating.scala index 216d12642c..5a2273bd98 100644 --- a/zio-http-example/src/main/scala/example/HtmlTemplating.scala +++ b/zio-http-example/src/main/scala/example/HtmlTemplating.scala @@ -8,7 +8,7 @@ object HtmlTemplating extends ZIOAppDefault { // Importing everything from `zio.html` import zio.http.template._ - def app: HttpApp[Any, Response] = { + def app: Routes[Any, Response] = { // Html response takes in a `Html` instance. Handler.html { @@ -45,7 +45,7 @@ object HtmlTemplating extends ZIOAppDefault { ), ) } - }.toHttpApp + }.toRoutes def run = Server.serve(app).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/HttpsHelloWorld.scala b/zio-http-example/src/main/scala/example/HttpsHelloWorld.scala index dc99f5a24d..0c0918045d 100644 --- a/zio-http-example/src/main/scala/example/HttpsHelloWorld.scala +++ b/zio-http-example/src/main/scala/example/HttpsHelloWorld.scala @@ -6,10 +6,10 @@ import zio.http._ object HttpsHelloWorld extends ZIOAppDefault { // Create HTTP route - val app: HttpApp[Any, Response] = Routes( + val app: Routes[Any, Response] = Routes( Method.GET / "text" -> handler(Response.text("Hello World!")), Method.GET / "json" -> handler(Response.json("""{"greetings": "Hello World!"}""")), - ).toHttpApp + ) /** * In this example, a private key and certificate are loaded from resources. diff --git a/zio-http-example/src/main/scala/example/Interrupt.scala b/zio-http-example/src/main/scala/example/Interrupt.scala index cb753b59b7..29f3bec3b8 100644 --- a/zio-http-example/src/main/scala/example/Interrupt.scala +++ b/zio-http-example/src/main/scala/example/Interrupt.scala @@ -16,7 +16,7 @@ object MyServer extends ZIOAppDefault { handler(ZIO.sleep(10.seconds).map(_ => Response.text("done")).onExit { e => Console.printLine(e).exit }), - ).toHttpApp + ) def run = Server.serve(app).provide(Server.default) diff --git a/zio-http-example/src/main/scala/example/MultipartFormData.scala b/zio-http-example/src/main/scala/example/MultipartFormData.scala index 8beb8018cb..e3f4963342 100644 --- a/zio-http-example/src/main/scala/example/MultipartFormData.scala +++ b/zio-http-example/src/main/scala/example/MultipartFormData.scala @@ -6,7 +6,7 @@ import zio.http._ object MultipartFormData extends ZIOAppDefault { - private val app: HttpApp[Any, Response] = + private val app: Routes[Any, Response] = Routes( Method.POST / "upload" -> handler { (req: Request) => @@ -39,7 +39,7 @@ object MultipartFormData extends ZIOAppDefault { } yield response else ZIO.succeed(Response(status = Status.NotFound)) }, - ).sandbox.toHttpApp + ).sandbox private def program: ZIO[Client with Server with Scope, Throwable, Unit] = for { diff --git a/zio-http-example/src/main/scala/example/MultipartFormDataStreaming.scala b/zio-http-example/src/main/scala/example/MultipartFormDataStreaming.scala index 53ae425d43..5c2fd39c8c 100644 --- a/zio-http-example/src/main/scala/example/MultipartFormDataStreaming.scala +++ b/zio-http-example/src/main/scala/example/MultipartFormDataStreaming.scala @@ -8,7 +8,7 @@ import zio.http._ object MultipartFormDataStreaming extends ZIOAppDefault { - private val app: HttpApp[Any, Response] = + private val app: Routes[Any, Response] = Routes( Method.POST / "upload-simple" -> handler { (req: Request) => for { @@ -61,7 +61,7 @@ object MultipartFormDataStreaming extends ZIOAppDefault { } yield Response.text(count.toString) else ZIO.succeed(Response(status = Status.NotFound)) }, - ).sandbox.toHttpApp @@ Middleware.debug + ).sandbox @@ Middleware.debug private def program: ZIO[Server, Throwable, Unit] = for { diff --git a/zio-http-example/src/main/scala/example/PlainTextBenchmarkServer.scala b/zio-http-example/src/main/scala/example/PlainTextBenchmarkServer.scala index c352ed68f8..c76af9aba7 100644 --- a/zio-http-example/src/main/scala/example/PlainTextBenchmarkServer.scala +++ b/zio-http-example/src/main/scala/example/PlainTextBenchmarkServer.scala @@ -29,13 +29,13 @@ object PlainTextBenchmarkServer extends ZIOAppDefault { // .serverTime .addHeader(Header.Server(STATIC_SERVER_NAME)) - private def plainTextApp(response: Response): HttpApp[Any, Response] = - Routes(Method.GET / plaintextPath -> Handler.fromResponse(response)).toHttpApp + private def plainTextApp(response: Response): Routes[Any, Response] = + Routes(Method.GET / plaintextPath -> Handler.fromResponse(response)) - private def jsonApp(json: Response): HttpApp[Any, Response] = - Routes(Method.GET / jsonPath -> Handler.fromResponse(json)).toHttpApp + private def jsonApp(json: Response): Routes[Any, Response] = + Routes(Method.GET / jsonPath -> Handler.fromResponse(json)) - val app: HttpApp[Any, Response] = plainTextApp(frozenPlainTextResponse) ++ jsonApp(frozenJsonResponse) + val app: Routes[Any, Response] = plainTextApp(frozenPlainTextResponse) ++ jsonApp(frozenJsonResponse) private val config = Server.Config.default .port(8080) diff --git a/zio-http-example/src/main/scala/example/RequestStreaming.scala b/zio-http-example/src/main/scala/example/RequestStreaming.scala index bd8166a29c..919c8ea466 100644 --- a/zio-http-example/src/main/scala/example/RequestStreaming.scala +++ b/zio-http-example/src/main/scala/example/RequestStreaming.scala @@ -17,7 +17,7 @@ object RequestStreaming extends ZIOAppDefault { val data = Body.fromStreamChunked(stream) Response(body = data) - }).toHttpApp + }) // Run it like any simple app val run: UIO[ExitCode] = diff --git a/zio-http-example/src/main/scala/example/SSEServer.scala b/zio-http-example/src/main/scala/example/SSEServer.scala index 4b4dc86c54..1ada6129d8 100644 --- a/zio-http-example/src/main/scala/example/SSEServer.scala +++ b/zio-http-example/src/main/scala/example/SSEServer.scala @@ -14,11 +14,11 @@ object SSEServer extends ZIOAppDefault { val stream: ZStream[Any, Nothing, ServerSentEvent] = ZStream.repeatWithSchedule(ServerSentEvent(ISO_LOCAL_TIME.format(LocalDateTime.now)), Schedule.spaced(1.second)) - val app: HttpApp[Any, Response] = + val app: Routes[Any, Response] = Routes( Method.GET / "sse" -> handler(Response.fromServerSentEvents(stream)), - ).toHttpApp + ) val run: URIO[Any, ExitCode] = { Server.serve(app).provide(Server.default).exitCode diff --git a/zio-http-example/src/main/scala/example/ServeOnAnyOpenPort.scala b/zio-http-example/src/main/scala/example/ServeOnAnyOpenPort.scala index cfea8ad2f2..3a201f29b0 100644 --- a/zio-http-example/src/main/scala/example/ServeOnAnyOpenPort.scala +++ b/zio-http-example/src/main/scala/example/ServeOnAnyOpenPort.scala @@ -8,7 +8,7 @@ object ServeOnAnyOpenPort extends ZIOAppDefault { val httpApp = Routes( Method.GET / "hello" -> handler(Response.text("Hello, World!")), - ).toHttpApp + ) val app = for { port <- Server.install(httpApp) diff --git a/zio-http-example/src/main/scala/example/ServerConfigurationExample.scala b/zio-http-example/src/main/scala/example/ServerConfigurationExample.scala index ec48754278..10f8e70486 100644 --- a/zio-http-example/src/main/scala/example/ServerConfigurationExample.scala +++ b/zio-http-example/src/main/scala/example/ServerConfigurationExample.scala @@ -9,7 +9,7 @@ import zio.http._ object ServerConfigurationExample extends ZIOAppDefault { val httpApp = Routes( Method.GET / "hello" -> handler(Response.text("Hello, World!")), - ).sandbox.toHttpApp + ).sandbox override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] = Runtime.setConfigProvider(ConfigProvider.fromResourcePath()) diff --git a/zio-http-example/src/main/scala/example/ServerResponseCompression.scala b/zio-http-example/src/main/scala/example/ServerResponseCompression.scala index 668272e440..62f7baa3a4 100644 --- a/zio-http-example/src/main/scala/example/ServerResponseCompression.scala +++ b/zio-http-example/src/main/scala/example/ServerResponseCompression.scala @@ -7,7 +7,7 @@ import zio.http._ object ServerResponseCompression extends ZIOAppDefault { val httpApp = Routes( Method.GET / "hello" -> handler(Response.text("Hello, World!")), - ).sandbox.toHttpApp + ).sandbox val config = ZLayer.succeed( Server.Config.default.copy( diff --git a/zio-http-example/src/main/scala/example/ServerSentEventEndpoint.scala b/zio-http-example/src/main/scala/example/ServerSentEventEndpoint.scala index 742e40a76d..05eb0dc773 100644 --- a/zio-http-example/src/main/scala/example/ServerSentEventEndpoint.scala +++ b/zio-http-example/src/main/scala/example/ServerSentEventEndpoint.scala @@ -23,10 +23,10 @@ object ServerSentEventEndpoint extends ZIOAppDefault { val sseRoute = sseEndpoint.implement(Handler.succeed(stream)) - val app: HttpApp[Any, Response] = sseRoute.toHttpApp + val routes: Routes[Any, Response] = sseRoute.toRoutes override def run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = { - Server.serve(app).provide(Server.default).exitCode + Server.serve(routes).provide(Server.default).exitCode } } diff --git a/zio-http-example/src/main/scala/example/SignCookies.scala b/zio-http-example/src/main/scala/example/SignCookies.scala index 372d1c47a6..c5f9bb765c 100644 --- a/zio-http-example/src/main/scala/example/SignCookies.scala +++ b/zio-http-example/src/main/scala/example/SignCookies.scala @@ -15,7 +15,7 @@ object SignCookies extends ZIOAppDefault { private val app = Routes( Method.GET / "cookie" -> handler(Response.ok.addCookie(cookie.sign("secret"))), - ).toHttpApp + ) // Run it like any simple app val run = Server.serve(app).provide(Server.default) diff --git a/zio-http-example/src/main/scala/example/SimpleEffectBenchmarkServer.scala b/zio-http-example/src/main/scala/example/SimpleEffectBenchmarkServer.scala index 96d9a36d01..bd649069d0 100644 --- a/zio-http-example/src/main/scala/example/SimpleEffectBenchmarkServer.scala +++ b/zio-http-example/src/main/scala/example/SimpleEffectBenchmarkServer.scala @@ -16,7 +16,7 @@ object SimpleEffectBenchmarkServer extends ZIOAppDefault { private val STATIC_SERVER_NAME = "zio-http" - private val app: HttpApp[Any, Response] = Routes( + private val app: Routes[Any, Response] = Routes( Method.GET / "plaintext" -> handler( Response @@ -29,7 +29,7 @@ object SimpleEffectBenchmarkServer extends ZIOAppDefault { .json(jsonMessage) .addHeader(Header.Server(STATIC_SERVER_NAME)), ), - ).toHttpApp + ) private val config = Server.Config.default .port(8080) diff --git a/zio-http-example/src/main/scala/example/StaticFiles.scala b/zio-http-example/src/main/scala/example/StaticFiles.scala index f04f33c91f..5857c74296 100644 --- a/zio-http-example/src/main/scala/example/StaticFiles.scala +++ b/zio-http-example/src/main/scala/example/StaticFiles.scala @@ -11,7 +11,7 @@ object StaticFiles extends ZIOAppDefault { * "/static". For paths other than the resources directory, see * [[Middleware.serveDirectory]]. */ - val app = Routes.empty.toHttpApp @@ Middleware.serveResources(Path.empty / "static") + val app = HttpApp.empty @@ Middleware.serveResources(Path.empty / "static") override def run = Server.serve(app).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/StaticServer.scala b/zio-http-example/src/main/scala/example/StaticServer.scala index 1c54f9d7a3..a5e0c20fa6 100644 --- a/zio-http-example/src/main/scala/example/StaticServer.scala +++ b/zio-http-example/src/main/scala/example/StaticServer.scala @@ -49,7 +49,7 @@ object StaticServer extends ZIOAppDefault { else Handler.notFound) } yield http }, - ).sandbox.toHttpApp + ).sandbox val run = Server.serve(app).provide(Server.default) diff --git a/zio-http-example/src/main/scala/example/StreamingResponse.scala b/zio-http-example/src/main/scala/example/StreamingResponse.scala index efdb38c2eb..15b6066cb9 100644 --- a/zio-http-example/src/main/scala/example/StreamingResponse.scala +++ b/zio-http-example/src/main/scala/example/StreamingResponse.scala @@ -16,7 +16,7 @@ object StreamingResponse extends ZIOAppDefault { // Create a message as a Chunk[Byte] def message = Chunk.fromArray("Hello world !\r\n".getBytes(Charsets.Http)) - def app: HttpApp[Any, Response] = Routes( + def app: Routes[Any, Response] = Routes( // Simple (non-stream) based route Method.GET / "health" -> handler(Response.ok), @@ -28,5 +28,5 @@ object StreamingResponse extends ZIOAppDefault { body = Body.fromStream(ZStream.fromChunk(message), message.length.toLong), // Encoding content using a ZStream ), ), - ).toHttpApp + ) } diff --git a/zio-http-example/src/main/scala/example/WebSocketAdvanced.scala b/zio-http-example/src/main/scala/example/WebSocketAdvanced.scala index be1b918e4a..ee5e9e97e9 100644 --- a/zio-http-example/src/main/scala/example/WebSocketAdvanced.scala +++ b/zio-http-example/src/main/scala/example/WebSocketAdvanced.scala @@ -48,13 +48,13 @@ object WebSocketAdvanced extends ZIOAppDefault { } } - val app: HttpApp[Any, Response] = + val app: Routes[Any, Response] = Routes( Method.GET / "greet" / string("name") -> handler { (name: String, _: Request) => Response.text(s"Greetings ${name}!") }, Method.GET / "subscriptions" -> handler(socketApp.toResponse), - ).toHttpApp + ) override val run = Server.serve(app).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/WebSocketEcho.scala b/zio-http-example/src/main/scala/example/WebSocketEcho.scala index fa4217ab7c..d76d311435 100644 --- a/zio-http-example/src/main/scala/example/WebSocketEcho.scala +++ b/zio-http-example/src/main/scala/example/WebSocketEcho.scala @@ -21,13 +21,13 @@ object WebSocketEcho extends ZIOAppDefault { } } - private val app: HttpApp[Any, Response] = + private val app: Routes[Any, Response] = Routes( Method.GET / "greet" / string("name") -> handler { (name: String, _: Request) => Response.text(s"Greetings {$name}!") }, Method.GET / "subscriptions" -> handler(socketApp.toResponse), - ).toHttpApp + ) override val run = Server.serve(app).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/endpoint/BooksEndpointExample.scala b/zio-http-example/src/main/scala/example/endpoint/BooksEndpointExample.scala index 81159dee08..29ffab3f65 100644 --- a/zio-http-example/src/main/scala/example/endpoint/BooksEndpointExample.scala +++ b/zio-http-example/src/main/scala/example/endpoint/BooksEndpointExample.scala @@ -49,5 +49,5 @@ object BooksEndpointExample extends ZIOAppDefault { val swaggerRoutes = SwaggerUI.routes("docs" / "openapi", openAPI) val routes = Routes(booksRoute) ++ swaggerRoutes - def run = Server.serve(routes.toHttpApp).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/endpoint/CliExamples.scala b/zio-http-example/src/main/scala/example/endpoint/CliExamples.scala index a37a18613f..1029a15658 100644 --- a/zio-http-example/src/main/scala/example/endpoint/CliExamples.scala +++ b/zio-http-example/src/main/scala/example/endpoint/CliExamples.scala @@ -102,7 +102,7 @@ object TestCliServer extends zio.ZIOAppDefault with TestCliEndpoints { val routes = Routes(getUserRoute, getUserPostsRoute, createUserRoute) @@ Middleware.debug - val run = Server.serve(routes.toHttpApp).provide(Server.default) + val run = Server.serve(routes).provide(Server.default) } object TestCliClient extends zio.ZIOAppDefault with TestCliEndpoints { diff --git a/zio-http-example/src/main/scala/example/endpoint/EndpointWithError.scala b/zio-http-example/src/main/scala/example/endpoint/EndpointWithError.scala index b9d849f814..db4a1a050a 100644 --- a/zio-http-example/src/main/scala/example/endpoint/EndpointWithError.scala +++ b/zio-http-example/src/main/scala/example/endpoint/EndpointWithError.scala @@ -43,7 +43,7 @@ object EndpointWithError extends ZIOAppDefault { .mapError(err => NotFoundError(err, "The requested book was not found. Please try using a different ID.")) } - val app = endpoint.implement(getBookHandler).toHttpApp @@ Middleware.debug + val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug - def run = Server.serve(app).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleErrorsUsingEither.scala b/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleErrorsUsingEither.scala index dbc2dbc4bd..4fe6e24ba5 100644 --- a/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleErrorsUsingEither.scala +++ b/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleErrorsUsingEither.scala @@ -56,7 +56,7 @@ object EndpointWithMultipleErrorsUsingEither extends ZIOAppDefault { ZIO.fail(Left(AuthenticationError("User is not authenticated", 123))) } - val app = endpoint.implement(getBookHandler).toHttpApp @@ Middleware.debug + val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug - def run = Server.serve(app).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } diff --git a/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleUnifiedErrors.scala b/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleUnifiedErrors.scala index 2476662308..ff19d0543f 100644 --- a/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleUnifiedErrors.scala +++ b/zio-http-example/src/main/scala/example/endpoint/EndpointWithMultipleUnifiedErrors.scala @@ -59,7 +59,7 @@ object EndpointWithMultipleUnifiedErrors extends ZIOAppDefault { ZIO.fail(AuthenticationError("User is not authenticated", 123)) } - val app = endpoint.implement(getBookHandler).toHttpApp @@ Middleware.debug + val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug - def run = Server.serve(app).provide(Server.default) + def run = Server.serve(routes).provide(Server.default) } diff --git a/zio-http-testkit/src/main/scala/zio/http/TestClient.scala b/zio-http-testkit/src/main/scala/zio/http/TestClient.scala index 6205332459..b2a28c3d01 100644 --- a/zio-http-testkit/src/main/scala/zio/http/TestClient.scala +++ b/zio-http-testkit/src/main/scala/zio/http/TestClient.scala @@ -10,7 +10,7 @@ import zio._ * Server */ final case class TestClient( - behavior: Ref[HttpApp[Any, Response]], + behavior: Ref[Routes[Any, Response]], serverSocketBehavior: Ref[WebSocketApp[Any]], ) extends ZClient.Driver[Any, Throwable] { @@ -21,11 +21,11 @@ final case class TestClient( * * @example * {{{ - * TestClient.addHttpApp(HttpApp.empty) + * TestClient.addRoutes(HttpApp.empty) * }}} */ - def addHttpApp( - app: HttpApp[Any, Response], + def addRoutes( + app: Routes[Any, Response], ): ZIO[Any, Nothing, Unit] = behavior.update(_ ++ app) @@ -104,7 +104,7 @@ final case class TestClient( ): ZIO[R, Nothing, Unit] = for { r <- ZIO.environment[R] - provided = HttpApp.fromIterable(route +: routes).provideEnvironment(r) + provided = Routes.fromIterable(route +: routes).provideEnvironment(r) _ <- behavior.update(_ ++ provided) } yield () @@ -174,8 +174,8 @@ final case class TestClient( object TestClient { - def addApp(app: HttpApp[Any, Response]): ZIO[TestClient, Nothing, Unit] = - ZIO.serviceWithZIO[TestClient](_.addHttpApp(app)) + def addApp(app: Routes[Any, Response]): ZIO[TestClient, Nothing, Unit] = + ZIO.serviceWithZIO[TestClient](_.addRoutes(app)) /** * Adds an exact 1-1 behavior @@ -243,7 +243,7 @@ object TestClient { val layer: ZLayer[Any, Nothing, TestClient & Client] = ZLayer.scopedEnvironment { for { - behavior <- Ref.make[HttpApp[Any, Response]](HttpApp.empty) + behavior <- Ref.make[Routes[Any, Response]](Routes.empty) socketBehavior <- Ref.make[WebSocketApp[Any]](WebSocketApp.unit) driver = TestClient(behavior, socketBehavior) } yield ZEnvironment[TestClient, Client](driver, ZClient.fromDriver(driver)) diff --git a/zio-http-testkit/src/main/scala/zio/http/TestServer.scala b/zio-http-testkit/src/main/scala/zio/http/TestServer.scala index c991464bbe..e144a05447 100644 --- a/zio-http-testkit/src/main/scala/zio/http/TestServer.scala +++ b/zio-http-testkit/src/main/scala/zio/http/TestServer.scala @@ -68,8 +68,8 @@ final case class TestServer(driver: Driver, bindPort: Int) extends Server { ): ZIO[R, Nothing, Unit] = for { r <- ZIO.environment[R] - provided = route.provideEnvironment(r) - app: HttpApp[Any, Response] = provided.toHttpApp + provided = route.provideEnvironment(r) + app: Routes[Any, Response] = provided.toRoutes _ <- driver.addApp(app, r) } yield () @@ -91,12 +91,12 @@ final case class TestServer(driver: Driver, bindPort: Int) extends Server { ): ZIO[R, Nothing, Unit] = for { r <- ZIO.environment[R] - provided = routes.provideEnvironment(r) - app: HttpApp[Any, Response] = provided.toHttpApp + provided = routes.provideEnvironment(r) + app: Routes[Any, Response] = provided _ <- driver.addApp(app, r) } yield () - override def install[R](httpApp: HttpApp[R, Response])(implicit + override def install[R](httpApp: Routes[R, Response])(implicit trace: zio.Trace, ): URIO[R, Unit] = ZIO diff --git a/zio-http-testkit/src/test/scala/zio/http/SocketContractSpec.scala b/zio-http-testkit/src/test/scala/zio/http/SocketContractSpec.scala index 76ca2141bc..b5d026360d 100644 --- a/zio-http-testkit/src/test/scala/zio/http/SocketContractSpec.scala +++ b/zio-http-testkit/src/test/scala/zio/http/SocketContractSpec.scala @@ -130,7 +130,7 @@ object SocketContractSpec extends ZIOHttpSpec { ZIO.serviceWithZIO[Server](server => for { p <- Promise.make[Throwable, Unit] - _ <- server.install(serverApp(p).toHttpAppWS) + _ <- server.install(serverApp(p).toRoutes) } yield (server.port, p), ) diff --git a/zio-http-testkit/src/test/scala/zio/http/TestClientSpec.scala b/zio-http-testkit/src/test/scala/zio/http/TestClientSpec.scala index 1d817d1d96..350cd414c7 100644 --- a/zio-http-testkit/src/test/scala/zio/http/TestClientSpec.scala +++ b/zio-http-testkit/src/test/scala/zio/http/TestClientSpec.scala @@ -60,7 +60,7 @@ object TestClientSpec extends ZIOHttpSpec { for { client <- ZIO.service[Client] _ <- TestClient.addApp { - HttpApp( + Routes( Method.GET / trailing -> handler { Response.text("fallback") }, Method.GET / "hello" / "world" -> handler { Response.text("Hey there!") }, ) diff --git a/zio-http/jvm/src/main/scala/zio/http/netty/server/NettyDriver.scala b/zio-http/jvm/src/main/scala/zio/http/netty/server/NettyDriver.scala index 2e99fcd21e..3a7b0a185b 100644 --- a/zio-http/jvm/src/main/scala/zio/http/netty/server/NettyDriver.scala +++ b/zio-http/jvm/src/main/scala/zio/http/netty/server/NettyDriver.scala @@ -24,7 +24,7 @@ import zio._ import zio.http.Driver.StartResult import zio.http.netty._ import zio.http.netty.client.NettyClientDriver -import zio.http.{ClientDriver, Driver, HttpApp, Response, Server} +import zio.http.{ClientDriver, Driver, Routes, Response, Server} import io.netty.bootstrap.ServerBootstrap import io.netty.channel._ @@ -53,12 +53,12 @@ private[zio] final case class NettyDriver( ) } yield StartResult(port, serverInboundHandler.inFlightRequests) - def addApp[R](newApp: HttpApp[R, Response], env: ZEnvironment[R])(implicit trace: Trace): UIO[Unit] = ZIO.succeed { + def addApp[R](newApp: Routes[R, Response], env: ZEnvironment[R])(implicit trace: Trace): UIO[Unit] = ZIO.succeed { var loop = true while (loop) { val oldAppAndEnv = appRef.get() val (oldApp, oldEnv) = oldAppAndEnv - val updatedApp = (oldApp ++ newApp).asInstanceOf[HttpApp[Any, Response]] + val updatedApp = (oldApp ++ newApp).asInstanceOf[Routes[Any, Response]] val updatedEnv = oldEnv.unionAll(env) val updatedAppAndEnv = (updatedApp, updatedEnv) @@ -114,8 +114,8 @@ object NettyDriver { implicit val trace: Trace = Trace.empty ZLayer.makeSome[EventLoopGroup & ChannelFactory[ServerChannel] & Server.Config & NettyConfig, Driver]( ZLayer.succeed( - new AtomicReference[(HttpApp[Any, Response], ZEnvironment[Any])]((HttpApp.empty, ZEnvironment.empty)), - ), + new AtomicReference[(Routes[Any, Response], ZEnvironment[Any])]((Routes.empty, ZEnvironment.empty)), + ), NettyRuntime.live, ServerChannelInitializer.layer, ServerInboundHandler.live, diff --git a/zio-http/jvm/src/main/scala/zio/http/netty/server/ServerInboundHandler.scala b/zio-http/jvm/src/main/scala/zio/http/netty/server/ServerInboundHandler.scala index ea6f2ff4ca..3c64f42a7c 100644 --- a/zio-http/jvm/src/main/scala/zio/http/netty/server/ServerInboundHandler.scala +++ b/zio-http/jvm/src/main/scala/zio/http/netty/server/ServerInboundHandler.scala @@ -49,7 +49,7 @@ private[zio] final case class ServerInboundHandler( implicit private val unsafe: Unsafe = Unsafe.unsafe - private var app: HttpApp[Any, Response] = _ + private var app: Routes[Any, Response] = _ private var env: ZEnvironment[Any] = _ val inFlightRequests: LongAdder = new LongAdder() diff --git a/zio-http/jvm/src/main/scala/zio/http/netty/server/package.scala b/zio-http/jvm/src/main/scala/zio/http/netty/server/package.scala index 3e0fef2584..d62f15103e 100644 --- a/zio-http/jvm/src/main/scala/zio/http/netty/server/package.scala +++ b/zio-http/jvm/src/main/scala/zio/http/netty/server/package.scala @@ -23,7 +23,7 @@ import zio.http._ import java.util.concurrent.atomic.AtomicReference // scalafix:ok; import zio.stacktracer.TracingImplicits.disableAutoTrace package object server { - private[server] type AppRef = AtomicReference[(HttpApp[Any, Response], ZEnvironment[Any])] + private[server] type AppRef = AtomicReference[(Routes[Any, Response], ZEnvironment[Any])] private[server] type EnvRef = AtomicReference[ZEnvironment[Any]] val live: ZLayer[Server.Config, Throwable, Driver] = diff --git a/zio-http/jvm/src/test/scala/zio/http/ClientProxySpec.scala b/zio-http/jvm/src/test/scala/zio/http/ClientProxySpec.scala index 7a9e601650..0c710d6dcf 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ClientProxySpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ClientProxySpec.scala @@ -16,18 +16,16 @@ package zio.http -import java.net.ConnectException - import zio.Config.Secret -import zio.test.Assertion._ -import zio.test.TestAspect.{sequential, timeout, withLiveClock} -import zio.test._ -import zio.{Scope, Trace, ZIO, ZLayer, durationInt} - -import zio.http.ZClient.{Config, DriverLive} import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} import zio.http.netty.NettyConfig import zio.http.netty.client.NettyClientDriver +import zio.test.Assertion._ +import zio.test.TestAspect.{sequential, withLiveClock} +import zio.test._ +import zio.{Scope, ZIO, ZLayer} + +import java.net.ConnectException object ClientProxySpec extends HttpRunnableSpec { @@ -56,7 +54,7 @@ object ClientProxySpec extends HttpRunnableSpec { for { port <- ZIO.environmentWithZIO[DynamicServer](_.get.port) url <- ZIO.fromEither(URL.decode(s"http://localhost:$port")) - id <- DynamicServer.deploy(Handler.ok.toHttpApp) + id <- DynamicServer.deploy(Handler.ok.toRoutes) proxy = Proxy.empty.url(url).headers(Headers(DynamicServer.APP_ID, id)) zclient <- ZIO.serviceWith[Client](_.proxy(proxy)) out <- zclient @@ -76,7 +74,7 @@ object ClientProxySpec extends HttpRunnableSpec { for { port <- ZIO.environmentWithZIO[DynamicServer](_.get.port) url <- ZIO.fromEither(URL.decode(s"http://localhost:$port")) - id <- DynamicServer.deploy(Handler.ok.toHttpApp) + id <- DynamicServer.deploy(Handler.ok.toRoutes) proxy = Proxy.empty.url(url).headers(Headers(DynamicServer.APP_ID, id)) out <- Client .request( @@ -101,7 +99,7 @@ object ClientProxySpec extends HttpRunnableSpec { else Response.status(Status.Forbidden) } - .toHttpApp + .toRoutes val res = for { diff --git a/zio-http/jvm/src/test/scala/zio/http/ClientSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ClientSpec.scala index 230baf8c46..2b4426f8e8 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ClientSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ClientSpec.scala @@ -31,26 +31,26 @@ object ClientSpec extends HttpRunnableSpec { def clientSpec = suite("ClientSpec")( test("respond Ok") { - val app = Handler.ok.toHttpApp.deploy(Request()).map(_.status) + val app = Handler.ok.toRoutes.deploy(Request()).map(_.status) assertZIO(app)(equalTo(Status.Ok)) }, test("non empty content") { - val app = Handler.text("abc").toHttpApp + val app = Handler.text("abc").toRoutes val responseContent = app.deploy(Request()).flatMap(_.body.asChunk) assertZIO(responseContent)(isNonEmpty) }, test("echo POST request content") { - val app = Handler.fromFunctionZIO[Request] { req => req.body.asString.map(Response.text(_)) }.sandbox.toHttpApp + val app = Handler.fromFunctionZIO[Request] { req => req.body.asString.map(Response.text(_)) }.sandbox.toRoutes val res = app.deploy(Request(method = Method.POST, body = Body.fromString("ZIO user"))).flatMap(_.body.asString) assertZIO(res)(equalTo("ZIO user")) }, test("empty content") { - val app = HttpApp.empty + val app = Routes.empty val responseContent = app.deploy(Request()).flatMap(_.body.asString.map(_.length)) assertZIO(responseContent)(equalTo(0)) }, test("text content") { - val app = Handler.text("zio user does not exist").toHttpApp + val app = Handler.text("zio user does not exist").toRoutes val responseContent = app.deploy(Request()).flatMap(_.body.asString) assertZIO(responseContent)(containsString("user")) }, @@ -61,7 +61,7 @@ object ClientSpec extends HttpRunnableSpec { assertZIO(res)(isLeft(isSubtype[ConnectException](anything))) }, test("streaming content to server") { - val app = Handler.fromFunctionZIO[Request] { req => req.body.asString.map(Response.text(_)) }.sandbox.toHttpApp + val app = Handler.fromFunctionZIO[Request] { req => req.body.asString.map(Response.text(_)) }.sandbox.toRoutes val stream = ZStream.fromIterable(List("a", "b", "c"), chunkSize = 1) val res = app .deploy(Request(method = Method.POST, body = Body.fromCharSequenceStreamChunked(stream))) @@ -71,7 +71,7 @@ object ClientSpec extends HttpRunnableSpec { test("no trailing slash for empty path") { for { baseURL <- DynamicServer.httpURL - _ <- Handler.ok.toHttpApp + _ <- Handler.ok.toRoutes .deployAndRequest(c => (c @@ ZClientAspect.requestLogging()).get("")) .runZIO(()) loggedUrl <- ZTestLogger.logOutput.map(_.collectFirst { case m => m.annotations("url") }.mkString) @@ -80,14 +80,14 @@ object ClientSpec extends HttpRunnableSpec { test("trailing slash for explicit slash") { for { baseURL <- DynamicServer.httpURL - _ <- Handler.ok.toHttpApp + _ <- Handler.ok.toRoutes .deployAndRequest(c => (c @@ ZClientAspect.requestLogging()).get("/")) .runZIO(()) loggedUrl <- ZTestLogger.logOutput.map(_.collectFirst { case m => m.annotations("url") }.mkString) } yield assertTrue(loggedUrl == s"$baseURL/") }, test("reading of unfinished body must fail") { - val app = Handler.fromStreamChunked(ZStream.never).sandbox.toHttpApp + val app = Handler.fromStreamChunked(ZStream.never).sandbox.toRoutes val requestCode = (client: Client) => (for { response <- ZIO.scoped(client(Request())) diff --git a/zio-http/jvm/src/test/scala/zio/http/ClientStreamingSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ClientStreamingSpec.scala index 6d57883092..f18338092d 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ClientStreamingSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ClientStreamingSpec.scala @@ -32,7 +32,7 @@ import zio.http.netty.NettyConfig.LeakDetectionLevel object ClientStreamingSpec extends HttpRunnableSpec { def extractStatus(response: Response): Status = response.status - val app = HttpApp( + val app = Routes( Method.GET / "simple-get" -> handler(Response.text("simple response")), Method.GET / "streaming-get" -> diff --git a/zio-http/jvm/src/test/scala/zio/http/ContentTypeSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ContentTypeSpec.scala index ead7cfbefc..2d45fdec17 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ContentTypeSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ContentTypeSpec.scala @@ -17,42 +17,41 @@ package zio.http import zio._ +import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} import zio.test.Assertion.{equalTo, isNone, isSome} -import zio.test.TestAspect.{timeout, withLiveClock} +import zio.test.TestAspect.withLiveClock import zio.test._ -import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} - object ContentTypeSpec extends HttpRunnableSpec { val contentSpec = suite("Content type header on file response")( test("mp4") { val res = - Handler.fromResource("TestFile2.mp4").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + Handler.fromResource("TestFile2.mp4").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isSome(equalTo(Header.ContentType(MediaType.video.`mp4`)))) }, test("js") { val res = - Handler.fromResource("TestFile3.js").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + Handler.fromResource("TestFile3.js").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isSome(equalTo(Header.ContentType(MediaType.application.`javascript`)))) }, test("no extension") { - val res = Handler.fromResource("TestFile4").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + val res = Handler.fromResource("TestFile4").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isNone) }, test("css") { val res = - Handler.fromResource("TestFile5.css").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + Handler.fromResource("TestFile5.css").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isSome(equalTo(Header.ContentType(MediaType.text.`css`)))) }, test("mp3") { val res = - Handler.fromResource("TestFile6.mp3").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + Handler.fromResource("TestFile6.mp3").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isSome(equalTo(Header.ContentType(MediaType.audio.`mpeg`)))) }, test("unidentified extension") { val res = - Handler.fromResource("truststore.jks").sandbox.toHttpApp.deploy(Request()).map(_.header(Header.ContentType)) + Handler.fromResource("truststore.jks").sandbox.toRoutes.deploy(Request()).map(_.header(Header.ContentType)) assertZIO(res)(isNone) }, test("already set content-type") { @@ -62,7 +61,7 @@ object ContentTypeSpec extends HttpRunnableSpec { .fromResource("TestFile6.mp3") .map(_.addHeader(Header.ContentType(expected))) .sandbox - .toHttpApp + .toRoutes .deploy(Request()) .map( _.header(Header.ContentType), diff --git a/zio-http/jvm/src/test/scala/zio/http/DynamicAppTest.scala b/zio-http/jvm/src/test/scala/zio/http/DynamicAppTest.scala index 1b5f28e658..293820ca3f 100644 --- a/zio-http/jvm/src/test/scala/zio/http/DynamicAppTest.scala +++ b/zio-http/jvm/src/test/scala/zio/http/DynamicAppTest.scala @@ -26,13 +26,13 @@ import zio.http.netty.client.NettyClientDriver object DynamicAppTest extends ZIOHttpSpec { def extractStatus(response: Response): Status = response.status - val httpApp1: HttpApp[Any, Response] = - HttpApp( + val httpApp1: Routes[Any, Response] = + Routes( Method.GET / "good" -> Handler.ok, ).sandbox - val httpApp2: HttpApp[Any, Response] = - HttpApp( + val httpApp2: Routes[Any, Response] = + Routes( Method.GET / "better" -> handler(Response.status(Status.Created)), ).sandbox diff --git a/zio-http/jvm/src/test/scala/zio/http/FlashSpec.scala b/zio-http/jvm/src/test/scala/zio/http/FlashSpec.scala index f20f709ba2..6ece32043b 100644 --- a/zio-http/jvm/src/test/scala/zio/http/FlashSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/FlashSpec.scala @@ -118,7 +118,7 @@ object FlashSpec extends ZIOHttpSpec { } yield Response.html(html) } - val app = HttpApp(routeUserSave, routeConfirm) + val app = Routes(routeUserSave, routeConfirm) for { response1 <- app.runZIO(Request.post(URL(routeUserSavePath.format(()).toOption.get), Body.empty)) diff --git a/zio-http/jvm/src/test/scala/zio/http/KeepAliveSpec.scala b/zio-http/jvm/src/test/scala/zio/http/KeepAliveSpec.scala index 0147b4e27f..0720b67222 100644 --- a/zio-http/jvm/src/test/scala/zio/http/KeepAliveSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/KeepAliveSpec.scala @@ -16,16 +16,15 @@ package zio.http +import zio.Scope +import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} import zio.test.Assertion.{equalTo, isNone, isSome} -import zio.test.TestAspect.{sequential, timeout, withLiveClock} +import zio.test.TestAspect.{sequential, withLiveClock} import zio.test.{Spec, assert} -import zio.{Scope, ZIO, durationInt} - -import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} object KeepAliveSpec extends HttpRunnableSpec { - private val app = Handler.ok.toHttpApp + private val routes = Handler.ok.toRoutes private val connectionCloseHeader = Headers(Header.Connection.Close) private val keepAliveHeader = Headers(Header.Connection.KeepAlive) private val appKeepAliveEnabled = serve @@ -35,13 +34,13 @@ object KeepAliveSpec extends HttpRunnableSpec { test("without connection close") { for { _ <- appKeepAliveEnabled - res <- app.deploy(Request()).map(_.header(Header.Connection)) + res <- routes.deploy(Request()).map(_.header(Header.Connection)) } yield assert(res)(isNone) }, test("with connection close") { for { _ <- appKeepAliveEnabled - res <- app.deploy(Request(headers = connectionCloseHeader)).map(_.header(Header.Connection)) + res <- routes.deploy(Request(headers = connectionCloseHeader)).map(_.header(Header.Connection)) } yield assert(res)(isSome(equalTo(Header.Connection.Close))) }, ), @@ -49,13 +48,13 @@ object KeepAliveSpec extends HttpRunnableSpec { test("without keep-alive") { for { _ <- appKeepAliveEnabled - res <- app.deploy(Request(version = Version.`HTTP/1.0`)).map(_.header(Header.Connection)) + res <- routes.deploy(Request(version = Version.`HTTP/1.0`)).map(_.header(Header.Connection)) } yield assert(res)(isSome(equalTo(Header.Connection.Close))) }, test("with keep-alive") { for { _ <- appKeepAliveEnabled - res <- app + res <- routes .deploy(Request(version = Version.Http_1_0, headers = keepAliveHeader)) .map(_.header(Header.Connection)) } yield assert(res)(isNone) diff --git a/zio-http/jvm/src/test/scala/zio/http/LogAnnotationMiddlewareSpec.scala b/zio-http/jvm/src/test/scala/zio/http/LogAnnotationMiddlewareSpec.scala index f9f58b5a1f..d9d851672a 100644 --- a/zio-http/jvm/src/test/scala/zio/http/LogAnnotationMiddlewareSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/LogAnnotationMiddlewareSpec.scala @@ -12,7 +12,7 @@ object LogAnnotationMiddlewareSpec extends ZIOSpecDefault { handler(ZIO.logWarning("Oh!") *> ZIO.succeed(Response.text("Hey logging!"))), ) .@@(Middleware.logAnnotate("label", "value")) - .toHttpApp + .runZIO(Request.get("/")) for { @@ -32,7 +32,7 @@ object LogAnnotationMiddlewareSpec extends ZIOSpecDefault { Set(LogAnnotation("method", req.method.name), LogAnnotation("path", req.path.encode)), ), ) - .toHttpApp + .runZIO(Request.get("/")) for { @@ -51,7 +51,7 @@ object LogAnnotationMiddlewareSpec extends ZIOSpecDefault { ) .@@(Middleware.logAnnotateHeaders("header")) .@@(Middleware.logAnnotateHeaders(Header.UserAgent.name)) - .toHttpApp + .runZIO { Request .get("/") diff --git a/zio-http/jvm/src/test/scala/zio/http/MultipartMixedSpec.scala b/zio-http/jvm/src/test/scala/zio/http/MultipartMixedSpec.scala index dc2e2c4a56..6192a7c028 100644 --- a/zio-http/jvm/src/test/scala/zio/http/MultipartMixedSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/MultipartMixedSpec.scala @@ -401,7 +401,7 @@ object MultipartMixedSpec extends ZIOHttpSpec { case (None, None) => res0 case (Some(mt), None) => res0.contentType(mt) case (Some(mt), Some(b)) => res0.contentType(mt, b) - case (None, Some(b)) => + case (None, Some(_)) => sys.error("r u joking me?!?!") } diff --git a/zio-http/jvm/src/test/scala/zio/http/NettyMaxHeaderLengthSpec.scala b/zio-http/jvm/src/test/scala/zio/http/NettyMaxHeaderLengthSpec.scala index 1d636ea173..86ea9d4a92 100644 --- a/zio-http/jvm/src/test/scala/zio/http/NettyMaxHeaderLengthSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/NettyMaxHeaderLengthSpec.scala @@ -29,7 +29,7 @@ object NettyMaxHeaderLengthSpec extends ZIOHttpSpec { override def spec: Spec[TestEnvironment with Scope, Any] = test("should get a failure instead of an empty body") { - val app = Handler + val routes = Handler .fromFunctionZIO[Request] { request => request.body.asString.map { body => val responseBody = if (body.isEmpty) "" else body @@ -37,9 +37,10 @@ object NettyMaxHeaderLengthSpec extends ZIOHttpSpec { } // this should not be run, as the request is invalid } .sandbox - .toHttpApp + .toRoutes + for { - port <- Server.install(app) + port <- Server.install(routes) url = URL.decode(s"http://localhost:$port").toOption.get headers = Headers( Header.UserAgent.Product("a looooooooooooooooooooooooooooong header", None), diff --git a/zio-http/jvm/src/test/scala/zio/http/NettyMaxInitialLineLengthSpec.scala b/zio-http/jvm/src/test/scala/zio/http/NettyMaxInitialLineLengthSpec.scala index 513d13d85e..441c6b962a 100644 --- a/zio-http/jvm/src/test/scala/zio/http/NettyMaxInitialLineLengthSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/NettyMaxInitialLineLengthSpec.scala @@ -32,7 +32,7 @@ object NettyMaxInitialLineLength extends ZIOHttpSpec { override def spec: Spec[TestEnvironment with Scope, Any] = test("should get a failure instead of an empty body") { - val app = Handler + val routes = Handler .fromFunctionZIO[Request] { request => request.body.asString.map { body => val responseBody = if (body.isEmpty) "" else body @@ -40,9 +40,10 @@ object NettyMaxInitialLineLength extends ZIOHttpSpec { } // this should not be run, as the request is invalid } .sandbox - .toHttpApp + .toRoutes + for { - port <- Server.install(app) + port <- Server.install(routes) url = URL .decode(s"http://localhost:$port/a%20looooooooooooooooooooooooooooong%20query%20parameter") .toOption diff --git a/zio-http/jvm/src/test/scala/zio/http/RequestStreamingServerSpec.scala b/zio-http/jvm/src/test/scala/zio/http/RequestStreamingServerSpec.scala index 2c23fd0262..71d03f2423 100644 --- a/zio-http/jvm/src/test/scala/zio/http/RequestStreamingServerSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/RequestStreamingServerSpec.scala @@ -49,14 +49,15 @@ object RequestStreamingServerSpec extends HttpRunnableSpec { test("test unsafe large content") { val size = 1024 * 1024 val content = genString(size, '?') - val app = Handler + val routes = Handler .fromFunctionZIO[Request] { _.body.asStream.runCount .map(bytesCount => Response.text(bytesCount.toString)) } .sandbox - .toHttpApp - val res = app.deploy(Request(body = Body.fromString(content))).flatMap(_.body.asString) + .toRoutes + + val res = routes.deploy(Request(body = Body.fromString(content))).flatMap(_.body.asString) assertZIO(res)(equalTo(size.toString)) }, test("multiple body read") { @@ -67,12 +68,12 @@ object RequestStreamingServerSpec extends HttpRunnableSpec { _ <- req.body.asChunk } yield Response.ok } - }.sandbox.toHttpApp + }.sandbox val res = app.deploy(Request()).map(_.status) assertZIO(res)(equalTo(Status.InternalServerError)) }, suite("streaming request passed to client")({ - val app = HttpApp( + val app = Routes( Method.POST / "1" -> handler { (req: Request) => val host = req.headers.get(Header.Host).get val newRequest = diff --git a/zio-http/jvm/src/test/scala/zio/http/ResponseCompressionSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ResponseCompressionSpec.scala index 2c65b6e4f8..9f5a21a2ec 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ResponseCompressionSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ResponseCompressionSpec.scala @@ -29,13 +29,13 @@ import zio.http.netty.NettyConfig object ResponseCompressionSpec extends ZIOHttpSpec { - private val text: HttpApp[Any, Response] = - HttpApp( + private val text: Routes[Any, Response] = + Routes( Method.GET / "text" -> handler(Response.text("Hello World!\n")), ) private val stream = - HttpApp( + Routes( Method.GET / "stream" -> handler( Response( diff --git a/zio-http/jvm/src/test/scala/zio/http/RouteSpec.scala b/zio-http/jvm/src/test/scala/zio/http/RouteSpec.scala index d1d4c02ea5..11e5be89d3 100644 --- a/zio-http/jvm/src/test/scala/zio/http/RouteSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/RouteSpec.scala @@ -82,7 +82,7 @@ object RouteSpec extends ZIOHttpSpec { .handleErrorCauseZIO(c => p.failCause(c).as(Response.internalServerError)) request = Request.get(URL.decode("/endpoint").toOption.get) - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) result <- p.await.catchAllCause(c => ZIO.succeed(c.prettyPrint)) } yield assertTrue(extractStatus(response) == Status.InternalServerError, result.contains("hmm...")) @@ -98,7 +98,7 @@ object RouteSpec extends ZIOHttpSpec { ) request = Request.get(URL.decode("/endpoint").toOption.get) - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) result <- p.await.catchAllCause(c => ZIO.succeed(c.prettyPrint)) resultWarning <- ZIO.fromOption(response.headers.get(Header.Warning).map(_.text)) @@ -116,7 +116,7 @@ object RouteSpec extends ZIOHttpSpec { ) val request = Request.get(URL.decode("/endpoint").toOption.get) for { - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) resultWarning <- ZIO.fromOption(response.headers.get(Header.Warning).map(_.text)) } yield assertTrue( @@ -129,7 +129,7 @@ object RouteSpec extends ZIOHttpSpec { val errorHandled = route.handleErrorCause(_ => Response.text("error").status(Status.InternalServerError)) val request = Request.get(URL.decode("/endpoint").toOption.get) for { - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) bodyString <- response.body.asString } yield assertTrue(extractStatus(response) == Status.InternalServerError, bodyString == "error") }, @@ -139,7 +139,7 @@ object RouteSpec extends ZIOHttpSpec { route.handleErrorCauseZIO(_ => ZIO.succeed(Response.text("error").status(Status.InternalServerError))) val request = Request.get(URL.decode("/endpoint").toOption.get) for { - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) bodyString <- response.body.asString } yield assertTrue(extractStatus(response) == Status.InternalServerError, bodyString == "error") }, @@ -149,7 +149,7 @@ object RouteSpec extends ZIOHttpSpec { route.handleErrorRequestCause((_, _) => Response.text("error").status(Status.InternalServerError)) val request = Request.get(URL.decode("/endpoint").toOption.get) for { - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) bodyString <- response.body.asString } yield assertTrue(extractStatus(response) == Status.InternalServerError, bodyString == "error") }, @@ -160,7 +160,7 @@ object RouteSpec extends ZIOHttpSpec { ) val request = Request.get(URL.decode("/endpoint").toOption.get) for { - response <- errorHandled.toHttpApp.runZIO(request) + response <- errorHandled.toRoutes.runZIO(request) bodyString <- response.body.asString } yield assertTrue(extractStatus(response) == Status.InternalServerError, bodyString == "error") }, diff --git a/zio-http/jvm/src/test/scala/zio/http/HttpAppMiddlewareSpec.scala b/zio-http/jvm/src/test/scala/zio/http/RoutesMiddlewareSpec.scala similarity index 97% rename from zio-http/jvm/src/test/scala/zio/http/HttpAppMiddlewareSpec.scala rename to zio-http/jvm/src/test/scala/zio/http/RoutesMiddlewareSpec.scala index 32a3903cfc..04aaac657b 100644 --- a/zio-http/jvm/src/test/scala/zio/http/HttpAppMiddlewareSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/RoutesMiddlewareSpec.scala @@ -22,7 +22,7 @@ import zio.test._ import zio.http.Method -object HttpAppMiddlewareSpec extends ZIOHttpSpec with ExitAssertion { +object RoutesMiddlewareSpec extends ZIOHttpSpec with ExitAssertion { def spec: Spec[Any, Any] = suite("HttpAppMiddleware")( diff --git a/zio-http/jvm/src/test/scala/zio/http/HttpAppSpec.scala b/zio-http/jvm/src/test/scala/zio/http/RoutesSpec.scala similarity index 88% rename from zio-http/jvm/src/test/scala/zio/http/HttpAppSpec.scala rename to zio-http/jvm/src/test/scala/zio/http/RoutesSpec.scala index 0079e900bf..c6ca58d121 100644 --- a/zio-http/jvm/src/test/scala/zio/http/HttpAppSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/RoutesSpec.scala @@ -16,23 +16,21 @@ package zio.http -import zio._ -import zio.test.Assertion._ import zio.test._ -object HttpAppSpec extends ZIOHttpSpec { +object RoutesSpec extends ZIOHttpSpec { def extractStatus(response: Response): Status = response.status def spec = suite("HttpAppSpec")( test("empty not found") { - val app = HttpApp.empty + val app = Routes.empty for { result <- app.run() } yield assertTrue(extractStatus(result) == Status.NotFound) }, test("compose empty not found") { - val app = HttpApp.empty ++ HttpApp.empty + val app = Routes.empty ++ Routes.empty for { result <- app.run() @@ -43,7 +41,7 @@ object HttpAppSpec extends ZIOHttpSpec { val app = handler { (req: Request) => Response(body = req.body) - }.toHttpApp + } for { result <- app.runZIO(Request(body = body)) diff --git a/zio-http/jvm/src/test/scala/zio/http/SSLSpec.scala b/zio-http/jvm/src/test/scala/zio/http/SSLSpec.scala index cb19d3e5c6..a75c0234f7 100644 --- a/zio-http/jvm/src/test/scala/zio/http/SSLSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/SSLSpec.scala @@ -33,7 +33,7 @@ object SSLSpec extends ZIOHttpSpec { val payload = Gen.alphaNumericStringBounded(10000, 20000) - val app: HttpApp[Any, Response] = HttpApp( + val app: Routes[Any, Response] = Routes( Method.GET / "success" -> handler(Response.ok), ).sandbox diff --git a/zio-http/jvm/src/test/scala/zio/http/ServerSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ServerSpec.scala index d71d029d40..66fecc77f5 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ServerSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ServerSpec.scala @@ -50,20 +50,20 @@ object ServerSpec extends HttpRunnableSpec { def dynamicAppSpec = suite("DynamicAppSpec")( suite("success")( test("status is 200") { - val status = Handler.ok.toHttpApp.deploy.status.run() + val status = Handler.ok.toRoutes.deploy.status.run() assertZIO(status)(equalTo(Status.Ok)) }, test("status is 200") { - val res = Handler.text("ABC").toHttpApp.deploy.status.run() + val res = Handler.text("ABC").toRoutes.deploy.status.run() assertZIO(res)(equalTo(Status.Ok)) }, test("content is set") { - val res = Handler.text("ABC").toHttpApp.deploy.body.mapZIO(_.asString).run() + val res = Handler.text("ABC").toRoutes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(containsString("ABC")) }, ), suite("not found") { - val app = HttpApp.empty + val app = Routes.empty test("status is 404") { val res = app.deploy.status.run() assertZIO(res)(equalTo(Status.NotFound)) @@ -74,76 +74,76 @@ object ServerSpec extends HttpRunnableSpec { } } + suite("error") { - val app = Handler.fail(new Error("SERVER_ERROR")).sandbox.toHttpApp + val routes = Handler.fail(new Error("SERVER_ERROR")).sandbox.toRoutes test("status is 500") { - val res = app.deploy.status.run() + val res = routes.deploy.status.run() assertZIO(res)(equalTo(Status.InternalServerError)) } + test("content is empty") { - val res = app.deploy.body.mapZIO(_.asString).run() + val res = routes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(isEmptyString) } + test("header is set") { - val res = app.deploy.header(Header.ContentLength).run() + val res = routes.deploy.header(Header.ContentLength).run() assertZIO(res)(isSome(anything)) } } + suite("die") { - val app = Handler.die(new Error("SERVER_ERROR")).toHttpApp + val routes = Handler.die(new Error("SERVER_ERROR")).toRoutes test("status is 500") { - val res = app.deploy.status.run() + val res = routes.deploy.status.run() assertZIO(res)(equalTo(Status.InternalServerError)) } + test("content is empty") { - val res = app.deploy.body.mapZIO(_.asString).run() + val res = routes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(isEmptyString) } + test("header is set") { - val res = app.deploy.header(Header.ContentLength).run() + val res = routes.deploy.header(Header.ContentLength).run() assertZIO(res)(isSome(anything)) } } + suite("echo content") { - val app = (RoutePattern.any -> + val routes = (RoutePattern.any -> handler { (_: Path, req: Request) => req.body.asString.map(text => Response.text(text)) - }).sandbox.toHttpApp + }).sandbox.toRoutes test("status is 200") { - val res = app.deploy.status.run() + val res = routes.deploy.status.run() assertZIO(res)(equalTo(Status.Ok)) } + test("body is ok") { - val res = app.deploy.body.mapZIO(_.asString).run(body = Body.fromString("ABC")) + val res = routes.deploy.body.mapZIO(_.asString).run(body = Body.fromString("ABC")) assertZIO(res)(equalTo("ABC")) } + test("empty string") { - val res = app.deploy.body.mapZIO(_.asString).run(body = Body.fromString("")) + val res = routes.deploy.body.mapZIO(_.asString).run(body = Body.fromString("")) assertZIO(res)(equalTo("")) } + test("one char") { - val res = app.deploy.body.mapZIO(_.asString).run(body = Body.fromString("1")) + val res = routes.deploy.body.mapZIO(_.asString).run(body = Body.fromString("1")) assertZIO(res)(equalTo("1")) } + test("data") { val dataStream = ZStream.repeat("A").take(MaxSize.toLong) val app = - HttpApp(RoutePattern.any -> handler((_: Path, req: Request) => Response(body = req.body))) + Routes(RoutePattern.any -> handler((_: Path, req: Request) => Response(body = req.body))) val res = app.deploy.body.mapZIO(_.asChunk.map(_.length)).run(body = Body.fromCharSequenceStreamChunked(dataStream)) assertZIO(res)(equalTo(MaxSize)) } } + suite("headers") { - val app = Handler.ok.addHeader("Foo", "Bar").toHttpApp + val routes = Handler.ok.addHeader("Foo", "Bar").toRoutes test("headers are set") { - val res = app.deploy.rawHeader("Foo").run() + val res = routes.deploy.rawHeader("Foo").run() assertZIO(res)(isSome(equalTo("Bar"))) } } + suite("response") { - val app = Handler.fromResponse(Response(status = Status.Ok, body = Body.fromString("abc"))).toHttpApp + val routes = Handler.fromResponse(Response(status = Status.Ok, body = Body.fromString("abc"))).toRoutes test("body is set") { - val res = app.deploy.body.mapZIO(_.asString).run() + val res = routes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(equalTo("abc")) } } + @@ -151,22 +151,22 @@ object ServerSpec extends HttpRunnableSpec { val body = "some-text" val bodyAsStream = ZStream.fromChunk(Chunk.fromArray(body.getBytes)) - val app = HttpApp( + val routes = Routes( RoutePattern.any -> handler { (_: Path, req: Request) => req.body.asString.map(body => Response.text(body)) }, - ).sandbox.deploy + ).sandbox.deploy.toRoutes.sandbox def roundTrip[R, E <: Throwable]( - app: HttpApp[R, Response], - headers: Headers, + routes : Routes[R, Response], + headers : Headers, contentStream: ZStream[R, E, Byte], - compressor: ZPipeline[R, E, Byte, Byte], - decompressor: ZPipeline[R, E, Byte, Byte], + compressor : ZPipeline[R, E, Byte, Byte], + decompressor : ZPipeline[R, E, Byte, Byte], ) = for { compressed <- contentStream.via(compressor).runCollect - response <- app.run(body = Body.fromChunk(compressed), headers = headers) + response <- routes.run(body = Body.fromChunk(compressed), headers = headers) body <- response.body.asChunk.flatMap(ch => ZStream.fromChunk(ch).via(decompressor).runCollect) } yield new String(body.toArray, StandardCharsets.UTF_8) @@ -188,7 +188,7 @@ object ServerSpec extends HttpRunnableSpec { ), ) { case (contentEncoding, compressor, acceptEncoding, decompressor) => val result = roundTrip( - app.sandbox.toHttpApp, + routes.sandbox, Headers(acceptEncoding, contentEncoding), bodyAsStream, compressor, @@ -198,7 +198,7 @@ object ServerSpec extends HttpRunnableSpec { } } + test("pass through for unsupported accept encoding request") { - val result = app.run( + val result = routes.run( body = Body.fromString(body), headers = Headers(Header.AcceptEncoding.Br()), ) @@ -214,7 +214,7 @@ object ServerSpec extends HttpRunnableSpec { ), ), ) { ae => - val result = app.run( + val result = routes.run( body = Body.fromString(body), headers = Headers(ae), ) @@ -224,16 +224,16 @@ object ServerSpec extends HttpRunnableSpec { } + suite("interruption")( test("interrupt closes the channel without response") { - val app = Handler.fromZIO { + val routes = Handler.fromZIO { ZIO.interrupt.as(Response.text("not interrupted")) - }.toHttpApp - assertZIO(app.deploy.run().exit)( + }.toRoutes + assertZIO(routes.deploy.run().exit)( fails(hasField("class.simpleName", _.getClass.getSimpleName, equalTo("PrematureChannelClosureException"))), ) }, ) + suite("proxy") { - val server = HttpApp( + val server = Routes( Method.ANY / "proxy" / trailing -> handler { (path: Path, req: Request) => val url = URL.decode(s"http://localhost:$port/$path").toOption.get @@ -267,13 +267,13 @@ object ServerSpec extends HttpRunnableSpec { ) def requestSpec = suite("RequestSpec") { - val app: HttpApp[Any, Response] = - Routes + val app: Routes[Any, Response] = + Routes .singleton(handler { (_: Path, req: Request) => Response.text(req.header(Header.ContentLength).map(_.length).getOrElse(-1).toString) }) .sandbox - .toHttpApp + test("has content-length") { check(Gen.alphaNumericString) { string => @@ -282,20 +282,20 @@ object ServerSpec extends HttpRunnableSpec { } } + test("POST Request.getBody") { - val app = Routes + val app =Routes .singleton(handler { (_: Path, req: Request) => req.body.asChunk.as(Response.ok) }) .sandbox - .toHttpApp + val res = app.deploy.status.run(path = Root, method = Method.POST, body = Body.fromString("some text")) assertZIO(res)(equalTo(Status.Ok)) } + test("body can be read multiple times") { - val app = Routes + val app =Routes .singleton(handler { (_: Path, req: Request) => (req.body.asChunk *> req.body.asChunk).as(Response.ok) }) .sandbox - .toHttpApp + val res = app.deploy.status.run(method = Method.POST, body = Body.fromString("some text")) assertZIO(res)(equalTo(Status.Ok)) } @@ -304,12 +304,12 @@ object ServerSpec extends HttpRunnableSpec { def responseSpec = suite("ResponseSpec")( test("data") { check(nonEmptyContent) { case (string, data) => - val res = Handler.fromBody(data).toHttpApp.deploy.body.mapZIO(_.asString).run() + val res = Handler.fromBody(data).toRoutes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(equalTo(string)) } }, test("data from file") { - val res = Handler.fromResource("TestFile.txt").sandbox.toHttpApp.deploy.body.mapZIO(_.asString).run() + val res = Handler.fromResource("TestFile.txt").sandbox.toRoutes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(equalTo("foo\nbar")) }, test("content-type header on file response") { @@ -317,7 +317,7 @@ object ServerSpec extends HttpRunnableSpec { Handler .fromResource("TestFile2.mp4") .sandbox - .toHttpApp + .toRoutes .deploy .header(Header.ContentType) .run() @@ -326,23 +326,23 @@ object ServerSpec extends HttpRunnableSpec { }, test("status") { checkAll(HttpGen.status) { case status => - val res = Handler.status(status).toHttpApp.deploy.status.run() + val res = Handler.status(status).toRoutes.deploy.status.run() assertZIO(res)(equalTo(status)) } }, test("header") { check(HttpGen.header) { header => - val res = Handler.ok.addHeader(header).toHttpApp.deploy.rawHeader(header.headerName).run() + val res = Handler.ok.addHeader(header).toRoutes.deploy.rawHeader(header.headerName).run() assertZIO(res)(isSome(equalTo(header.renderedValue))) } }, test("text streaming") { - val res = Handler.fromStreamChunked(ZStream("a", "b", "c")).sandbox.toHttpApp.deploy.body.mapZIO(_.asString).run() + val res = Handler.fromStreamChunked(ZStream("a", "b", "c")).sandbox.toRoutes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(equalTo("abc")) }, test("echo streaming") { - val res = Routes + val res =Routes .singleton(handler { (_: Path, req: Request) => Handler.fromStreamChunked(ZStream.fromZIO(req.body.asChunk).flattenChunks): Handler[ Any, @@ -352,7 +352,7 @@ object ServerSpec extends HttpRunnableSpec { ] }) .sandbox - .toHttpApp + .deploy .body .mapZIO(_.asString) @@ -365,7 +365,7 @@ object ServerSpec extends HttpRunnableSpec { Handler .fromStreamChunked(ZStream.fromPath(Paths.get(path))) .sandbox - .toHttpApp + .toRoutes .deploy .body .mapZIO(_.asString) @@ -377,7 +377,7 @@ object ServerSpec extends HttpRunnableSpec { Handler .fromStream(ZStream.fromZIO(ZIO.attempt(throw new Exception("boom"))), 42) .sandbox - .toHttpApp + .toRoutes .deploy .body .mapZIO(_.asString) @@ -390,7 +390,7 @@ object ServerSpec extends HttpRunnableSpec { Handler .fromStreamChunked(ZStream.fromZIO(ZIO.attempt(throw new Exception("boom")))) .sandbox - .toHttpApp + .toRoutes .deploy .body .mapZIO(_.asString) @@ -404,7 +404,7 @@ object ServerSpec extends HttpRunnableSpec { Handler .html(zio.http.template.html(body(div(id := "foo", "bar")))) .sandbox - .toHttpApp + .toRoutes .deploy .body .mapZIO(_.asString) @@ -412,15 +412,15 @@ object ServerSpec extends HttpRunnableSpec { assertZIO(res)(equalTo("""
bar
""")) }, test("content-type") { - val app = Handler.html(zio.http.template.html(body(div(id := "foo", "bar")))).sandbox.toHttpApp - val res = app.deploy.header(Header.ContentType).run() + val app = Handler.html(zio.http.template.html(body(div(id := "foo", "bar")))).sandbox + val res = app.toRoutes.deploy.header(Header.ContentType).run() assertZIO(res)(isSome(equalTo(Header.ContentType(MediaType.text.html)))) }, ), suite("content-length")( suite("string") { test("unicode text") { - val res = Handler.text("äöü").sandbox.toHttpApp.deploy.contentLength.run() + val res = Handler.text("äöü").sandbox.toRoutes.deploy.contentLength.run() assertZIO(res)(isSome(equalTo(Header.ContentLength(6L)))) } + test("already set") { @@ -429,7 +429,7 @@ object ServerSpec extends HttpRunnableSpec { .text("1234567890") .addHeader(Header.ContentLength(4L)) .sandbox - .toHttpApp + .toRoutes .deploy .contentLength .run() @@ -443,7 +443,7 @@ object ServerSpec extends HttpRunnableSpec { val expected = (0 to size) map (_ => Status.Ok) val response = Response.text("abc") for { - actual <- ZIO.foreachPar(0 to size)(_ => Handler.fromResponse(response).toHttpApp.deploy.status.run()) + actual <- ZIO.foreachPar(0 to size)(_ => Handler.fromResponse(response).toRoutes.deploy.status.run()) } yield assertTrue(actual == expected) }, test("update after cache") { @@ -453,7 +453,7 @@ object ServerSpec extends HttpRunnableSpec { actual <- Handler .fromResponse(res) .addHeader(Header.Server(server)) - .toHttpApp + .toRoutes .deploy .header(Header.Server) .run() @@ -464,11 +464,11 @@ object ServerSpec extends HttpRunnableSpec { def requestBodySpec = suite("RequestBodySpec")( test("POST Request stream") { - val app: HttpApp[Any, Response] = Routes.singleton { + val app: Routes[Any, Response] = Routes.singleton { handler { (_: Path, req: Request) => Response(body = Body.fromStreamChunked(req.body.asStream)) } - }.toHttpApp + } check(Gen.alphaNumericString) { c => assertZIO(app.deploy.body.mapZIO(_.asString).run(path = Root, method = Method.POST, body = Body.fromString(c)))( @@ -479,17 +479,17 @@ object ServerSpec extends HttpRunnableSpec { ) def serverErrorSpec = suite("ServerErrorSpec") { - val app = Handler.fail(new Error("SERVER_ERROR")).sandbox.toHttpApp + val routes = Handler.fail(new Error("SERVER_ERROR")).sandbox.toRoutes test("status is 500") { - val res = app.deploy.status.run() + val res = routes.deploy.status.run() assertZIO(res)(equalTo(Status.InternalServerError)) } + test("content is empty") { - val res = app.deploy.body.mapZIO(_.asString).run() + val res = routes.deploy.body.mapZIO(_.asString).run() assertZIO(res)(isEmptyString) } + test("header is set") { - val res = app.deploy.headers.run().map(_.header(Header.ContentLength)) + val res = routes.deploy.headers.run().map(_.header(Header.ContentLength)) assertZIO(res)(isSome(anything)) } } diff --git a/zio-http/jvm/src/test/scala/zio/http/ServerStartSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ServerStartSpec.scala index 225751a0b9..d2806b0d12 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ServerStartSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ServerStartSpec.scala @@ -30,7 +30,7 @@ object ServerStartSpec extends HttpRunnableSpec { test("desired port") { val port = 8088 val config = Server.Config.default.port(port) - serve(HttpApp.empty).flatMap { port => + serve(Routes.empty).flatMap { port => assertZIO(ZIO.attempt(port))(equalTo(port)) }.provide( ZLayer.succeed(config), @@ -42,7 +42,7 @@ object ServerStartSpec extends HttpRunnableSpec { test("available port") { val port = 0 val config = Server.Config.default.port(port) - serve(HttpApp.empty).flatMap { bindPort => + serve(Routes.empty).flatMap { bindPort => assertZIO(ZIO.attempt(bindPort))(not(equalTo(port))) }.provide( ZLayer.succeed(config), diff --git a/zio-http/jvm/src/test/scala/zio/http/StaticFileServerSpec.scala b/zio-http/jvm/src/test/scala/zio/http/StaticFileServerSpec.scala index 7499ab3c3f..3c5cecfcf2 100644 --- a/zio-http/jvm/src/test/scala/zio/http/StaticFileServerSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/StaticFileServerSpec.scala @@ -20,24 +20,24 @@ import java.io.File import zio._ import zio.test.Assertion._ -import zio.test.TestAspect.{timeout, unix, withLiveClock} +import zio.test.TestAspect.{unix, withLiveClock} import zio.test.assertZIO import zio.http.internal.{DynamicServer, HttpRunnableSpec, serverTestLayer} object StaticFileServerSpec extends HttpRunnableSpec { - private val fileOk = Handler.fromResource("TestFile.txt").sandbox.toHttpApp.deploy - private val fileNotFound = Handler.fromResource("Nothing").sandbox.toHttpApp.deploy + private val fileOk = Handler.fromResource("TestFile.txt").sandbox.toRoutes.deploy + private val fileNotFound = Handler.fromResource("Nothing").sandbox.toRoutes.deploy private val testArchivePath = getClass.getResource("/TestArchive.jar").getPath private val resourceOk = - Handler.fromResourceWithURL(new java.net.URL(s"jar:file:$testArchivePath!/TestFile.txt")).sandbox.toHttpApp.deploy + Handler.fromResourceWithURL(new java.net.URL(s"jar:file:$testArchivePath!/TestFile.txt")).sandbox.toRoutes.deploy private val resourceNotFound = Handler .fromResourceWithURL(new java.net.URL(s"jar:file:$testArchivePath!/NonExistent.txt")) .sandbox - .toHttpApp + .toRoutes .deploy override def spec = suite("StaticFileServerSpec") { @@ -72,7 +72,7 @@ object StaticFileServerSpec extends HttpRunnableSpec { suite("fromFile")( suite("failure on construction")( test("should respond with 500") { - val res = Handler.fromFile(throw new Error("Wut happened?")).sandbox.toHttpApp.deploy.run().map(_.status) + val res = Handler.fromFile(throw new Error("Wut happened?")).sandbox.toRoutes.deploy.run().map(_.status) assertZIO(res)(equalTo(Status.InternalServerError)) }, ), @@ -80,7 +80,7 @@ object StaticFileServerSpec extends HttpRunnableSpec { test("should respond with 500") { val tmpFile = File.createTempFile("test", "txt") tmpFile.setReadable(false) - val res = Handler.fromFile(tmpFile).sandbox.toHttpApp.deploy.run().map(_.status) + val res = Handler.fromFile(tmpFile).sandbox.toRoutes.deploy.run().map(_.status) assertZIO(res)(equalTo(Status.Forbidden)) } @@ unix, ), @@ -89,7 +89,7 @@ object StaticFileServerSpec extends HttpRunnableSpec { final class BadFile(name: String) extends File(name) { override def exists(): Boolean = throw new Error("Haha") } - val res = Handler.fromFile(new BadFile("Length Failure")).sandbox.toHttpApp.deploy.run().map(_.status) + val res = Handler.fromFile(new BadFile("Length Failure")).sandbox.toRoutes.deploy.run().map(_.status) assertZIO(res)(equalTo(Status.InternalServerError)) }, ), diff --git a/zio-http/jvm/src/test/scala/zio/http/StaticServerSpec.scala b/zio-http/jvm/src/test/scala/zio/http/StaticServerSpec.scala index 71203845f2..1d718404d9 100644 --- a/zio-http/jvm/src/test/scala/zio/http/StaticServerSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/StaticServerSpec.scala @@ -27,7 +27,7 @@ import zio.http.internal.{DynamicServer, HttpGen, HttpRunnableSpec, serverTestLa object StaticServerSpec extends HttpRunnableSpec { - private val staticApp = HttpApp( + private val staticApp = Routes( Method.GET / "success" -> handler(Response.ok), Method.GET / "failure" -> handler(ZIO.fail(new RuntimeException("FAILURE"))), Method.GET / "die" -> handler(ZIO.die(new RuntimeException("DIE"))), @@ -35,17 +35,17 @@ object StaticServerSpec extends HttpRunnableSpec { ).sandbox // Use this route to test anything that doesn't require ZIO related computations. - private val nonZIO = HttpApp( + private val nonZIO = Routes( Method.ANY / "ExitSuccess" -> handler(Exit.succeed(Response.ok)), Method.ANY / "ExitFailure" -> handler(Exit.fail(new RuntimeException("FAILURE"))), Method.ANY / "throwable" -> handlerTODO("Throw inside Handler"), ).sandbox - private val staticAppWithCors = HttpApp( + private val staticAppWithCors = Routes( Method.GET / "success-cors" -> handler(Response.ok.addHeader(Header.Vary("test1", "test2"))), ) @@ cors(CorsConfig(allowedMethods = AccessControlAllowMethods(Method.GET, Method.POST))) - private val combined: HttpApp[Any, Response] = nonZIO ++ staticApp ++ staticAppWithCors + private val combined: Routes[Any, Response] = nonZIO ++ staticApp ++ staticAppWithCors private val app = serve { combined } diff --git a/zio-http/jvm/src/test/scala/zio/http/StatusSpec.scala b/zio-http/jvm/src/test/scala/zio/http/StatusSpec.scala index a25fc3f24f..c4a63ab955 100644 --- a/zio-http/jvm/src/test/scala/zio/http/StatusSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/StatusSpec.scala @@ -42,7 +42,7 @@ object StatusSpec extends ZIOHttpSpec { suite("toHttpApp")( test("status") { checkAll(statusGen) { case status => - val res = status.toHttpApp.runZIO(Request.get(URL.empty)) + val res = status.toRoutes.runZIO(Request.get(URL.empty)) assertZIO(res.map(_.status))(equalTo(status)) } }, diff --git a/zio-http/jvm/src/test/scala/zio/http/WebSocketConfig.scala b/zio-http/jvm/src/test/scala/zio/http/WebSocketConfig.scala index de83ee1f88..7c7936b287 100644 --- a/zio-http/jvm/src/test/scala/zio/http/WebSocketConfig.scala +++ b/zio-http/jvm/src/test/scala/zio/http/WebSocketConfig.scala @@ -42,7 +42,7 @@ object WebSocketConfigSpec extends HttpRunnableSpec { channel.send(closeFrame) case _ => ZIO.unit } - }.toHttpAppWS + }.toRoutes } res <- ZIO.scoped { diff --git a/zio-http/jvm/src/test/scala/zio/http/WebSocketSpec.scala b/zio-http/jvm/src/test/scala/zio/http/WebSocketSpec.scala index b68d266c87..2df18f2628 100644 --- a/zio-http/jvm/src/test/scala/zio/http/WebSocketSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/WebSocketSpec.scala @@ -39,7 +39,7 @@ object WebSocketSpec extends HttpRunnableSpec { case event @ Unregistered => msg.add(event, true) case event => msg.add(event) } - }.toHttpAppWS + }.toRoutes } res <- ZIO.scoped { @@ -85,7 +85,7 @@ object WebSocketSpec extends HttpRunnableSpec { case _ => ZIO.unit } - }.toHttpAppWS.deployWS + }.toRoutes.deployWS // Setup Client // Client closes the connection after 1 second @@ -112,7 +112,7 @@ object WebSocketSpec extends HttpRunnableSpec { } @@ nonFlaky, test("Multiple websocket upgrades") { val app = - Handler.webSocket(channel => channel.send(ChannelEvent.Read(WebSocketFrame.text("BAR")))).toHttpAppWS.deployWS + Handler.webSocket(channel => channel.send(ChannelEvent.Read(WebSocketFrame.text("BAR")))).toRoutes.deployWS val codes = ZIO .foreach(1 to 1024)(_ => app.runZIO(WebSocketApp.unit).map(_.status)) .map(_.count(_ == Status.SwitchingProtocols)) @@ -130,7 +130,7 @@ object WebSocketSpec extends HttpRunnableSpec { case event @ Unregistered => msg.add(event, true) case event => msg.add(event) } - }.toHttpAppWS + }.toRoutes } res <- ZIO.scoped { @@ -179,7 +179,7 @@ object WebSocketSpec extends HttpRunnableSpec { case _ => ZIO.unit } } - }.toHttpAppWS + }.toRoutes } queue1 <- Queue.unbounded[String] diff --git a/zio-http/jvm/src/test/scala/zio/http/ZClientAspectSpec.scala b/zio-http/jvm/src/test/scala/zio/http/ZClientAspectSpec.scala index fc0501667b..1e1a634a82 100644 --- a/zio-http/jvm/src/test/scala/zio/http/ZClientAspectSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/ZClientAspectSpec.scala @@ -17,28 +17,25 @@ package zio.http import zio._ -import zio.test.TestAspect.withLiveClock -import zio.test._ - import zio.http.URL.Location import zio.http.netty.NettyConfig +import zio.test.TestAspect.withLiveClock +import zio.test._ object ZClientAspectSpec extends ZIOHttpSpec { def extractStatus(response: Response): Status = response.status - val app: HttpApp[Any, Response] = { - Route.handled(Method.GET / "hello")(Handler.fromResponse(Response.text("hello"))) - }.toHttpApp + val routes: Routes[Any, Response] = + Route.handled(Method.GET / "hello")(Handler.fromResponse(Response.text("hello"))).toRoutes - val redir: HttpApp[Any, Response] = { - Route.handled(Method.GET / "redirect")(Handler.fromResponse(Response.redirect(URL.empty / "hello"))) - }.toHttpApp + val redir: Routes[Any, Response] = + Route.handled(Method.GET / "redirect")(Handler.fromResponse(Response.redirect(URL.empty / "hello"))).toRoutes override def spec: Spec[TestEnvironment with Scope, Any] = suite("ZClientAspect")( test("debug") { for { - port <- Server.install(app) + port <- Server.install(routes) baseClient <- ZIO.service[Client] client = baseClient.url( URL(Path.empty, Location.Absolute(Scheme.HTTP, "localhost", Some(port))), @@ -54,7 +51,7 @@ object ZClientAspectSpec extends ZIOHttpSpec { }, test("requestLogging")( for { - port <- Server.install(app) + port <- Server.install(routes) baseClient <- ZIO.service[Client] client = baseClient .url( @@ -87,7 +84,7 @@ object ZClientAspectSpec extends ZIOHttpSpec { ), test("followRedirects")( for { - port <- Server.install(redir ++ app) + port <- Server.install(redir ++ routes) baseClient <- ZIO.service[Client] client = baseClient .url( diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/BadRequestSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/BadRequestSpec.scala index 504a32630e..009c6a56e3 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/BadRequestSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/BadRequestSpec.scala @@ -18,7 +18,6 @@ object BadRequestSpec extends ZIOSpecDefault { .query(QueryCodec.queryInt("age")) .out[Unit] val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2").addHeader(Header.Accept(MediaType.text.`html`)) val expectedBody = @@ -31,7 +30,7 @@ object BadRequestSpec extends ZIOSpecDefault { ), ) for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody.encode.toString) }, @@ -40,14 +39,13 @@ object BadRequestSpec extends ZIOSpecDefault { .query(QueryCodec.queryInt("age")) .out[Unit] val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2") .addHeader(Header.Accept(MediaType.application.json)) val expectedBody = """{"name":"SchemaTransformationFailure","message":"Expected single value for query parameter age, but got 2 instead"}""" for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody) }, @@ -56,14 +54,13 @@ object BadRequestSpec extends ZIOSpecDefault { .query(QueryCodec.queryInt("age")) .out[Unit] val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2") .addHeader(Header.Accept(MediaType.application.`atf`)) val expectedBody = """{"name":"SchemaTransformationFailure","message":"Expected single value for query parameter age, but got 2 instead"}""" for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody) }, @@ -73,13 +70,12 @@ object BadRequestSpec extends ZIOSpecDefault { .out[Unit] .emptyErrorResponse val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2") .addHeader(Header.Accept(MediaType.application.`atf`)) val expectedBody = "" for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody) }, @@ -88,14 +84,13 @@ object BadRequestSpec extends ZIOSpecDefault { .query(QueryCodec.queryInt("age")) .out[Unit] val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2") .addHeader(Header.Accept(MediaType.application.json)) val expectedBody = """{"name":"SchemaTransformationFailure","message":"Expected single value for query parameter age, but got 2 instead"}""" for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody) }, @@ -105,14 +100,13 @@ object BadRequestSpec extends ZIOSpecDefault { .out[Unit] .outCodecError(default) val route = endpoint.implement(handler((_: Int) => ())) - val app = route.toHttpApp val request = Request(method = Method.GET, url = url"/test?age=1&age=2") .addHeader(Header.Accept(MediaType.application.json)) val expectedBody = """{"name2":"SchemaTransformationFailure","message2":"Expected single value for query parameter age, but got 2 instead"}""" for { - response <- app.runZIO(request) + response <- route.toRoutes.runZIO(request) body <- response.body.asString } yield assertTrue(body == expectedBody) }, diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/CustomErrorSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/CustomErrorSpec.scala index 50dc2afec6..6e6f9d9460 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/CustomErrorSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/CustomErrorSpec.scala @@ -16,25 +16,15 @@ package zio.http.endpoint -import java.time.Instant - import zio._ -import zio.test._ - -import zio.stream.ZStream - -import zio.schema.annotation.validate -import zio.schema.codec.{DecodeError, JsonCodec} -import zio.schema.validation.Validation -import zio.schema.{DeriveSchema, Schema, StandardType} - -import zio.http.Header.ContentType import zio.http.Method._ import zio.http._ -import zio.http.codec.HttpCodec.{query, queryInt} import zio.http.codec._ import zio.http.endpoint.EndpointSpec.extractStatus -import zio.http.forms.Fixtures.formField +import zio.schema.annotation.validate +import zio.schema.validation.Validation +import zio.schema.{DeriveSchema, Schema} +import zio.test._ object CustomErrorSpec extends ZIOHttpSpec { def spec = suite("CustomErrorSpec")( @@ -49,6 +39,7 @@ object CustomErrorSpec extends ZIOHttpSpec { ZIO.fail(s"path(users, $userId)") } } + .toRoutes val request = Request .get( @@ -56,7 +47,7 @@ object CustomErrorSpec extends ZIOHttpSpec { ) for { - response <- routes.toHttpApp.runZIO(request) + response <- routes.runZIO(request) body <- response.body.asString.orDie } yield assertTrue(extractStatus(response).code == customCode, body == s""""path(users, $userId)"""") } @@ -76,15 +67,16 @@ object CustomErrorSpec extends ZIOHttpSpec { else ZIO.fail(TestError.UnexpectedError("something went wrong")) } } + .toRoutes val request1 = Request.get(URL.decode(s"/users/$myUserId").toOption.get) val request2 = Request.get(URL.decode(s"/users/$invalidUserId").toOption.get) for { - response1 <- routes.toHttpApp.runZIO(request1) + response1 <- routes.runZIO(request1) body1 <- response1.body.asString.orDie - response2 <- routes.toHttpApp.runZIO(request2) + response2 <- routes.runZIO(request2) body2 <- response2.body.asString.orDie } yield assertTrue( extractStatus(response1) == Status.NotFound, @@ -111,14 +103,15 @@ object CustomErrorSpec extends ZIOHttpSpec { .handleErrorCause { cause => Response.text("Caught: " + cause.defects.headOption.fold("no known cause")(d => d.getMessage)) } + .toRoutes val request1 = Request.post(URL.decode("/users").toOption.get, Body.fromString("""{"id":0}""")) val request2 = Request.post(URL.decode("/users").toOption.get, Body.fromString(s"""{"id":$userId}""")) for { - response1 <- routes.toHttpApp.runZIO(request1) + response1 <- routes.runZIO(request1) body1 <- response1.body.asString.orDie - response2 <- routes.toHttpApp.runZIO(request2) + response2 <- routes.runZIO(request2) body2 <- response2.body.asString.orDie } yield assertTrue( extractStatus(response1) == Status.BadRequest, diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/EndpointSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/EndpointSpec.scala index 5f231e72b5..b94e6adea5 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/EndpointSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/EndpointSpec.scala @@ -28,13 +28,13 @@ import zio.http._ object EndpointSpec extends ZIOHttpSpec { def spec = suite("EndpointSpec")() - def testEndpoint[R](service: HttpApp[R, Nothing])( + def testEndpoint[R](service: Routes[R, Nothing])( url: String, expected: String, ): ZIO[R, Response, TestResult] = testEndpointWithHeaders(service)(url, headers = List.empty, expected) - def testEndpointWithHeaders[R](service: HttpApp[R, Nothing])( + def testEndpointWithHeaders[R](service: Routes[R, Nothing])( url: String, headers: List[(String, String)], expected: String, diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/MultipartSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/MultipartSpec.scala index 80d7c5988a..603abfe2b2 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/MultipartSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/MultipartSpec.scala @@ -60,7 +60,7 @@ object MultipartSpec extends ZIOHttpSpec { ), ) } - result <- route.toHttpApp.runZIO(Request.get(URL.decode("/test-form").toOption.get)).exit + result <- route.toRoutes.runZIO(Request.get(URL.decode("/test-form").toOption.get)).exit response <- result match { case Exit.Success(value) => ZIO.succeed(value) case Exit.Failure(cause) => @@ -116,7 +116,7 @@ object MultipartSpec extends ZIOHttpSpec { ), ) } - result <- route.toHttpApp.runZIO(Request.get(URL.decode("/test-form").toOption.get)).exit + result <- route.toRoutes.runZIO(Request.get(URL.decode("/test-form").toOption.get)).exit response <- result match { case Exit.Success(value) => ZIO.succeed(value) case Exit.Failure(cause) => @@ -167,8 +167,7 @@ object MultipartSpec extends ZIOHttpSpec { FormField.binaryField("uploaded-image", bytes, MediaType.image.png), ) boundary <- Boundary.randomUUID - result <- route.toHttpApp - .runZIO( + result <- route.toRoutes.runZIO( Request.post(URL.decode("/test-form").toOption.get, Body.fromMultipartForm(form, boundary)), ) .exit @@ -243,8 +242,7 @@ object MultipartSpec extends ZIOHttpSpec { for { boundary <- Boundary.randomUUID - result <- route.toHttpApp - .runZIO( + result <- route.toRoutes.runZIO( Request.post(URL.decode("/test-form").toOption.get, Body.fromMultipartForm(form, boundary)), ) .exit diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/NotFoundSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/NotFoundSpec.scala index 3440b617a0..8fa0b1fd1d 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/NotFoundSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/NotFoundSpec.scala @@ -40,7 +40,7 @@ object NotFoundSpec extends ZIOHttpSpec { test("on wrong path") { check(Gen.int) { userId => val testRoutes = test404( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .out[String] .implement { @@ -57,7 +57,7 @@ object NotFoundSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/user/$userId", Method.GET) && testRoutes(s"/users/$userId/wrong", Method.GET) } @@ -65,7 +65,7 @@ object NotFoundSpec extends ZIOHttpSpec { test("on wrong method") { check(Gen.int, Gen.int, Gen.alphaNumericString) { (userId, postId, name) => val testRoutes = test404( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .out[String] .implement { @@ -82,14 +82,14 @@ object NotFoundSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users/$userId", Method.POST) && testRoutes(s"/users/$userId/posts/$postId?name=$name", Method.PUT) } }, ) - def test404[R](service: HttpApp[R, Nothing])( + def test404[R](service: Routes[R, Nothing])( url: String, method: Method, ): ZIO[R, Response, TestResult] = { diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/QueryParameterSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/QueryParameterSpec.scala index ea82190c04..82d0b6ec88 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/QueryParameterSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/QueryParameterSpec.scala @@ -31,7 +31,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("simple request with query parameter") { check(Gen.int, Gen.int, Gen.alphaNumericString) { (userId, postId, username) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .out[String] .implement { @@ -48,7 +48,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users/$userId", s"path(users, $userId)") && testRoutes( s"/users/$userId/posts/$postId?name=$username", @@ -59,7 +59,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("optional query parameter") { check(Gen.int, Gen.alphaNumericString) { (userId, details) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(query("details").optional) .out[String] @@ -69,7 +69,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users/$userId", s"path(users, $userId, None)") && testRoutes(s"/users/$userId?details=", s"path(users, $userId, Some())") && testRoutes(s"/users/$userId?details=$details", s"path(users, $userId, Some($details))") @@ -78,7 +78,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("multiple optional query parameters") { check(Gen.int, Gen.alphaNumericString, Gen.alphaNumericString) { (userId, key, value) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(query("key").optional) .query(query("value").optional) @@ -89,7 +89,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users/$userId", s"path(users, $userId, None, None)") && testRoutes(s"/users/$userId?key=&value=", s"path(users, $userId, Some(), Some())") && testRoutes(s"/users/$userId?key=&value=$value", s"path(users, $userId, Some(), Some($value))") && @@ -99,7 +99,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("query parameters with multiple values") { check(Gen.int, Gen.listOfN(3)(Gen.alphaNumericString)) { (userId, keys) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("key")) .out[String] @@ -109,7 +109,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?key=${keys(0)}&key=${keys(1)}&key=${keys(2)}", @@ -128,7 +128,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("optional query parameters with multiple values") { check(Gen.int, Gen.listOfN(3)(Gen.alphaNumericString)) { (userId, keys) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("key").optional) .out[String] @@ -138,7 +138,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?key=${keys(0)}&key=${keys(1)}&key=${keys(2)}", @@ -158,7 +158,7 @@ object QueryParameterSpec extends ZIOHttpSpec { check(Gen.int, Gen.listOfN(3)(Gen.alphaNumericString), Gen.listOfN(2)(Gen.alphaNumericString)) { (userId, keys, values) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("key") & queryAll("value")) .out[String] @@ -168,7 +168,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?key=${keys(0)}&key=${keys(1)}&key=${keys(2)}&value=${values(0)}&value=${values(1)}", @@ -183,7 +183,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("mix of multi value and single value query parameters") { check(Gen.int, Gen.listOfN(2)(Gen.alphaNumericString), Gen.alphaNumericString) { (userId, multi, single) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("multi") & query("single")) .out[String] @@ -193,7 +193,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?multi=${multi(0)}&multi=${multi(1)}&single=$single", @@ -204,7 +204,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("either of two multi value query parameters") { check(Gen.int, Gen.listOfN(2)(Gen.alphaNumericString), Gen.listOfN(2)(Gen.boolean)) { (userId, left, right) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("left") | queryAllBool("right")) .out[String] @@ -214,7 +214,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?left=${left(0)}&left=${left(1)}", @@ -234,7 +234,7 @@ object QueryParameterSpec extends ZIOHttpSpec { check(Gen.int, Gen.listOfN(2)(Gen.alphaNumericString), Gen.listOfN(2)(Gen.alphaNumericString)) { (userId, left, right) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("left") | queryAll("right")) .out[String] @@ -244,7 +244,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?left=${left(0)}&left=${left(1)}", @@ -263,7 +263,7 @@ object QueryParameterSpec extends ZIOHttpSpec { test("either of multi value or single value query parameter") { check(Gen.int, Gen.listOfN(2)(Gen.alphaNumericString), Gen.alphaNumericString) { (userId, left, right) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .query(queryAll("left") | query("right")) .out[String] @@ -273,7 +273,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId?left=${left(0)}&left=${left(1)}", @@ -291,7 +291,7 @@ object QueryParameterSpec extends ZIOHttpSpec { }, test("query parameters keys without values for multi value query") { val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users") .query(queryAllInt("ints")) .out[String] @@ -301,7 +301,7 @@ object QueryParameterSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users?ints", @@ -309,7 +309,7 @@ object QueryParameterSpec extends ZIOHttpSpec { ) }, test("no specified query parameters for multi value query") { - val testRoutes = HttpApp( + val testRoutes = Routes( Endpoint(GET / "users") .query(queryAllInt("ints")) .out[String] @@ -326,7 +326,7 @@ object QueryParameterSpec extends ZIOHttpSpec { }, test("multiple query parameter values to single value query parameter codec") { val testRoutes = - HttpApp( + Routes( Endpoint(GET / "users") .query(queryInt("ints")) .out[String] diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/RequestSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/RequestSpec.scala index 17e70e5d13..7ca694d3e7 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/RequestSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/RequestSpec.scala @@ -36,7 +36,7 @@ object RequestSpec extends ZIOHttpSpec { test("simple request with header") { check(Gen.int, Gen.int, Gen.uuid) { (userId, postId, correlationId) => val testRoutes = testEndpointWithHeaders( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .header(HeaderCodec.name[java.util.UUID]("X-Correlation-ID")) .out[String] @@ -54,7 +54,7 @@ object RequestSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes( s"/users/$userId", List("X-Correlation-ID" -> correlationId.toString), @@ -79,7 +79,7 @@ object RequestSpec extends ZIOHttpSpec { } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request .get(URL.decode(s"/posts?id=$id").toOption.get) .addHeader(Header.Accept(MediaType.text.`plain`)), @@ -101,7 +101,7 @@ object RequestSpec extends ZIOHttpSpec { } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request .get(URL.decode(s"/posts?id=$id").toOption.get) .addHeader(Header.Accept(MediaType.application.`json`, MediaType.text.`plain`)), @@ -123,7 +123,7 @@ object RequestSpec extends ZIOHttpSpec { } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request.get(URL.decode(s"/posts?id=$id").toOption.get), ) } yield assertTrue(extractStatus(response).code == 404) @@ -138,7 +138,7 @@ object RequestSpec extends ZIOHttpSpec { .out[Int] val routes = endpoint.implement { Handler.succeed(id) } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request.get(url"/posts?id=$notAnId").addHeader(Header.Accept(MediaType.application.`json`)), ) contentType = response.header(Header.ContentType) @@ -160,7 +160,7 @@ object RequestSpec extends ZIOHttpSpec { } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request.get(URL.decode(s"/posts").toOption.get).addHeader("X-Correlation-ID", notACorrelationId), ) } yield assertTrue(extractStatus(response).code == 400) @@ -179,7 +179,7 @@ object RequestSpec extends ZIOHttpSpec { } for { - response <- routes.toHttpApp.runZIO( + response <- routes.toRoutes.runZIO( Request.get(URL.decode(s"/posts").toOption.get), ) } yield assertTrue(extractStatus(response).code == 400) @@ -188,7 +188,7 @@ object RequestSpec extends ZIOHttpSpec { test("out of order api") { check(Gen.int, Gen.int, Gen.alphaNumericString, Gen.int(1, Int.MaxValue)) { (userId, postId, name, age) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users" / int("userId")) .out[String] .implement { @@ -206,7 +206,7 @@ object RequestSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users/$userId", s"path(users, $userId)") && testRoutes( s"/users/$userId/posts/$postId?name=$name&age=$age", @@ -217,7 +217,7 @@ object RequestSpec extends ZIOHttpSpec { test("fallback") { check(Gen.int, Gen.alphaNumericString) { (userId, username) => val testRoutes = testEndpoint( - HttpApp( + Routes( Endpoint(GET / "users") .query(queryInt("userId") | query("userId")) .out[String] @@ -228,7 +228,7 @@ object RequestSpec extends ZIOHttpSpec { } }, ), - ) _ + ) _ testRoutes(s"/users?userId=$userId", s"path(users) query(userId=$userId)") && testRoutes(s"/users?userId=$username", s"path(users) query(userId=$username)") } @@ -356,7 +356,7 @@ object RequestSpec extends ZIOHttpSpec { } val testRoutes = testEndpoint( - HttpApp( + Routes( broadUsers, broadUsersId, boardUsersPosts, @@ -374,7 +374,7 @@ object RequestSpec extends ZIOHttpSpec { boardUsersPostsCommentsReplies, boardUsersPostsCommentsRepliesId, ), - ) _ + ) _ testRoutes("/users", "path(users)") && testRoutes(s"/users/$userId", s"path(users, $userId)") && @@ -407,7 +407,7 @@ object RequestSpec extends ZIOHttpSpec { check(Gen.alphaNumericString, Gen.alphaNumericString) { (queryValue, headerValue) => val headerOrQuery = HeaderCodec.name[String]("X-Header") | QueryCodec.query("header") val endpoint = Endpoint(GET / "test").out[String].inCodec(headerOrQuery) - val routes = endpoint.implement(Handler.identity) + val routes = endpoint.implement(Handler.identity).toRoutes val request = Request.get( URL .decode(s"/test?header=$queryValue") @@ -425,11 +425,11 @@ object RequestSpec extends ZIOHttpSpec { .addHeader("X-Header", headerValue) for { - response <- routes.toHttpApp.runZIO(request) + response <- routes.runZIO(request) onlyQuery <- response.body.asString.orDie - response <- routes.toHttpApp.runZIO(requestWithHeader) + response <- routes.runZIO(requestWithHeader) onlyHeader <- response.body.asString.orDie - response <- routes.toHttpApp.runZIO(requestWithHeaderAndQuery) + response <- routes.runZIO(requestWithHeaderAndQuery) headerAndQuery <- response.body.asString.orDie } yield assertTrue( onlyQuery == s""""$queryValue"""", @@ -446,7 +446,7 @@ object RequestSpec extends ZIOHttpSpec { Handler.fromFunction { created => if (created) Right(()) else Left("not created") } - } + }.toRoutes val requestCreated = Request.get( URL .decode("/test?Created=true") @@ -461,9 +461,9 @@ object RequestSpec extends ZIOHttpSpec { ) for { - notCreated <- routes.toHttpApp.runZIO(requestNotCreated) + notCreated <- routes.runZIO(requestNotCreated) header = notCreated.rawHeader("X-Header").get - response <- routes.toHttpApp.runZIO(requestCreated) + response <- routes.runZIO(requestCreated) value = header == "not created" && extractStatus(notCreated) == Status.Ok && extractStatus(response) == Status.Created @@ -481,7 +481,7 @@ object RequestSpec extends ZIOHttpSpec { .in[NewPost](Doc.p("New post")) .out[PostCreated](Status.Created, MediaType.application.`json`) val routes = - endpoint.implement(Handler.succeed(PostCreated(postId))) + endpoint.implement(Handler.succeed(PostCreated(postId))).toRoutes val request = Request .post( @@ -490,7 +490,7 @@ object RequestSpec extends ZIOHttpSpec { ) for { - response <- routes.toHttpApp.runZIO(request) + response <- routes.runZIO(request) code = extractStatus(response) contentType = response.header(Header.ContentType) body <- response.body.asString.orDie @@ -509,10 +509,10 @@ object RequestSpec extends ZIOHttpSpec { .in[NewPost] .out[Int] val routes = - endpoint.implement(Handler.succeed(postId)) + endpoint.implement(Handler.succeed(postId)).toRoutes for { - response <- routes.toHttpApp.runZIO( + response <- routes.runZIO( Request .post( URL.decode("/posts").toOption.get, @@ -529,9 +529,10 @@ object RequestSpec extends ZIOHttpSpec { val route = Endpoint(GET / "test-byte-stream") .outStream[Byte](Doc.p("Test data")) .implement(Handler.succeed(ZStream.fromChunk(bytes).rechunk(16))) + .toRoutes for { - result <- route.toHttpApp.runZIO(Request.get(URL.decode("/test-byte-stream").toOption.get)).exit + result <- route.runZIO(Request.get(URL.decode("/test-byte-stream").toOption.get)).exit response <- result match { case Exit.Success(value) => ZIO.succeed(value) case Exit.Failure(cause) => @@ -552,9 +553,10 @@ object RequestSpec extends ZIOHttpSpec { val route = Endpoint(GET / "test-byte-stream") .outStream[Byte](Status.Ok, MediaType.image.png) .implement(Handler.succeed(ZStream.fromChunk(bytes).rechunk(16))) + .toRoutes for { - result <- route.toHttpApp.runZIO(Request.get(URL.decode("/test-byte-stream").toOption.get)).exit + result <- route.runZIO(Request.get(URL.decode("/test-byte-stream").toOption.get)).exit response <- result match { case Exit.Success(value) => ZIO.succeed(value) case Exit.Failure(cause) => @@ -580,9 +582,10 @@ object RequestSpec extends ZIOHttpSpec { byteStream.runCount } } + .toRoutes for { - result <- route.toHttpApp + result <- route .runZIO(Request.post(URL.decode("/test-byte-stream").toOption.get, Body.fromChunk(bytes))) .exit response <- result match { diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/RoundtripSpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/RoundtripSpec.scala index cc3809e462..d13f0e3dde 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/RoundtripSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/RoundtripSpec.scala @@ -79,7 +79,7 @@ object RoundtripSpec extends ZIOHttpSpec { def testEndpoint[P, In, Err, Out]( endpoint: Endpoint[P, In, Err, Out, EndpointMiddleware.None.type], - route: HttpApp[Any, Nothing], + route: Routes[Any, Nothing], in: In, out: Out, ): ZIO[Client with Server with Scope, Err, TestResult] = @@ -87,7 +87,7 @@ object RoundtripSpec extends ZIOHttpSpec { def testEndpointZIO[P, In, Err, Out]( endpoint: Endpoint[P, In, Err, Out, EndpointMiddleware.None.type], - route: HttpApp[Any, Nothing], + route: Routes[Any, Nothing], in: In, outF: Out => ZIO[Any, Err, TestResult], ): zio.ZIO[Server with Client with Scope, Err, TestResult] = @@ -100,7 +100,7 @@ object RoundtripSpec extends ZIOHttpSpec { } yield result def testEndpointCustomRequestZIO[P, In, Err, Out]( - route: HttpApp[Any, Nothing], + route: Routes[Any, Nothing], in: Request, outF: Response => ZIO[Any, Err, TestResult], ): zio.ZIO[Server with Client with Scope, Err, TestResult] = @@ -115,7 +115,7 @@ object RoundtripSpec extends ZIOHttpSpec { def testEndpointError[P, In, Err, Out]( endpoint: Endpoint[P, In, Err, Out, EndpointMiddleware.None.type], - route: HttpApp[Any, Nothing], + route: Routes[Any, Nothing], in: In, err: Err, ): ZIO[Client with Server with Scope, Out, TestResult] = @@ -123,7 +123,7 @@ object RoundtripSpec extends ZIOHttpSpec { def testEndpointErrorZIO[P, In, Err, Out]( endpoint: Endpoint[P, In, Err, Out, EndpointMiddleware.None.type], - route: HttpApp[Any, Nothing], + route: Routes[Any, Nothing], in: In, errorF: Err => ZIO[Any, Nothing, TestResult], ): ZIO[Client with Server with Scope, Out, TestResult] = @@ -155,10 +155,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( usersPostAPI, - HttpApp(usersPostHandler), + Routes(usersPostHandler), (10, 20), Post(20, "title", "body", 10), - ) + ) }, test("simple get with protobuf encoding via explicit media type") { val usersPostAPI = @@ -175,10 +175,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( usersPostAPI, - HttpApp(usersPostHandler), + Routes(usersPostHandler), (10, 20, Header.Accept(MediaType.parseCustomMediaType("application/protobuf").get)), Post(20, "title", "body", 10), - ) && assertZIO(TestConsole.output)(contains("ContentType: application/protobuf\n")) + ) && assertZIO(TestConsole.output)(contains("ContentType: application/protobuf\n")) }, test("simple get with only protobuf encoding") { implicit def postCodec[T: Schema]: HttpContentCodec[T] = protobuf.only[T] @@ -196,10 +196,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( usersPostAPI, - HttpApp(usersPostHandler), + Routes(usersPostHandler), (10, 20, Header.Accept(MediaType.parseCustomMediaType("application/protobuf").get)), Post(20, "title", "body", 10), - ) && assertZIO(TestConsole.output)(contains("ContentType: application/protobuf\n")) + ) && assertZIO(TestConsole.output)(contains("ContentType: application/protobuf\n")) }, test("simple get with optional query params") { val api = @@ -218,21 +218,21 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( api, - HttpApp(handler), + Routes(handler), (10, 20, None, Some("x")), Post(10, "-", "x", 20), - ) && testEndpoint( + ) && testEndpoint( api, - HttpApp(handler), + Routes(handler), (10, 20, None, None), Post(10, "-", "-", 20), - ) && + ) && testEndpoint( api, - HttpApp(handler), + Routes(handler), (10, 20, Some("x"), Some("y")), Post(10, "x", "y", 20), - ) + ) }, test("throwing error in handler") { val api = Endpoint(POST / string("id") / "xyz" / string("name") / "abc") @@ -244,14 +244,13 @@ object RoundtripSpec extends ZIOHttpSpec { val handler = api.implement { Handler.fromFunction { case (accountId, name, instanceName, args, env) => - println(s"$accountId, $name, $instanceName, $args, $env") throw new RuntimeException("I can't code") s"$accountId, $name, $instanceName, $args, $env" } } for { - port <- Server.install(handler.toHttpApp) + port <- Server.install(handler.toRoutes) client <- ZIO.service[Client] response <- client( Request.post( @@ -274,10 +273,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( api, - HttpApp(route), + Routes(route), (11, Post(1, "title", "body", 111)), "userId: 11, post: Post(1,title,body,111)", - ) + ) }, test("byte stream input") { val api = Endpoint(PUT / "upload").inStream[Byte].out[Long] @@ -290,10 +289,10 @@ object RoundtripSpec extends ZIOHttpSpec { Random.nextBytes(1024 * 1024).flatMap { bytes => testEndpoint( api, - HttpApp(route), + Routes(route), ZStream.fromChunk(bytes).rechunk(1024), 1024 * 1024L, - ) + ) } }, test("byte stream output") { @@ -306,10 +305,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpointZIO( api, - HttpApp(route), + Routes(route), 1024 * 1024, (stream: ZStream[Any, Nothing, Byte]) => stream.runCount.map(c => assert(c)(equalTo(1024L * 1024L))), - ) + ) }, test("multi-part input") { val api = Endpoint(POST / "test") @@ -326,10 +325,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpoint( api, - HttpApp(route), + Routes(route), ("name", 10, Post(1, "title", "body", 111)), "name: name, value: 10, post: Post(1,title,body,111)", - ) + ) }, test("endpoint error returned") { val api = Endpoint(POST / "test") @@ -339,10 +338,10 @@ object RoundtripSpec extends ZIOHttpSpec { testEndpointError( api, - HttpApp(route), + Routes(route), (), "42", - ) + ) }, test("middleware error returned") { @@ -358,9 +357,9 @@ object RoundtripSpec extends ZIOHttpSpec { val endpointRoute = endpoint.implement(Handler.identity) - val routes = endpointRoute + val routes = endpointRoute.toRoutes - val app = routes.toHttpApp @@ alwaysFailingMiddleware + val app = routes @@ alwaysFailingMiddleware .implement(_ => ZIO.fail("FAIL"))(_ => ZIO.unit) for { @@ -397,9 +396,9 @@ object RoundtripSpec extends ZIOHttpSpec { val endpointRoute = endpoint.implement(Handler.identity) - val routes = endpointRoute + val routes = endpointRoute.toRoutes - val app = routes.toHttpApp @@ alwaysFailingMiddleware + val app = routes @@ alwaysFailingMiddleware .implement(_ => ZIO.fail("FAIL"))(_ => ZIO.unit) for { @@ -444,12 +443,10 @@ object RoundtripSpec extends ZIOHttpSpec { } } - val routes = endpointRoute - - val app = routes.toHttpApp + val routes = endpointRoute.toRoutes for { - port <- Server.install(app) + port <- Server.install(routes) executorLayer = ZLayer(ZIO.serviceWith[Client](makeExecutor(_, port))) cause <- ZIO @@ -494,10 +491,10 @@ object RoundtripSpec extends ZIOHttpSpec { Random.nextBytes(1024 * 1024).flatMap { bytes => testEndpoint( api, - HttpApp(route), + Routes(route), ("xyz", 100, ZStream.fromChunk(bytes).rechunk(1024)), s"name: xyz, value: 100, count: ${1024 * 1024}", - ) + ) } }, test("multi-part input with stream and invalid json field") { @@ -519,7 +516,7 @@ object RoundtripSpec extends ZIOHttpSpec { .nextBytes(1024 * 1024) .flatMap { bytes => testEndpointCustomRequestZIO( - HttpApp(route), + Routes(route), Request.post( "/test", Body.fromMultipartForm( @@ -545,7 +542,7 @@ object RoundtripSpec extends ZIOHttpSpec { s == """"name: xyz, metadata: ImageMetadata(sample description,2023-10-02T10:30:00Z), count: 1048576"""", ), ), - ) + ) } .map { r => assert(r.isFailure)(isTrue) // We expect it to fail but complete diff --git a/zio-http/jvm/src/test/scala/zio/http/endpoint/openapi/SwaggerUISpec.scala b/zio-http/jvm/src/test/scala/zio/http/endpoint/openapi/SwaggerUISpec.scala index 12d9e3b11f..a7bfbb7f61 100644 --- a/zio-http/jvm/src/test/scala/zio/http/endpoint/openapi/SwaggerUISpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/endpoint/openapi/SwaggerUISpec.scala @@ -34,7 +34,7 @@ object SwaggerUISpec extends ZIOSpecDefault { OpenAPIGen.fromEndpoints(title = "Another Endpoint Example", version = "2.0", getUser, getUserPosts) val routes = - HttpApp(getUserRoute, getUserPostsRoute) ++ SwaggerUI.app("docs" / "openapi", openAPIv1, openAPIv2) + Routes(getUserRoute, getUserPostsRoute) ++ SwaggerUI.routes("docs" / "openapi", openAPIv1, openAPIv2) val response = routes.apply(Request(method = Method.GET, url = url"/docs/openapi")) diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/DynamicServer.scala b/zio-http/jvm/src/test/scala/zio/http/internal/DynamicServer.scala index 92a7de9a9a..0f1d070b9a 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/DynamicServer.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/DynamicServer.scala @@ -24,9 +24,9 @@ import zio.http._ import zio.http.internal.DynamicServer.Id sealed trait DynamicServer { - def add(app: HttpApp[Any, Response]): UIO[Id] + def add(app: Routes[Any, Response]): UIO[Id] - def get(id: Id): UIO[Option[HttpApp[Any, Response]]] + def get(id: Id): UIO[Option[Routes[Any, Response]]] def port: ZIO[Any, Nothing, Int] @@ -41,7 +41,7 @@ object DynamicServer { val APP_ID = "X-APP_ID" - def app(dynamicServer: DynamicServer): RequestHandler[Any, Response] = + def handler(dynamicServer: DynamicServer): RequestHandler[Any, Response] = Handler.fromFunctionHandler[Request] { (req: Request) => Handler .fromZIO(req.rawHeader(APP_ID) match { @@ -59,13 +59,13 @@ object DynamicServer { def baseURL(scheme: Scheme): ZIO[DynamicServer, Nothing, String] = port.map(port => s"${scheme.encode}://localhost:$port") - def deploy[R](app: HttpApp[R, Response]): ZIO[DynamicServer with R, Nothing, String] = + def deploy[R](app: Routes[R, Response]): ZIO[DynamicServer with R, Nothing, String] = for { env <- ZIO.environment[R] id <- ZIO.environmentWithZIO[DynamicServer](_.get.add(app.provideEnvironment(env))) } yield id - def get(id: Id): ZIO[DynamicServer, Nothing, Option[HttpApp[Any, Response]]] = + def get(id: Id): ZIO[DynamicServer, Nothing, Option[Routes[Any, Response]]] = ZIO.environmentWithZIO[DynamicServer](_.get.get(id)) def httpURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.HTTP) @@ -73,7 +73,7 @@ object DynamicServer { val live: ZLayer[Any, Nothing, DynamicServer] = ZLayer { for { - ref <- Ref.make(Map.empty[Id, HttpApp[Any, Response]]) + ref <- Ref.make(Map.empty[Id, Routes[Any, Response]]) pr <- Promise.make[Nothing, Server] } yield new Live(ref, pr) } @@ -87,13 +87,13 @@ object DynamicServer { def wsURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.WS) - final class Live(ref: Ref[Map[Id, HttpApp[Any, Response]]], pr: Promise[Nothing, Server]) extends DynamicServer { - def add(app: HttpApp[Any, Response]): UIO[Id] = for { + final class Live(ref: Ref[Map[Id, Routes[Any, Response]]], pr: Promise[Nothing, Server]) extends DynamicServer { + def add(app: Routes[Any, Response]): UIO[Id] = for { id <- ZIO.succeed(UUID.randomUUID().toString) _ <- ref.update(map => map + (id -> app)) } yield id - def get(id: Id): UIO[Option[HttpApp[Any, Response]]] = ref.get.map(_.get(id)) + def get(id: Id): UIO[Option[Routes[Any, Response]]] = ref.get.map(_.get(id)) def port: ZIO[Any, Nothing, Int] = start.map(_.port) diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/HttpAppTestExtensions.scala b/zio-http/jvm/src/test/scala/zio/http/internal/HttpAppTestExtensions.scala index 7c8c7b3cb9..5dc7a81d58 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/HttpAppTestExtensions.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/HttpAppTestExtensions.scala @@ -19,7 +19,7 @@ package zio.http.internal import zio.http._ trait HttpAppTestExtensions { - implicit class HttpAppSyntax[R](route: HttpApp[R, Response]) { + implicit class HttpAppSyntax[R](route: Routes[R, Response]) { def rawHeader(name: String): Handler[R, Response, Request, Option[String]] = route.toHandler.map(res => res.rawHeader(name)) diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/HttpRunnableSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/HttpRunnableSpec.scala index 76c7f5ca21..9807027cd7 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/HttpRunnableSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/HttpRunnableSpec.scala @@ -16,10 +16,9 @@ package zio.http.internal -import zio.{Scope, ZIO} - import zio.http.URL.Location import zio.http._ +import zio.{Scope, ZIO} /** * Should be used only when e2e tests needs to be written. Typically we would @@ -29,9 +28,9 @@ import zio.http._ * requests. */ abstract class HttpRunnableSpec extends ZIOHttpSpec { self => - implicit class RunnableHttpClientAppSyntax[R](route: HttpApp[R, Response]) { + implicit class RunnableHttpClientAppSyntax[R](route: Routes[R, Response]) { - def app: HttpApp[R, Response] = route + def app: Routes[R, Response] = route /** * Deploys the http application on the test server and returns a Http of @@ -107,12 +106,12 @@ abstract class HttpRunnableSpec extends ZIOHttpSpec { self => for { server <- ZIO.service[Server] ds <- ZIO.service[DynamicServer] - app = DynamicServer.app(ds) - port <- Server.install(app.toHttpApp) + handler = DynamicServer.handler(ds) + port <- Server.install(handler.toRoutes) _ <- DynamicServer.setStart(server) } yield port - def serve[R](app: HttpApp[R, Response]): ZIO[R with DynamicServer with Server, Nothing, Int] = + def serve[R](app: Routes[R, Response]): ZIO[R with DynamicServer with Server, Nothing, Int] = for { server <- ZIO.service[Server] port <- Server.install(app) diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/AuthSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/AuthSpec.scala index 032d43a1cc..fc60b13403 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/AuthSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/AuthSpec.scala @@ -80,7 +80,7 @@ object AuthSpec extends ZIOHttpSpec with HttpAppTestExtensions { }, test("Extract username via context with Routes") { val app = { - HttpApp( + Routes( Method.GET / "context" -> basicAuthContextM -> Handler.fromFunction[(AuthContext, Request)] { case (c: AuthContext, _) => Response.text(c.value) }, ) @@ -106,7 +106,7 @@ object AuthSpec extends ZIOHttpSpec with HttpAppTestExtensions { assertZIO(app.runZIO(Request.get(URL.empty).copy(headers = failureBasicHeader)))(isSome) }, test("Provide for multiple routes") { - val secureRoutes = HttpApp( + val secureRoutes = Routes( Method.GET / "a" -> handler((_: Request) => ZIO.serviceWith[AuthContext](ctx => Response.text(ctx.value))), Method.GET / "b" / int("id") -> handler((id: Int, _: Request) => ZIO.serviceWith[AuthContext](ctx => Response.text(s"for id: $id: ${ctx.value}")), @@ -144,9 +144,9 @@ object AuthSpec extends ZIOHttpSpec with HttpAppTestExtensions { assertZIO(app.runZIO(Request.get(URL.empty).copy(headers = failureBearerHeader)))(isSome) }, test("Does not affect fallback apps") { - val app1 = HttpApp(Method.GET / "a" -> Handler.ok) - val app2 = HttpApp(Method.GET / "b" -> Handler.ok) - val app3 = HttpApp(Method.GET / "c" -> Handler.ok) + val app1 = Routes(Method.GET / "a" -> Handler.ok) + val app2 = Routes(Method.GET / "b" -> Handler.ok) + val app3 = Routes(Method.GET / "c" -> Handler.ok) val app = app1 ++ app2 @@ bearerAuthM ++ app3 for { s1 <- app.runZIO(Request.get(URL(Root / "a")).copy(headers = failureBearerHeader)) @@ -170,9 +170,9 @@ object AuthSpec extends ZIOHttpSpec with HttpAppTestExtensions { assertZIO(app.runZIO(Request.get(URL.empty).copy(headers = failureBearerHeader)))(isSome) }, test("Does not affect fallback apps") { - val app1 = HttpApp(Method.GET / "a" -> Handler.ok) - val app2 = HttpApp(Method.GET / "b" -> Handler.ok) - val app3 = HttpApp(Method.GET / "c" -> Handler.ok) + val app1 = Routes(Method.GET / "a" -> Handler.ok) + val app2 = Routes(Method.GET / "b" -> Handler.ok) + val app3 = Routes(Method.GET / "c" -> Handler.ok) val app = app1 ++ app2 @@ bearerAuthZIOM ++ app3 for { s1 <- app.runZIO(Request.get(URL(Root / "a")).copy(headers = failureBearerHeader)) diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/CorsSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/CorsSpec.scala index 312e4b76c0..02f2fa5aec 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/CorsSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/CorsSpec.scala @@ -27,7 +27,7 @@ import zio.http.internal.HttpAppTestExtensions object CorsSpec extends ZIOHttpSpec with HttpAppTestExtensions { def extractStatus(response: Response): Status = response.status - val app = HttpApp( + val app = Routes( Method.GET / "success" -> handler(Response.ok), Method.GET / "failure" -> handler(ZIO.fail("failure")), Method.GET / "die" -> handler(ZIO.dieMessage("die")), diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/MetricsSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/MetricsSpec.scala index 5c44953fd1..3e454e03e5 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/MetricsSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/MetricsSpec.scala @@ -29,7 +29,7 @@ object MetricsSpec extends ZIOHttpSpec with HttpAppTestExtensions { override def spec: Spec[TestEnvironment with Scope, Any] = suite("MetricsSpec")( test("http_requests_total & http_errors_total") { - val app = HttpApp( + val app = Routes( Method.GET / "ok" -> Handler.ok, Method.GET / "error" -> Handler.internalServerError, Method.GET / "fail" -> Handler.fail(Response.status(Status.Forbidden)), @@ -61,7 +61,7 @@ object MetricsSpec extends ZIOHttpSpec with HttpAppTestExtensions { ) }, test("http_requests_total with path label mapper") { - val app = (Method.GET / "user" / int("id") -> Handler.ok).toHttpApp @@ metrics( + val routes = (Method.GET / "user" / int("id") -> Handler.ok).toRoutes @@ metrics( extraLabels = Set(MetricLabel("test", "http_requests_total with path label mapper")), ) @@ -70,8 +70,8 @@ object MetricsSpec extends ZIOHttpSpec with HttpAppTestExtensions { val totalOk = total.tagged("path", "/user/{id}").tagged("method", "GET").tagged("status", "200") for { - _ <- app.runZIO(Request.get(url = URL(Root / "user" / "1"))) - _ <- app.runZIO(Request.get(url = URL(Root / "user" / "2"))) + _ <- routes.runZIO(Request.get(url = URL(Root / "user" / "1"))) + _ <- routes.runZIO(Request.get(url = URL(Root / "user" / "2"))) totalOkCount <- totalOk.value } yield assertTrue(totalOkCount == MetricState.Counter(2)) }, @@ -86,8 +86,8 @@ object MetricsSpec extends ZIOHttpSpec with HttpAppTestExtensions { .tagged("method", "GET") .tagged("status", "200") - val app: HttpApp[Any, Response] = - (Method.GET / "ok" -> Handler.ok).toHttpApp @@ metrics(extraLabels = + val app: Routes[Any, Response] = + (Method.GET / "ok" -> Handler.ok).toRoutes @@ metrics(extraLabels = Set(MetricLabel("test", "http_request_duration_seconds")), ) @@ -105,7 +105,7 @@ object MetricsSpec extends ZIOHttpSpec with HttpAppTestExtensions { for { promise <- Promise.make[Nothing, Unit] - app = HttpApp( + app = Routes( Method.ANY / PathCodec.trailing -> (Handler.fromZIO(promise.succeed(())) *> Handler.ok.delay(10.seconds)), ) @@ metrics(extraLabels = Set(MetricLabel("test", "http_concurrent_requests_total"))) before <- gauge.value diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/RequestLoggingSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/RequestLoggingSpec.scala index caf2b985a0..693ea0fee7 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/RequestLoggingSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/RequestLoggingSpec.scala @@ -25,7 +25,7 @@ import zio.http.internal.HttpAppTestExtensions object RequestLoggingSpec extends ZIOHttpSpec with HttpAppTestExtensions { - private val app = HttpApp( + private val app = Routes( Method.GET / "ok" -> Handler.ok, Method.GET / "error" -> Handler.internalServerError, Method.GET / "fail" -> Handler.fail(Response.status(Status.Forbidden)), diff --git a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/WebSpec.scala b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/WebSpec.scala index 347e345a99..dfb5275c9d 100644 --- a/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/WebSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/internal/middlewares/WebSpec.scala @@ -29,7 +29,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => def extractStatus(response: Response): Status = response.status private val app = - HttpApp( + Routes( Method.GET / "health" -> handler(ZIO.succeed(Response.ok).delay(1 second)), ) @@ -40,23 +40,23 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => suite("headers suite")( test("addHeaders") { val middleware = addHeaders(Headers("KeyA", "ValueA") ++ Headers("KeyB", "ValueB")) - val headers = (Handler.ok @@ middleware).toHttpApp.headerValues + val headers = (Handler.ok @@ middleware).headerValues assertZIO(headers.runZIO(Request.get(URL.empty)))(contains("ValueA") && contains("ValueB")) }, test("addHeader") { val middleware = addHeader("KeyA", "ValueA") - val headers = (Handler.ok @@ middleware).toHttpApp.headerValues + val headers = (Handler.ok @@ middleware).headerValues assertZIO(headers.runZIO(Request.get(URL.empty)))(contains("ValueA")) }, test("updateHeaders") { val middleware = updateHeaders(_ => Headers("KeyA", "ValueA")) - val headers = (Handler.ok @@ middleware).toHttpApp.headerValues + val headers = (Handler.ok @@ middleware).headerValues assertZIO(headers.runZIO(Request.get(URL.empty)))(contains("ValueA")) }, test("removeHeader") { val middleware = removeHeader("KeyA") val headers = - (Handler.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware).toHttpApp rawHeader "KeyA" + (Handler.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware) rawHeader "KeyA" assertZIO(headers.runZIO(Request.get(URL.empty)))(isNone) }, ), @@ -73,7 +73,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => }, test("log 404 status method url and time") { for { - _ <- runApp((Handler.notFound @@ debug).toHttpApp) + _ <- runApp(Handler.notFound.toRoutes @@ debug) log <- TestConsole.output } yield assertTrue( log.size == 1, @@ -216,7 +216,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => ), ) checkAll(urls) { case (url, expected) => - val app = HttpApp( + val app = Routes( Method.ANY / PathCodec.trailing -> handler { (_: Path, req: Request) => Response.text(req.url.encode) }, @@ -240,7 +240,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => ) checkAll(urls zip Gen.fromIterable(Seq(true, false))) { case (url, expected, perm) => - val app = (Handler.ok @@ redirectTrailingSlash(perm)).toHttpApp + val app = (Handler.ok @@ redirectTrailingSlash(perm)) val location = if (url != expected) Some(expected) else None val status = if (url == expected) Status.Ok @@ -268,7 +268,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => ) checkAll(urls) { url => - val app = (Handler.ok @@ redirectTrailingSlash(true)).toHttpApp + val app = (Handler.ok @@ redirectTrailingSlash(true)) for { url <- ZIO.fromEither(URL.decode(url)) response <- app.runZIO(Request.get(url = url)) @@ -317,7 +317,7 @@ object WebSpec extends ZIOHttpSpec with HttpAppTestExtensions { self => private def condZIO(flg: Boolean) = (_: Any) => ZIO.succeed(flg) - private def runApp[R](app: HttpApp[R, Response]): ZIO[R, Response, Response] = { + private def runApp[R](app: Routes[R, Response]): ZIO[R, Response, Response] = { for { fib <- app.runZIO { Request.get(url = URL(Root / "health")) }.fork _ <- TestClock.adjust(10 seconds) diff --git a/zio-http/jvm/src/test/scala/zio/http/netty/NettyStreamBodySpec.scala b/zio-http/jvm/src/test/scala/zio/http/netty/NettyStreamBodySpec.scala index 89b34a8c2f..af011ee769 100644 --- a/zio-http/jvm/src/test/scala/zio/http/netty/NettyStreamBodySpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/netty/NettyStreamBodySpec.scala @@ -14,7 +14,7 @@ import zio.http.netty.NettyConfig.LeakDetectionLevel object NettyStreamBodySpec extends HttpRunnableSpec { def app(streams: Iterator[ZStream[Any, Throwable, Byte]], len: Long) = - HttpApp( + Routes( Method.GET / "with-content-length" -> handler( http.Response( diff --git a/zio-http/jvm/src/test/scala/zio/http/netty/client/NettyConnectionPoolSpec.scala b/zio-http/jvm/src/test/scala/zio/http/netty/client/NettyConnectionPoolSpec.scala index 2649765462..f670c4b722 100644 --- a/zio-http/jvm/src/test/scala/zio/http/netty/client/NettyConnectionPoolSpec.scala +++ b/zio-http/jvm/src/test/scala/zio/http/netty/client/NettyConnectionPoolSpec.scala @@ -30,7 +30,7 @@ import zio.http.netty.NettyConfig object NettyConnectionPoolSpec extends HttpRunnableSpec { - private val app = HttpApp( + private val app = Routes( Method.POST / "streaming" -> handler((req: Request) => Response(body = Body.fromStreamChunked(req.body.asStream))), Method.GET / "slow" -> handler(ZIO.sleep(1.hour).as(Response.text("done"))), Method.ANY / trailing -> handler((_: Path, req: Request) => req.body.asString.map(Response.text(_))), diff --git a/zio-http/shared/src/main/scala-2/zio/http/HttpAppVersionSpecific.scala b/zio-http/shared/src/main/scala-2/zio/http/HttpAppVersionSpecific.scala deleted file mode 100644 index 02babc74ff..0000000000 --- a/zio-http/shared/src/main/scala-2/zio/http/HttpAppVersionSpecific.scala +++ /dev/null @@ -1,14 +0,0 @@ -package zio.http - -import zio.Tag - -trait HttpAppVersionSpecific { - private[http] class ApplyContextAspect[-Env, +Err, Env0](private val self: HttpApp[Env, Err]) { - def apply[Env1, Env2 <: Env, Ctx: Tag](aspect: HandlerAspect[Env1, Ctx])(implicit - ev: Env0 with Ctx <:< Env, - tag: Tag[Env0], - tag1: Tag[Env1], - ): HttpApp[Env0 with Env1, Err] = self.transform(_.@@[Env0](aspect)) - } - -} diff --git a/zio-http/shared/src/main/scala-3/zio/http/HttpAppVersionSpecific.scala b/zio-http/shared/src/main/scala-3/zio/http/HttpAppVersionSpecific.scala deleted file mode 100644 index 8d545ca3c8..0000000000 --- a/zio-http/shared/src/main/scala-3/zio/http/HttpAppVersionSpecific.scala +++ /dev/null @@ -1,10 +0,0 @@ -package zio.http - -trait HttpAppVersionSpecific { - private[http] class ApplyContextAspect[-Env, +Err, Env0](private val self: HttpApp[Env, Err]) { - transparent inline def apply[Env1, Env2 <: Env, Ctx](aspect: HandlerAspect[Env1, Ctx])(implicit - ev: Env0 with Ctx <:< Env, - ): HttpApp[Env0 with Env1, Err] = self.transform(_.@@[Env0](aspect)) - } - -} diff --git a/zio-http/shared/src/main/scala/zio/http/Driver.scala b/zio-http/shared/src/main/scala/zio/http/Driver.scala index 1eeb0abb0a..f1e7871230 100644 --- a/zio-http/shared/src/main/scala/zio/http/Driver.scala +++ b/zio-http/shared/src/main/scala/zio/http/Driver.scala @@ -26,7 +26,7 @@ import zio.http.Driver.StartResult trait Driver { def start(implicit trace: Trace): RIO[Scope, StartResult] - def addApp[R](newApp: HttpApp[R, Response], env: ZEnvironment[R])(implicit trace: Trace): UIO[Unit] + def addApp[R](newApp: Routes[R, Response], env: ZEnvironment[R])(implicit trace: Trace): UIO[Unit] def createClientDriver()(implicit trace: Trace): ZIO[Scope, Throwable, ClientDriver] } diff --git a/zio-http/shared/src/main/scala/zio/http/Handler.scala b/zio-http/shared/src/main/scala/zio/http/Handler.scala index 1b27ca083e..bf65d57b51 100644 --- a/zio-http/shared/src/main/scala/zio/http/Handler.scala +++ b/zio-http/shared/src/main/scala/zio/http/Handler.scala @@ -608,11 +608,25 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => * the handler has been appropriately sandboxed, turning all possible failures * into well-formed HTTP responses. */ - def toHttpApp(implicit in: Request <:< In, out: Out <:< Response, trace: Trace): HttpApp[R, Err] = { + @deprecated("Use toRoutes instead. Will be removed in the next release.") + def toHttpApp(implicit err: Err <:< Response, in: Request <:< In, out: Out <:< Response, trace: Trace): HttpApp[R] = { + val handler: Handler[R, Response, Request, Response] = + self.asInstanceOf[Handler[R, Response, Request, Response]] + + HttpApp(Routes.singleton(handler.contramap[(Path, Request)](_._2))) + } + + /** + * Converts the request handler into an HTTP application. Note that the + * handler of the HTTP application is not identical to this handler, because + * the handler has been appropriately sandboxed, turning all possible failures + * into well-formed HTTP responses. + */ + def toRoutes(implicit in: Request <:< In, out: Out <:< Response, trace: Trace): Routes[R, Err] = { val handler: Handler[R, Err, Request, Response] = self.asInstanceOf[Handler[R, Err, Request, Response]] - HttpApp(Routes.singleton(handler.contramap[(Path, Request)](_._2))) + Routes.singleton(handler.contramap[(Path, Request)](_._2)) } /** diff --git a/zio-http/shared/src/main/scala/zio/http/HandlerAspect.scala b/zio-http/shared/src/main/scala/zio/http/HandlerAspect.scala index 2cdd998a9f..2628a0c515 100644 --- a/zio-http/shared/src/main/scala/zio/http/HandlerAspect.scala +++ b/zio-http/shared/src/main/scala/zio/http/HandlerAspect.scala @@ -90,8 +90,7 @@ final case class HandlerAspect[-Env, +CtxOut]( * Applies middleware to the specified handler, which may ignore the context * produced by this middleware. */ - @deprecated("Transform your Routes to HttpApp and use the overloaded apply for HttpApp.") - def apply[Env1 <: Env, Err]( + override def apply[Env1 <: Env, Err]( routes: Routes[Env1, Err], ): Routes[Env1, Err] = routes.transform[Env1] { handler => @@ -107,26 +106,6 @@ final case class HandlerAspect[-Env, +CtxOut]( } } - /** - * Applies middleware to the specified handler, which may ignore the context - * produced by this middleware. - */ - override def apply[Env1 <: Env, Err]( - routes: HttpApp[Env1, Err], - ): HttpApp[Env1, Err] = - routes.transform[Env1] { handler => - if (self == HandlerAspect.identity) handler - else { - for { - tuple <- protocol.incomingHandler - (state, (request, ctxOut)) = tuple - either <- Handler.fromZIO(handler(request)).either - response <- Handler.fromZIO(protocol.outgoingHandler((state, either.merge))) - response <- if (either.isLeft) Handler.fail(response) else Handler.succeed(response) - } yield response - } - } - /** * Applies middleware to the specified handler, which must process the context * produced by this middleware. diff --git a/zio-http/shared/src/main/scala/zio/http/HttpApp.scala b/zio-http/shared/src/main/scala/zio/http/HttpApp.scala index 03056a8d30..b4761f9ce6 100644 --- a/zio-http/shared/src/main/scala/zio/http/HttpApp.scala +++ b/zio-http/shared/src/main/scala/zio/http/HttpApp.scala @@ -17,9 +17,7 @@ package zio.http import zio._ - -import zio.http.HttpApp.ApplyContextAspect -import zio.http.codec.PathCodec +import zio.stacktracer.TracingImplicits.disableAutoTrace /** * An HTTP application is a collection of routes, all of whose errors have been @@ -28,125 +26,30 @@ import zio.http.codec.PathCodec * HTTP applications can be installed into a [[zio.http.Server]], which is * capable of using them to serve requests. */ -final case class HttpApp[-Env, +Err](routes: Chunk[zio.http.Route[Env, Err]]) -/*extends PartialFunction[Request, ZIO[Env, Response, Response]]*/ { self => +@deprecated("Use Routes instead. Will be removed in the next release.") +final case class HttpApp[-Env](routes: Routes[Env, Response]) + extends PartialFunction[Request, ZIO[Env, Response, Response]] { self => private var _tree: HttpApp.Tree[_] = null.asInstanceOf[HttpApp.Tree[_]] - def @@[Env1 <: Env](aspect: Middleware[Env1]): HttpApp[Env1, Err] = - aspect(self) - - def @@[Env0](aspect: HandlerAspect[Env0, Unit]): HttpApp[Env with Env0, Err] = - aspect(self) - - def @@[Env0, Ctx <: Env]( - aspect: HandlerAspect[Env0, Ctx], - )(implicit tag: Tag[Ctx]): HttpApp[Env0, Err] = - self.transform(_ @@ aspect) - - def @@[Env0]: ApplyContextAspect[Env, Err, Env0] = - new ApplyContextAspect[Env, Err, Env0](self) + /** + * Applies the specified route aspect to every route in the HTTP application. + */ + def @@[Env1 <: Env](aspect: Middleware[Env1]): HttpApp[Env1] = + copy(routes = routes @@ aspect) /** * Combines this HTTP application with the specified HTTP application. In case * of route conflicts, the routes in this HTTP application take precedence * over the routes in the specified HTTP application. */ - def ++[Env1 <: Env, Err1 >: Err](that: HttpApp[Env1, Err1]): HttpApp[Env1, Err1] = + def ++[Env1 <: Env](that: HttpApp[Env1]): HttpApp[Env1] = copy(routes = routes ++ that.routes) - /** - * Prepend the specified route to this HttpApp - */ - def +:[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): HttpApp[Env1, Err1] = - copy(routes = route +: routes) - - /** - * Appends the specified route to this HttpApp - */ - def :+[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): HttpApp[Env1, Err1] = - copy(routes = routes :+ route) - /** * Executes the HTTP application with the specified request input, returning * an effect that will either succeed or fail with a Response. */ - def apply(request: Request)(implicit ev: Err <:< Response): ZIO[Env, Response, Response] = - runZIO(request) - - /** - * Handles all typed errors in the routes by converting them into responses. - * This method can be used to convert routes that do not handle their errors - * into ones that do handle their errors. - */ - def handleError(f: Err => Response)(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleError(f))) - - def handleErrorZIO(f: Err => ZIO[Any, Nothing, Response])(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorZIO(f))) - - /** - * Handles all typed errors, as well as all non-recoverable errors, by - * converting them into responses. This method can be used to convert routes - * that do not handle their errors into ones that do handle their errors. - */ - def handleErrorCause(f: Cause[Err] => Response)(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorCause(f))) - - /** - * Handles all typed errors, as well as all non-recoverable errors, by - * converting them into a ZIO effect that produces the response. This method - * can be used to convert routes that do not handle their errors into ones - * that do handle their errors. - */ - def handleErrorCauseZIO(f: Cause[Err] => ZIO[Any, Nothing, Response])(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorCauseZIO(f))) - - /** - * Allows the transformation of the Err type through an Effectful program - * allowing one to build up a HttpApp in Stages delegates to the Route - */ - def mapErrorZIO[Err1](fxn: Err => ZIO[Any, Err1, Response])(implicit trace: Trace): HttpApp[Env, Err1] = - new HttpApp(routes.map(_.mapErrorZIO(fxn))) - - /** - * Allows the transformation of the Err type through a function allowing one - * to build up a HttpApp in Stages delegates to the Route - */ - def mapError[Err1](fxn: Err => Err1): HttpApp[Env, Err1] = - new HttpApp(routes.map(_.mapError(fxn))) - - def nest(prefix: PathCodec[Unit])(implicit trace: Trace, ev: Err <:< Response): HttpApp[Env, Err] = - new HttpApp(self.routes.map(_.nest(prefix))) - - /** - * Handles all typed errors in the routes by converting them into responses, - * taking into account the request that caused the error. This method can be - * used to convert routes that do not handle their errors into ones that do - * handle their errors. - */ - def handleErrorRequest(f: (Err, Request) => Response)(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorRequest(f))) - - /** - * Handles all typed errors in the routes by converting them into responses, - * taking into account the request that caused the error. This method can be - * used to convert routes that do not handle their errors into ones that do - * handle their errors. - */ - def handleErrorRequestCause(f: (Request, Cause[Err]) => Response)(implicit trace: Trace): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorRequestCause(f))) - - /** - * Handles all typed errors, as well as all non-recoverable errors, by - * converting them into a ZIO effect that produces the response, taking into - * account the request that caused the error. This method can be used to - * convert routes that do not handle their errors into ones that do handle - * their errors. - */ - def handleErrorRequestCauseZIO(f: (Request, Cause[Err]) => ZIO[Any, Nothing, Response])(implicit - trace: Trace, - ): HttpApp[Env, Nothing] = - new HttpApp(routes.map(_.handleErrorRequestCauseZIO(f))) + def apply(request: Request): ZIO[Env, Response, Response] = runZIO(request) /** * Checks to see if the HTTP application may be defined at the specified @@ -155,78 +58,41 @@ final case class HttpApp[-Env, +Err](routes: Chunk[zio.http.Route[Env, Err]]) * This method only checks for the presence of a handler that handles the * method and path of the specified request. */ - def isDefinedAt(request: Request)(implicit ev: Err <:< Response): Boolean = - tree(Trace.empty, ev).get(request.method, request.path).nonEmpty + def isDefinedAt(request: Request): Boolean = + tree(Trace.empty).get(request.method, request.path).nonEmpty /** * Provides the specified environment to the HTTP application, returning a new * HTTP application that has no environmental requirements. */ - def provideEnvironment(env: ZEnvironment[Env]): HttpApp[Any, Err] = - copy(routes = routes.map(_.provideEnvironment(env))) - - def run(request: Request)(implicit trace: Trace): ZIO[Env, Either[Err, Response], Response] = { - - class RouteFailure[+Err](val err: Cause[Err]) extends Throwable(null, null, true, false) { - override def getMessage: String = err.unified.headOption.fold("")(_.message) - - override def getStackTrace(): Array[StackTraceElement] = - err.unified.headOption.fold[Chunk[StackTraceElement]](Chunk.empty)(_.trace).toArray - - override def getCause(): Throwable = - err.find { case Cause.Die(throwable, _) => throwable } - .orElse(err.find { case Cause.Fail(value: Throwable, _) => value }) - .orNull - - override def toString = - err.prettyPrint - } - var routeFailure: RouteFailure[Err] = null - - handleErrorCauseZIO { cause => - routeFailure = new RouteFailure(cause) - ZIO.refailCause(Cause.die(routeFailure)) - } - .apply(request) - .mapErrorCause { - case Cause.Die(value: RouteFailure[_], _) if value == routeFailure => routeFailure.err.map(Left(_)) - case cause => cause.map(Right(_)) - } - } + def provideEnvironment(env: ZEnvironment[Env]): HttpApp[Any] = + copy(routes = routes.provideEnvironment(env)) def run( method: Method = Method.GET, path: Path = Path.root, headers: Headers = Headers.empty, body: Body = Body.empty, - )(implicit ev: Err <:< Response): ZIO[Env, Nothing, Response] = + ): ZIO[Env, Nothing, Response] = runZIO(Request(method = method, url = URL.root.path(path), headers = headers, body = body)) /** * An alias for `apply`. */ - def runZIO(request: Request)(implicit ev: Err <:< Response): ZIO[Env, Nothing, Response] = - toHandler(ev)(request) - - /** - * Returns new routes that automatically translate all failures into - * responses, using best-effort heuristics to determine the appropriate HTTP - * status code, and attaching error details using the HTTP header `Warning`. - */ - def sandbox(implicit trace: Trace): HttpApp[Env, Nothing] = - HttpApp(routes.map(_.sandbox)) + def runZIO(request: Request): ZIO[Env, Nothing, Response] = + toHandler(request) /** * Returns a new HTTP application whose requests will be timed out after the * specified duration elapses. */ - def timeout(duration: Duration)(implicit trace: Trace): HttpApp[Env, Err] = + def timeout(duration: Duration)(implicit trace: Trace): HttpApp[Env] = self @@ Middleware.timeout(duration) /** * Converts the HTTP application into a request handler. */ - def toHandler(implicit ev: Err <:< Response): Handler[Env, Nothing, Request, Response] = { + val toHandler: Handler[Env, Nothing, Request, Response] = { implicit val trace: Trace = Trace.empty Handler .fromFunctionHandler[Request] { req => @@ -247,44 +113,24 @@ final case class HttpApp[-Env, +Err](routes: Chunk[zio.http.Route[Env, Err]]) .merge } - /** - * Returns new new HttpApp whose handlers are transformed by the specified - * function. - */ - def transform[Env1]( - f: Handler[Env, Response, Request, Response] => Handler[Env1, Response, Request, Response], - ): HttpApp[Env1, Err] = - new HttpApp(routes.map(_.transform(f))) - /** * Accesses the underlying tree that provides fast dispatch to handlers. */ - def tree(implicit trace: Trace, ev: Err <:< Response): HttpApp.Tree[Env] = { + def tree(implicit trace: Trace): HttpApp.Tree[Env] = { if (_tree eq null) { - _tree = HttpApp.Tree.fromRoutes(routes.asInstanceOf[Chunk[Route[Env, Response]]]) + _tree = HttpApp.Tree.fromRoutes(routes) } + _tree.asInstanceOf[HttpApp.Tree[Env]] } } - -object HttpApp extends HttpAppVersionSpecific { +object HttpApp { /** * An HTTP application that does not handle any routes. */ - val empty: HttpApp[Any, Nothing] = HttpApp(Routes.empty) - - def apply[Env, Err](route: Route[Env, Err], routes: Route[Env, Err]*): HttpApp[Env, Err] = - HttpApp(Chunk.fromIterable(route +: routes)) - - def apply[Env, Err](routes: Routes[Env, Err]): HttpApp[Env, Err] = - HttpApp(routes.routes) - - def fromIterable[Env, Err](routes: Iterable[Route[Env, Err]]): HttpApp[Env, Err] = - HttpApp(Chunk.fromIterable(routes)) - - def singleton[Env, Err](h: Handler[Env, Err, (Path, Request), Response])(implicit trace: Trace): HttpApp[Env, Err] = - HttpApp(Route.route(RoutePattern.any)(h)) + @deprecated("Use Routes.empty instead. Will be removed in the next release.") + val empty: HttpApp[Any] = HttpApp(Routes.empty) private[http] final case class Tree[-Env](tree: RoutePattern.Tree[RequestHandler[Env, Response]]) { self => final def ++[Env1 <: Env](that: Tree[Env1]): Tree[Env1] = @@ -302,7 +148,7 @@ object HttpApp extends HttpAppVersionSpecific { private[http] object Tree { val empty: Tree[Any] = Tree(RoutePattern.Tree.empty) - def fromRoutes[Env](routes: Chunk[zio.http.Route[Env, Response]])(implicit trace: Trace): Tree[Env] = - empty.addAll(routes) + def fromRoutes[Env](routes: Routes[Env, Response])(implicit trace: Trace): Tree[Env] = + empty.addAll(routes.routes) } } diff --git a/zio-http/shared/src/main/scala/zio/http/Middleware.scala b/zio-http/shared/src/main/scala/zio/http/Middleware.scala index c0c0803cb6..a84f7b8644 100644 --- a/zio-http/shared/src/main/scala/zio/http/Middleware.scala +++ b/zio-http/shared/src/main/scala/zio/http/Middleware.scala @@ -24,12 +24,8 @@ import zio.http.codec.{PathCodec, SegmentCodec} import zio.http.endpoint.EndpointMiddleware.None.Err trait Middleware[-UpperEnv] { self => - def apply[Env1 <: UpperEnv, Err]( - routes: Routes[Env1, Err], - ): Routes[Env1, Err] - def apply[Env1 <: UpperEnv, Err](app: HttpApp[Env1, Err]): HttpApp[Env1, Err] = - HttpApp(self(Routes.fromIterable(app.routes))) + def apply[Env1 <: UpperEnv, Err](app: Routes[Env1, Err]): Routes[Env1, Err] def @@[UpperEnv1 <: UpperEnv]( that: Middleware[UpperEnv1], @@ -348,11 +344,11 @@ object Middleware extends HandlerAspects { acc || stop } - override def apply[Env1 <: Any, Err](routes: HttpApp[Env1, Err]): HttpApp[Env1, Err] = { + override def apply[Env1 <: Any, Err](routes: Routes[Env1, Err]): Routes[Env1, Err] = { val mountpoint = Method.GET / path.segments.map(PathCodec.literal).reduceLeftOption(_ / _).getOrElse(PathCodec.empty) val pattern = mountpoint / trailing - val other = HttpApp( + val other = Routes( pattern -> Handler .identity[Request] .flatMap { request => @@ -372,8 +368,6 @@ object Middleware extends HandlerAspects { routes ++ other } - override def apply[Env1 <: Any, Err](routes: Routes[Env1, Err]): Routes[Env1, Err] = - Routes.fromIterable(apply(HttpApp(routes)).routes) } /** diff --git a/zio-http/shared/src/main/scala/zio/http/Route.scala b/zio-http/shared/src/main/scala/zio/http/Route.scala index 5946fe05d6..fc25ba3c95 100644 --- a/zio-http/shared/src/main/scala/zio/http/Route.scala +++ b/zio-http/shared/src/main/scala/zio/http/Route.scala @@ -284,7 +284,7 @@ sealed trait Route[-Env, +Err] { self => * the request, or else this method will fail fatally. */ final def run(request: Request)(implicit trace: Trace): ZIO[Env, Either[Err, Response], Response] = - HttpApp(self).run(request) + Routes(self).run(request) /** * Returns a route that automatically translates all failures into responses, @@ -296,7 +296,10 @@ sealed trait Route[-Env, +Err] { self => def toHandler(implicit ev: Err <:< Response, trace: Trace): Handler[Env, Response, Request, Response] - final def toHttpApp: HttpApp[Env, Err] = HttpApp(self) + @deprecated("Use toRoutes instead") + final def toHttpApp(implicit ev: Err <:< Response): HttpApp[Env] = toHandler.toHttpApp + + final def toRoutes: Routes[Env, Err] = Routes(self) def transform[Env1]( f: Handler[Env, Response, Request, Response] => Handler[Env1, Response, Request, Response], diff --git a/zio-http/shared/src/main/scala/zio/http/Routes.scala b/zio-http/shared/src/main/scala/zio/http/Routes.scala index 7cef1197e6..f18d794e8d 100644 --- a/zio-http/shared/src/main/scala/zio/http/Routes.scala +++ b/zio-http/shared/src/main/scala/zio/http/Routes.scala @@ -13,48 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package zio.http import zio._ - import zio.http.Routes.ApplyContextAspect import zio.http.codec.PathCodec /** - * Represents a collection of routes, each of which is defined by a pattern and - * a handler. This data type can be thought of as modeling a routing table, - * which decides where to direct every endpoint in an API based on both method - * and path of the request. + * An HTTP application is a collection of routes, all of whose errors have been + * handled through conversion into HTTP responses. * - * When you are done building a collection of routes, you typically convert the - * routes into an [[zio.http.HttpApp]] value, which can be done with the - * `toHttpApp` method. - * - * Routes may have handled or unhandled errors. A route of type `Route[Env, - * Throwable]`, for example, has not handled its errors by converting them into - * responses. Such unfinished routes cannot yet be converted into - * [[zio.http.HttpApp]] values. First, you must handle errors with the - * `handleError` or `handleErrorCause` methods. + * HTTP applications can be installed into a [[zio.http.Server]], which is + * capable of using them to serve requests. */ -final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Err]]) { self => - - /** - * Returns the concatenation of these routes with the specified routes. - */ - def ++[Env1 <: Env, Err1 >: Err](that: Routes[Env1, Err1]): Routes[Env1, Err1] = - new Routes(self.routes ++ that.routes) - - /** - * Appends the specified route to this collection of routes. - */ - def :+[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): Routes[Env1, Err1] = - new Routes(routes :+ route) - - /** - * Prepends the specified route to this collection of routes. - */ - def +:[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): Routes[Env1, Err1] = - new Routes(route +: routes) +final case class Routes[-Env, +Err](routes: Chunk[zio.http.Route[Env, Err]]) { self => + private var _tree: Routes.Tree[_] = null.asInstanceOf[Routes.Tree[_]] def @@[Env1 <: Env](aspect: Middleware[Env1]): Routes[Env1, Err] = aspect(self) @@ -70,14 +44,32 @@ final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Er def @@[Env0]: ApplyContextAspect[Env, Err, Env0] = new ApplyContextAspect[Env, Err, Env0](self) - def apply(request: Request)(implicit ev: Err <:< Response, trace: Trace): ZIO[Env, Response, Response] = - self.toHttpApp.apply(request) + /** + * Combines this HTTP application with the specified HTTP application. In case + * of route conflicts, the routes in this HTTP application take precedence + * over the routes in the specified HTTP application. + */ + def ++[Env1 <: Env, Err1 >: Err](that: Routes[Env1, Err1]): Routes[Env1, Err1] = + copy(routes = routes ++ that.routes) + + /** + * Prepend the specified route to this HttpApp + */ + def +:[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): Routes[Env1, Err1] = + copy(routes = route +: routes) - def asEnvType[Env2](implicit ev: Env2 <:< Env): Routes[Env2, Err] = - self.asInstanceOf[Routes[Env2, Err]] + /** + * Appends the specified route to this HttpApp + */ + def :+[Env1 <: Env, Err1 >: Err](route: zio.http.Route[Env1, Err1]): Routes[Env1, Err1] = + copy(routes = routes :+ route) - def asErrorType[Err2](implicit ev: Err <:< Err2): Routes[Env, Err2] = - self.asInstanceOf[Routes[Env, Err2]] + /** + * Executes the HTTP application with the specified request input, returning + * an effect that will either succeed or fail with a Response. + */ + def apply(request: Request)(implicit ev: Err <:< Response): ZIO[Env, Response, Response] = + runZIO(request) /** * Handles all typed errors in the routes by converting them into responses. @@ -109,14 +101,14 @@ final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Er /** * Allows the transformation of the Err type through an Effectful program - * allowing one to build up a Routes in Stages delegates to the Route + * allowing one to build up a HttpApp in Stages delegates to the Route */ def mapErrorZIO[Err1](fxn: Err => ZIO[Any, Err1, Response])(implicit trace: Trace): Routes[Env, Err1] = new Routes(routes.map(_.mapErrorZIO(fxn))) /** * Allows the transformation of the Err type through a function allowing one - * to build up a Routes in Stages delegates to the Route + * to build up a HttpApp in Stages delegates to the Route */ def mapError[Err1](fxn: Err => Err1): Routes[Env, Err1] = new Routes(routes.map(_.mapError(fxn))) @@ -155,11 +147,21 @@ final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Er new Routes(routes.map(_.handleErrorRequestCauseZIO(f))) /** - * Returns new routes that have each been provided the specified environment, - * thus eliminating their requirement for any specific environment. + * Checks to see if the HTTP application may be defined at the specified + * request input. Note that it is still possible for an HTTP application to + * return a 404 Not Found response, which cannot be detected by this method. + * This method only checks for the presence of a handler that handles the + * method and path of the specified request. + */ + def isDefinedAt(request: Request)(implicit ev: Err <:< Response): Boolean = + tree(Trace.empty, ev).get(request.method, request.path).nonEmpty + + /** + * Provides the specified environment to the HTTP application, returning a new + * HTTP application that has no environmental requirements. */ def provideEnvironment(env: ZEnvironment[Env]): Routes[Any, Err] = - new Routes(routes.map(_.provideEnvironment(env))) + copy(routes = routes.map(_.provideEnvironment(env))) def run(request: Request)(implicit trace: Trace): ZIO[Env, Either[Err, Response], Response] = { @@ -190,63 +192,112 @@ final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Er } } + def run( + method: Method = Method.GET, + path: Path = Path.root, + headers: Headers = Headers.empty, + body: Body = Body.empty, + )(implicit ev: Err <:< Response): ZIO[Env, Nothing, Response] = + runZIO(Request(method = method, url = URL.root.path(path), headers = headers, body = body)) + + /** + * An alias for `apply`. + */ + def runZIO(request: Request)(implicit ev: Err <:< Response): ZIO[Env, Nothing, Response] = + toHandler(ev)(request) + /** * Returns new routes that automatically translate all failures into * responses, using best-effort heuristics to determine the appropriate HTTP * status code, and attaching error details using the HTTP header `Warning`. */ def sandbox(implicit trace: Trace): Routes[Env, Nothing] = - new Routes(routes.map(_.sandbox)) + Routes(routes.map(_.sandbox)) /** - * Returns new routes that are all timed out by the specified maximum - * duration. + * Returns a new HTTP application whose requests will be timed out after the + * specified duration elapses. */ def timeout(duration: Duration)(implicit trace: Trace): Routes[Env, Err] = self @@ Middleware.timeout(duration) /** - * Converts the routes into an app, which can be done only when errors are - * handled and converted into responses. + * Converts the HTTP application into a request handler. */ - def toHttpApp: HttpApp[Env, Err] = - HttpApp(self) + def toHandler(implicit ev: Err <:< Response): Handler[Env, Nothing, Request, Response] = { + implicit val trace: Trace = Trace.empty + Handler + .fromFunctionHandler[Request] { req => + val chunk = tree.get(req.method, req.path) + + if (chunk.length == 0) Handler.notFound + else if (chunk.length == 1) chunk(0) + else { + // TODO: Support precomputed fallback among all chunk elements: + chunk.tail.foldLeft(chunk.head) { (acc, h) => + acc.catchAll { response => + if (response.status == Status.NotFound) h + else Handler.fail(response) + } + } + } + } + .merge + } /** - * Returns new routes whose handlers are transformed by the specified + * Returns new new HttpApp whose handlers are transformed by the specified * function. */ def transform[Env1]( f: Handler[Env, Response, Request, Response] => Handler[Env1, Response, Request, Response], ): Routes[Env1, Err] = new Routes(routes.map(_.transform(f))) -} -object Routes extends RoutesVersionSpecific { /** - * Constructs new routes from a varargs of individual routes. + * Accesses the underlying tree that provides fast dispatch to handlers. */ - @deprecated("Use HttpApp.apply instead. Will be removed in the next release.") - def apply[Env, Err](route: zio.http.Route[Env, Err], routes: zio.http.Route[Env, Err]*): Routes[Env, Err] = - new Routes(Chunk(route) ++ Chunk.fromIterable(routes)) + def tree(implicit trace: Trace, ev: Err <:< Response): Routes.Tree[Env] = { + if (_tree eq null) { + _tree = Routes.Tree.fromRoutes(routes.asInstanceOf[Chunk[Route[Env, Response]]]) + } + _tree.asInstanceOf[Routes.Tree[Env]] + } +} - /** - * A empty routes value that contains no routes inside it. - */ - val empty: Routes[Any, Nothing] = new Routes(Chunk.empty) +object Routes extends RoutesVersionSpecific { /** - * Constructs new routes from an iterable of individual routes. + * An HTTP application that does not handle any routes. */ - @deprecated("Use HttpApp.fromIterable instead. Will be removed in the next release.") - def fromIterable[Env, Err](iterable: Iterable[Route[Env, Err]]): Routes[Env, Err] = - new Routes(Chunk.fromIterable(iterable)) + val empty: Routes[Any, Nothing] = Routes(Chunk.empty) + + def apply[Env, Err](route: Route[Env, Err], routes: Route[Env, Err]*): Routes[Env, Err] = + Routes(Chunk.fromIterable(route +: routes)) + + def fromIterable[Env, Err](routes: Iterable[Route[Env, Err]]): Routes[Env, Err] = + Routes(Chunk.fromIterable(routes)) - /** - * Constructs a singleton route from a handler that handles all possible - * methods and paths. You would only use this method for testing. - */ - @deprecated("Use HttpApp.singleton instead. Will be removed in the next release.") def singleton[Env, Err](h: Handler[Env, Err, (Path, Request), Response])(implicit trace: Trace): Routes[Env, Err] = Routes(Route.route(RoutePattern.any)(h)) + + private[http] final case class Tree[-Env](tree: RoutePattern.Tree[RequestHandler[Env, Response]]) { self => + final def ++[Env1 <: Env](that: Tree[Env1]): Tree[Env1] = + Tree(self.tree ++ that.tree) + + final def add[Env1 <: Env](route: Route[Env1, Response])(implicit trace: Trace): Tree[Env1] = + Tree(self.tree.add(route.routePattern, route.toHandler)) + + final def addAll[Env1 <: Env](routes: Iterable[Route[Env1, Response]])(implicit trace: Trace): Tree[Env1] = + Tree(self.tree.addAll(routes.map(r => (r.routePattern, r.toHandler)))) + + final def get(method: Method, path: Path): Chunk[RequestHandler[Env, Response]] = + tree.get(method, path) + } + private[http] object Tree { + val empty: Tree[Any] = Tree(RoutePattern.Tree.empty) + + def fromRoutes[Env](routes: Chunk[zio.http.Route[Env, Response]])(implicit trace: Trace): Tree[Env] = + empty.addAll(routes) + } } diff --git a/zio-http/shared/src/main/scala/zio/http/Server.scala b/zio-http/shared/src/main/scala/zio/http/Server.scala index 18f201faae..4d52e9b235 100644 --- a/zio-http/shared/src/main/scala/zio/http/Server.scala +++ b/zio-http/shared/src/main/scala/zio/http/Server.scala @@ -33,7 +33,14 @@ trait Server { /** * Installs the given HTTP application into the server. */ - def install[R](httpApp: HttpApp[R, Response])(implicit trace: Trace): URIO[R, Unit] + @deprecated("Install Routes instead. Will be removed in the next release.") + def install[R](httpApp: HttpApp[R])(implicit trace: Trace): URIO[R, Unit] = + install(httpApp.routes) + + /** + * Installs the given HTTP application into the server. + */ + def install[R](httpApp: Routes[R, Response])(implicit trace: Trace): URIO[R, Unit] /** * The port on which the server is listening. @@ -329,8 +336,10 @@ object Server extends ServerPlatformSpecific { } } + + @deprecated("Serve Routes instead. Will be removed in the next release.") def serve[R]( - httpApp: HttpApp[R, Response], + httpApp: HttpApp[R], )(implicit trace: Trace): URIO[R with Server, Nothing] = { ZIO.logInfo("Starting the server...") *> install(httpApp) *> @@ -338,7 +347,21 @@ object Server extends ServerPlatformSpecific { ZIO.never } - def install[R](httpApp: HttpApp[R, Response])(implicit trace: Trace): URIO[R with Server, Int] = { + @deprecated("Install Routes instead. Will be removed in the next release.") + def install[R](httpApp: HttpApp[R])(implicit trace: Trace): URIO[R with Server, Int] = { + ZIO.serviceWithZIO[Server](_.install(httpApp)) *> ZIO.service[Server].map(_.port) + } + + def serve[R]( + httpApp: Routes[R, Response], + )(implicit trace: Trace): URIO[R with Server, Nothing] = { + ZIO.logInfo("Starting the server...") *> + install(httpApp) *> + ZIO.logInfo("Server started") *> + ZIO.never + } + + def install[R](httpApp: Routes[R, Response])(implicit trace: Trace): URIO[R with Server, Int] = { ZIO.serviceWithZIO[Server](_.install(httpApp)) *> ZIO.service[Server].map(_.port) } @@ -392,11 +415,12 @@ object Server extends ServerPlatformSpecific { driver: Driver, bindPort: Int, ) extends Server { - override def install[R](httpApp: HttpApp[R, Response])(implicit + override def install[R](httpApp: Routes[R, Response])(implicit trace: Trace, ): URIO[R, Unit] = ZIO.environment[R].flatMap(driver.addApp(httpApp, _)) override def port: Int = bindPort + } } diff --git a/zio-http/shared/src/main/scala/zio/http/Status.scala b/zio-http/shared/src/main/scala/zio/http/Status.scala index 089af773b9..1727675239 100644 --- a/zio-http/shared/src/main/scala/zio/http/Status.scala +++ b/zio-http/shared/src/main/scala/zio/http/Status.scala @@ -40,9 +40,10 @@ sealed trait Status extends Product with Serializable { self => lazy val text: String = code.toString /** - * Returns an HttpApp[Any, Nothing] that responses with this http status code. + * Returns an Routes[Any, Nothing] that responses with this http status code. */ - def toHttpApp(implicit trace: Trace): Handler[Any, Nothing, Any, Response] = Handler.status(self) + def toRoutes(implicit trace: Trace): Routes[Any, Nothing] = + Handler.status(self).toRoutes /** * Returns a Response with empty data and no headers. diff --git a/zio-http/shared/src/main/scala/zio/http/WebSocketApp.scala b/zio-http/shared/src/main/scala/zio/http/WebSocketApp.scala index abc784ff41..199cd592ee 100644 --- a/zio-http/shared/src/main/scala/zio/http/WebSocketApp.scala +++ b/zio-http/shared/src/main/scala/zio/http/WebSocketApp.scala @@ -72,9 +72,13 @@ final case class WebSocketApp[-R]( Response.fromSocketApp(self.provideEnvironment(env)) } - def toHttpAppWS(implicit trace: Trace): HttpApp[R, Response] = + @deprecated("Use toRoutes. Will be removed in the next release.") + def toHttpAppWS(implicit trace: Trace): HttpApp[R] = Handler.fromZIO(self.toResponse).toHttpApp + def toRoutes(implicit trace: Trace): Routes[R, Response] = + Handler.fromZIO(self.toResponse).toRoutes + def withConfig(config: WebSocketConfig): WebSocketApp[R] = copy(customConfig = Some(config)) } diff --git a/zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala b/zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala index ed7ced7ad1..a268b3eb2d 100644 --- a/zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala +++ b/zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala @@ -49,9 +49,9 @@ sealed trait PathCodec[A] { self => final def /[B](that: PathCodec[B])(implicit combiner: Combiner[A, B]): PathCodec[combiner.Out] = self ++ that - final def /[Env](routes: HttpApp[Env, Response])(implicit + final def /[Env](routes: Routes[Env, Response])(implicit ev: PathCodec[A] <:< PathCodec[Unit], - ): HttpApp[Env, Response] = + ): Routes[Env, Response] = routes.nest(ev(self)) final def annotate(metaData: MetaData[A]): PathCodec[A] = { diff --git a/zio-http/shared/src/main/scala/zio/http/endpoint/openapi/SwaggerUI.scala b/zio-http/shared/src/main/scala/zio/http/endpoint/openapi/SwaggerUI.scala index bc10d1c36d..3ffe3c8a61 100644 --- a/zio-http/shared/src/main/scala/zio/http/endpoint/openapi/SwaggerUI.scala +++ b/zio-http/shared/src/main/scala/zio/http/endpoint/openapi/SwaggerUI.scala @@ -28,33 +28,10 @@ object SwaggerUI { * of the OpenAPI specification and is url encoded. */ //format: on - @deprecated("Use app instead. Will be removed with the next release.") def routes(path: PathCodec[Unit], api: OpenAPI, apis: OpenAPI*): Routes[Any, Response] = { routes(path, DefaultSwaggerUIVersion, api, apis: _*) } - /** - * Creates routes for serving the Swagger UI at the given path. - * - * Example: - * {{{ - * val routes: Routes[Any, Response] = ??? - * val openAPIv1: OpenAPI = ??? - * val openAPIv2: OpenAPI = ??? - * val swaggerUIRoutes = SwaggerUI.routes("docs" / "openapi", openAPIv1, openAPIv2) - * val routesWithSwagger = routes ++ swaggerUIRoutes - * }}} - * - * With this middleware in place, a request to `https://www.domain.com/[path]` - * would serve the Swagger UI. The different OpenAPI specifications are served - * at `https://www.domain.com/[path]/[title].json`. Where `title` is the title - * of the OpenAPI specification and is url encoded. - */ - // format: on - def app(path: PathCodec[Unit], api: OpenAPI, apis: OpenAPI*): HttpApp[Any, Response] = { - app(path, DefaultSwaggerUIVersion, api, apis: _*) - } - //format: off /** * Creates a middleware for serving the Swagger UI at the given path and with @@ -75,7 +52,6 @@ object SwaggerUI { * of the OpenAPI specification and is url encoded. */ //format: on - @deprecated("Use app instead. Will be removed with the next release.") def routes(path: PathCodec[Unit], version: String, api: OpenAPI, apis: OpenAPI*): Routes[Any, Response] = { import zio.http.template._ val basePath = Method.GET / path @@ -126,72 +102,4 @@ object SwaggerUI { Routes.fromIterable(jsonRoutes) :+ uiRoute } - /** - * Creates a middleware for serving the Swagger UI at the given path and with - * the given swagger ui version. - * - * Example: - * {{{ - * val routes: Routes[Any, Response] = ??? - * val openAPIv1: OpenAPI = ??? - * val openAPIv2: OpenAPI = ??? - * val swaggerUIRoutes = SwaggerUI.routes("docs" / "openapi", openAPIv1, openAPIv2) - * val routesWithSwagger = routes ++ swaggerUIRoutes - * }}} - * - * With this middleware in place, a request to `https://www.domain.com/[path]` - * would serve the Swagger UI. The different OpenAPI specifications are served - * at `https://www.domain.com/[path]/[title].json`. Where `title` is the title - * of the OpenAPI specification and is url encoded. - */ - // format: on - def app(path: PathCodec[Unit], version: String, api: OpenAPI, apis: OpenAPI*): HttpApp[Any, Response] = { - import zio.http.template._ - val basePath = Method.GET / path - val jsonRoutes = (api +: apis).map { api => - basePath / s"${URLEncoder.encode(api.info.title, Charsets.Utf8.name())}.json" -> handler { (_: Request) => - Response.json(api.toJson) - } - } - val jsonPaths = jsonRoutes.map(_.routePattern.pathCodec.render) - val jsonTitles = (api +: apis).map(_.info.title) - val jsonUrls = jsonTitles.zip(jsonPaths).map { case (title, path) => s"""{url: "$path", name: "$title"}""" } - val uiRoute = basePath -> handler { (_: Request) => - Response.html( - html( - head( - meta(charsetAttr := "utf-8"), - meta(nameAttr := "viewport", contentAttr := "width=device-width, initial-scale=1"), - meta(nameAttr := "description", contentAttr := "SwaggerUI"), - title("SwaggerUI"), - link(relAttr := "stylesheet", href := s"https://unpkg.com/swagger-ui-dist@$version/swagger-ui.css"), - link( - relAttr := "icon", - typeAttr := "image/png", - href := s"https://unpkg.com/swagger-ui-dist@$version/favicon-32x32.png", - ), - ), - body( - div(id := "swagger-ui"), - script(srcAttr := s"https://unpkg.com/swagger-ui-dist@$version/swagger-ui-bundle.js"), - script(srcAttr := s"https://unpkg.com/swagger-ui-dist@$version/swagger-ui-standalone-preset.js"), - Dom.raw(s"""""".stripMargin), - ), - ), - ) - } - HttpApp.fromIterable(jsonRoutes) :+ uiRoute - } } diff --git a/zio-http/shared/src/main/scala/zio/http/multipart/mixed/MultipartMixed.scala b/zio-http/shared/src/main/scala/zio/http/multipart/mixed/MultipartMixed.scala index 6752b70665..a96e2dbe4d 100644 --- a/zio-http/shared/src/main/scala/zio/http/multipart/mixed/MultipartMixed.scala +++ b/zio-http/shared/src/main/scala/zio/http/multipart/mixed/MultipartMixed.scala @@ -75,15 +75,15 @@ object MultipartMixed { ZChannel .readWithCause( in => preamble(keep ++ in), - ZChannel.refailCause(_), - done => + ZChannel.refailCause, + _ => if (boundary.isClosing(buff)) ZChannel.succeed((Chunk.empty, true)) else if (boundary.isEncapsulating(buff)) ZChannel.succeed((Chunk.empty, false)) else ZChannel.fail(new IllegalStateException("multipart/chunked body ended with no boundary")), - ) + ) case idx => val h = buff.take(idx) val rest = buff.drop(idx + crlf.size) @@ -161,7 +161,7 @@ object MultipartMixed { .readWithCause( in => parseBodyAux(buff, pendingCrlf, currLine ++ in, true), err => ZChannel.write(buff) *> ZChannel.refailCause(err), - done => { + _ => { // still possible that the current line is encapsulating or closing boundary if (boundary.isClosing(currLine)) ZChannel.write(buff) *> ZChannel.succeed((Chunk.empty, true)) @@ -172,22 +172,22 @@ object MultipartMixed { new IllegalStateException("multipart/chunked body ended with no boundary"), ) }, - ) + ) } else { // we're no longer at beginning of a line, hence no need to look for boundary until we encounter a new line val (h, t) = currLine.splitAt(currLine.size - crlf.size + 1) if (t != currLine) { // also if we had a pending crlf we now know it's part of the content so we move it to the buffered part - parseBody(buff ++ pendingCrlf ++ h, Chunk.empty, t, false) + parseBody(buff ++ pendingCrlf ++ h, Chunk.empty, t, seekingBoundary = false) } else { ZChannel.readWithCause( - in => parseBodyAux(buff ++ pendingCrlf ++ h, Chunk.empty, t ++ in, false), + in => parseBodyAux(buff ++ pendingCrlf ++ h, Chunk.empty, t ++ in, seekingBoundary = false), err => ZChannel.write(buff ++ crlf ++ currLine) *> ZChannel.refailCause(err), - done => + _ => ZChannel.write(buff ++ crlf ++ currLine) *> ZChannel.fail( new IllegalStateException("multipart/chunked body ended with no boundary"), ), - ) + ) } } case idx if seekingBoundary => // potential boundary @@ -200,12 +200,12 @@ object MultipartMixed { else { // the crlf we just found can either be part of a following boundary or part of the content val nextLine = rest.drop(crlf.size) - parseBody(buff ++ pendingCrlf ++ h, crlf, nextLine, true) + parseBody(buff ++ pendingCrlf ++ h, crlf, nextLine, seekingBoundary = true) } case idx => // plain content // no need to check for boundary, just buffer and continue with parseBOL val (h, t) = currLine.splitAt(idx) - parseBody(buff ++ h, crlf, t.drop(crlf.size), true) + parseBody(buff ++ h, crlf, t.drop(crlf.size), seekingBoundary = true) } } } @@ -247,7 +247,7 @@ object MultipartMixed { ZChannel .fromZIO(pr.await) .flatMap { - case (rest, true) => + case (_, true) => epilogue case (rest, false) => cont(rest) @@ -267,7 +267,7 @@ object MultipartMixed { case (_, true) => epilogue } - .mapOut(Chunk.single(_)) + .mapOut(Chunk.single) val startPl: ZPipeline[Any, Throwable, Byte, Part] = startCh.toPipeline val result: ZStream[Any, Throwable, Part] = upstream.toStream >>> startPl @@ -301,9 +301,4 @@ object MultipartMixed { MultipartMixed(bytes, boundary, bufferSize) } - def fromPartsUUID(parts: ZStream[Any, Throwable, Part], bufferSize: Int = 8192): ZIO[Any, Nothing, MultipartMixed] = { - Boundary.randomUUID - .map(fromParts(parts, _, bufferSize)) - } - }