Skip to content

Commit

Permalink
Ignore empty appending to RoutePattern and render empty as slash (#3110
Browse files Browse the repository at this point in the history
…) (#3121)
  • Loading branch information
987Nabil authored Sep 27, 2024
1 parent f74fd6d commit 5e7f147
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,14 @@ object PathCodecSpec extends ZIOHttpSpec {
test("/users") {
val codec = PathCodec.empty / PathCodec.literal("users")

assertTrue(
codec.segments ==
Chunk(SegmentCodec.empty, SegmentCodec.literal("users")),
)
assertTrue(codec.segments == Chunk(SegmentCodec.literal("users")))
},
),
suite("render")(
test("empty") {
val codec = PathCodec.empty

assertTrue(codec.render == "")
assertTrue(codec.render == "/")
},
test("/users") {
val codec = PathCodec.empty / PathCodec.literal("users")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import zio.schema.{DeriveSchema, Schema}

import zio.http.Method.{GET, POST}
import zio.http._
import zio.http.codec.PathCodec.string
import zio.http.codec.{ContentCodec, Doc, HttpCodec}
import zio.http.codec.PathCodec.{empty, string}
import zio.http.codec._
import zio.http.endpoint._

object OpenAPIGenSpec extends ZIOSpecDefault {
Expand Down Expand Up @@ -211,6 +211,25 @@ object OpenAPIGenSpec extends ZIOSpecDefault {

override def spec: Spec[TestEnvironment with Scope, Any] =
suite("OpenAPIGenSpec")(
test("root endpoint to OpenAPI") {
val rootEndpoint = Endpoint(Method.GET / empty)
val generated = OpenAPIGen.fromEndpoints("Root Endpoint", "1.0", rootEndpoint)
val json = toJsonAst(generated)
val expectedJson = """|{
| "openapi" : "3.1.0",
| "info" : {
| "title" : "Root Endpoint",
| "version" : "1.0"
| },
| "paths" : {
| "/" : {
| "get" : {}
| }
| },
| "components" : {}
|}""".stripMargin
assertTrue(json == toJsonAst(expectedJson))
},
test("simple endpoint to OpenAPI") {
val generated = OpenAPIGen.fromEndpoints("Simple Endpoint", "1.0", simpleEndpoint.tag("simple", "endpoint"))
val json = toJsonAst(generated)
Expand Down
4 changes: 3 additions & 1 deletion zio-http/shared/src/main/scala/zio/http/Method.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ sealed trait Method { self =>
if (that == Method.ANY) self
else that

def /[A](that: PathCodec[A]): RoutePattern[A] = RoutePattern.fromMethod(self) / that
def /[A](that: PathCodec[A]): RoutePattern[A] =
if (that == PathCodec.empty) RoutePattern.fromMethod(self).asInstanceOf[RoutePattern[A]]
else RoutePattern.fromMethod(self) / that

def matches(that: Method): Boolean =
if (self == Method.ANY) true
Expand Down
4 changes: 3 additions & 1 deletion zio-http/shared/src/main/scala/zio/http/RoutePattern.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ final case class RoutePattern[A](method: Method, pathCodec: PathCodec[A]) { self
* Returns a new pattern that is extended with the specified segment pattern.
*/
def /[B](that: PathCodec[B])(implicit combiner: Combiner[A, B]): RoutePattern[combiner.Out] =
copy(pathCodec = pathCodec ++ that)
if (that == PathCodec.empty) self.asInstanceOf[RoutePattern[combiner.Out]]
else if (pathCodec == PathCodec.empty) copy(pathCodec = that.asInstanceOf[PathCodec[combiner.Out]])
else copy(pathCodec = pathCodec ++ that)

/**
* Creates a route from this pattern and the specified handler.
Expand Down
7 changes: 5 additions & 2 deletions zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ sealed trait PathCodec[A] extends codec.PathCodecPlatformSpecific { self =>
final def ++[B](that: PathCodec[B])(implicit combiner: Combiner[A, B]): PathCodec[combiner.Out] =
PathCodec.Concat(self, that, combiner)

final def /[B](that: PathCodec[B])(implicit combiner: Combiner[A, B]): PathCodec[combiner.Out] =
self ++ that
final def /[B](that: PathCodec[B])(implicit combiner: Combiner[A, B]): PathCodec[combiner.Out] = {
if (self == PathCodec.empty) that.asInstanceOf[PathCodec[combiner.Out]]
else if (that == PathCodec.empty) self.asInstanceOf[PathCodec[combiner.Out]]
else self ++ that
}

final def /[Env, Err](routes: Routes[Env, Err])(implicit
ev: PathCodec[A] <:< PathCodec[Unit],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ sealed trait SegmentCodec[A] { self =>
}
if (self ne SegmentCodec.Empty) b.append('/')
loop(self.asInstanceOf[SegmentCodec[_]])
if (b.isEmpty) b.appendAll("/")
b.result()
}

Expand Down

0 comments on commit 5e7f147

Please sign in to comment.