Skip to content

Commit

Permalink
migrate into main
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil committed Aug 4, 2023
1 parent 212f9ff commit f1516a1
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 45 deletions.
26 changes: 12 additions & 14 deletions zio-http/src/main/scala/zio/http/codec/internal/BodyCodec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@

package zio.http.codec.internal

import zio._
import zio.stacktracer.TracingImplicits.disableAutoTrace

import zio.stream.ZStream

import zio.http.{Body, MediaType}
import java.nio.charset.Charset

import zio._
import zio.stacktracer.TracingImplicits.disableAutoTrace

import zio.stream.{ZPipeline, ZStream}

Expand Down Expand Up @@ -54,7 +49,7 @@ private[internal] sealed trait BodyCodec[A] { self =>
/**
* Attempts to decode the `A` from a body using the given codec.
*/
def decodeFromBody(body: Body, codec: Codec[String, Char, Element]): IO[Throwable, A]
def decodeFromBody(body: Body, codec: Codec[String, Char, Element])(implicit trace: Trace): IO[Throwable, A]

/**
* Encodes the `A` to a body in the given codec.
Expand All @@ -64,7 +59,7 @@ private[internal] sealed trait BodyCodec[A] { self =>
/**
* Encodes the `A` to a body in the given codec.
*/
def encodeToBody(value: A, codec: Codec[String, Char, Element]): Body
def encodeToBody(value: A, codec: Codec[String, Char, Element])(implicit trace: Trace): Body

/**
* Erases the type for easier use in the internal implementation.
Expand Down Expand Up @@ -98,11 +93,12 @@ private[internal] object BodyCodec {

def decodeFromBody(body: Body, codec: BinaryCodec[Unit])(implicit trace: Trace): IO[Nothing, Unit] = ZIO.unit

def decodeFromBody(body: Body, codec: Codec[String, Char, Unit]): IO[Nothing, Unit] = ZIO.unit
def decodeFromBody(body: Body, codec: Codec[String, Char, Unit])(implicit trace: Trace): IO[Nothing, Unit] =
ZIO.unit

def encodeToBody(value: Unit, codec: BinaryCodec[Unit])(implicit trace: Trace): Body = Body.empty

def encodeToBody(value: Unit, codec: Codec[String, Char, Unit]): Body = Body.empty
def encodeToBody(value: Unit, codec: Codec[String, Char, Unit])(implicit trace: Trace): Body = Body.empty

def schema: Schema[Unit] = Schema[Unit]

Expand All @@ -118,14 +114,14 @@ private[internal] object BodyCodec {
else body.asChunk.flatMap(chunk => ZIO.fromEither(codec.decode(chunk)))
}

def decodeFromBody(body: Body, codec: Codec[String, Char, A]): IO[Throwable, A] =
def decodeFromBody(body: Body, codec: Codec[String, Char, A])(implicit trace: Trace): IO[Throwable, A] =
if (schema == Schema[Unit]) ZIO.unit.asInstanceOf[IO[Throwable, A]]
else body.asString.flatMap(chunk => ZIO.fromEither(codec.decode(chunk)))

def encodeToBody(value: A, codec: BinaryCodec[A])(implicit trace: Trace): Body =
Body.fromChunk(codec.encode(value))

def encodeToBody(value: A, codec: Codec[String, Char, A]): Body =
def encodeToBody(value: A, codec: Codec[String, Char, A])(implicit trace: Trace): Body =
Body.fromString(codec.encode(value))

type Element = A
Expand All @@ -138,13 +134,15 @@ private[internal] object BodyCodec {
): IO[Throwable, ZStream[Any, Nothing, E]] =
ZIO.succeed((body.asStream >>> codec.streamDecoder).orDie)

def decodeFromBody(body: Body, codec: Codec[String, Char, E]): IO[Throwable, ZStream[Any, Nothing, E]] =
def decodeFromBody(body: Body, codec: Codec[String, Char, E])(implicit
trace: Trace,
): IO[Throwable, ZStream[Any, Nothing, E]] =
ZIO.succeed((body.asStream >>> ZPipeline.decodeCharsWith(Charset.defaultCharset()) >>> codec.streamDecoder).orDie)

def encodeToBody(value: ZStream[Any, Nothing, E], codec: BinaryCodec[E])(implicit trace: Trace): Body =
Body.fromStream(value >>> codec.streamEncoder)

def encodeToBody(value: ZStream[Any, Nothing, E], codec: Codec[String, Char, E]): Body =
def encodeToBody(value: ZStream[Any, Nothing, E], codec: Codec[String, Char, E])(implicit trace: Trace): Body =
Body.fromStream(value >>> codec.streamEncoder.map(_.toByte))

type Element = E
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,10 @@
package zio.http.codec.internal

import zio._

import zio.stacktracer.TracingImplicits.disableAutoTrace

import zio.stream.ZStream

import zio.schema.codec._
import zio.schema.{Schema, StandardType}

import zio.stream.ZStream
import zio.stream.ZStream
import zio.schema.Schema
import zio.schema.codec.{BinaryCodec, Codec}

import zio.stream.ZStream
import zio.schema.Schema
import zio.schema.codec.{BinaryCodec, Codec}

Expand Down
18 changes: 13 additions & 5 deletions zio-http/src/main/scala/zio/http/endpoint/Endpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import zio.stream.ZStream

import zio.schema._

import zio.http.codec._
import zio.http.endpoint.Endpoint.OutErrors
import zio.http.{Handler, MediaType, Route, RoutePattern, Status}
import zio.http.Header.Accept.MediaTypeWithQFactor
import zio.http._
import zio.http.codec.{HttpCodec, _}
import zio.http.endpoint.Endpoint.{OutErrors, defaultMediaTypes}

/**
* An [[zio.http.endpoint.Endpoint]] represents an API endpoint for the HTTP
Expand Down Expand Up @@ -150,9 +151,13 @@ final case class Endpoint[PathInput, Input, Err, Output, Middleware <: EndpointM

val handlers = self.alternatives.map { endpoint =>
Handler.fromFunctionZIO { (request: zio.http.Request) =>
val outputMediaTypes = request.headers
.get(Header.Accept)
.map(_.mimeTypes)
.getOrElse(defaultMediaTypes)
endpoint.input.decodeRequest(request).orDie.flatMap { value =>
original(value).map(endpoint.output.encodeResponse(_)).catchAll { error =>
ZIO.succeed(endpoint.error.encodeResponse(error))
original(value).map(endpoint.output.encodeResponse(_, outputMediaTypes)).catchAll { error =>
ZIO.succeed(endpoint.error.encodeResponse(error, outputMediaTypes))
}
}
}
Expand Down Expand Up @@ -691,4 +696,7 @@ object Endpoint {
self.copy[PathInput, Input, alt.Out, Output, Middleware](error = self.error | codec)
}
}

private[endpoint] val defaultMediaTypes =
NonEmptyChunk(MediaTypeWithQFactor(MediaType.application.`json`, Some(1)))
}
24 changes: 18 additions & 6 deletions zio-http/src/main/scala/zio/http/endpoint/EndpointMiddleware.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@

package zio.http.endpoint

import zio.ZIO
import zio.{Chunk, ZIO}

import zio.http.Header.Accept.MediaTypeWithQFactor
import zio.http._
import zio.http.codec._
import zio.http.codec.{HttpCodec, _}

/**
* A description of endpoint middleware, in terms of what the middleware
Expand Down Expand Up @@ -55,14 +56,25 @@ sealed trait EndpointMiddleware { self =>
): HandlerAspect[R, S] =
HandlerAspect.interceptHandlerStateful(
Handler.fromFunctionZIO[Request] { request =>
val outputMediaTypes =
request.headers
.get(Header.Accept)
.map(_.mimeTypes.toChunk)
.getOrElse(Chunk(MediaTypeWithQFactor(MediaType.application.`json`, Some(1.0))))
input.decodeRequest(request).orDie.flatMap { in =>
incoming(in).catchAll(e => ZIO.fail(error.encodeResponse(e))).map((s: S) => (s, (request, s)))
incoming(in)
.catchAll(e => ZIO.fail(error.encodeResponse(e, outputMediaTypes)))
.map((s: S) => ((s, outputMediaTypes), (request, s)))
}
},
)(
Handler.fromFunctionZIO[(S, Response)] { case (state, response) =>
outgoing(state)
.fold(e => error.encodeResponse(e), (out: Out) => response.patch(output.encodeResponsePatch(out)))
Handler.fromFunctionZIO[((S, Chunk[MediaTypeWithQFactor]), Response)] {
case ((state, outputMediaTypes), response) =>
outgoing(state)
.fold(
e => error.encodeResponse(e, outputMediaTypes),
(out: Out) => response.patch(output.encodeResponsePatch(out, outputMediaTypes)),
)
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,20 @@ object EndpointRoundtripSpec extends ZIOSpecDefault {
},
test("simple get with protobuf encoding") {
val usersPostAPI =
Endpoint
.get(literal("users") / int("userId") / literal("posts") / int("postId"))
Endpoint(GET / "users" / int("userId") / "posts" / int("postId"))
.out[Post]
.header(HeaderCodec.accept)

val usersPostHandler =
usersPostAPI.implement { case (userId, postId, _) =>
ZIO.succeed(Post(postId, "title", "body", userId))
usersPostAPI.implement {
Handler.fromFunction { case (userId, postId, _) =>
Post(postId, "title", "body", userId)
}
}

testEndpoint(
usersPostAPI,
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"))
Expand Down Expand Up @@ -196,9 +197,9 @@ object EndpointRoundtripSpec extends ZIOSpecDefault {
},
test("throwing error in handler") {
val api = Endpoint(POST / string("id") / "xyz" / string("name") / "abc")
.query(query("details"))
.query(query("args").optional)
.query(query("env").optional)
.query(QueryCodec.query("details"))
.query(QueryCodec.query("args").optional)
.query(QueryCodec.query("env").optional)
.outError[String](Status.BadRequest)
.out[String] ?? Doc.p("doc")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import zio.http.Header.AccessControlAllowMethods
import zio.http.Middleware.{CorsConfig, cors}
import zio.http._
import zio.http.internal.HttpAppTestExtensions
import zio.http.internal.middlewares.CorsSpec.app
import zio.http.internal.middlewares.Cors.CorsConfig

object CorsSpec extends ZIOSpecDefault with HttpAppTestExtensions {
def extractStatus(response: Response): Status = response.status
Expand Down

0 comments on commit f1516a1

Please sign in to comment.