Skip to content

Commit

Permalink
Simpler default Endpoint#implement (#2811) (#2894)
Browse files Browse the repository at this point in the history
Co-authored-by: John A. De Goes <[email protected]>
  • Loading branch information
987Nabil and jdegoes authored Jun 9, 2024
1 parent f070e41 commit fcbbebf
Show file tree
Hide file tree
Showing 21 changed files with 152 additions and 134 deletions.
8 changes: 4 additions & 4 deletions docs/reference/endpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ In the above example, we defined an endpoint on the path `/books` that accepts a
After defining the endpoint, we are ready to implement it. We can implement it using the `Endpoint#implement` method, which takes a proper handler function that will be called when the endpoint is invoked and returns a `Route`:

```scala
val booksRoute = endpoint.implement(handler((query: String) => BookRepo.find(query)))
val booksRoute = endpoint.implement(query => BookRepo.find(query))
```

We can also generate OpenAPI documentation for our endpoint using the `OpenAPIGen.fromEndpoints` constructor:
Expand Down Expand Up @@ -261,13 +261,13 @@ object EndpointWithMultipleOutputTypes extends ZIOAppDefault {
.out[Quiz]

def run = Server.serve(
endpoint.implement(handler {
endpoint.implement(_ =>
ZIO.randomWith(_.nextBoolean)
.map(r =>
if (r) Right(Course("Introduction to Programming", 49.99))
else Left(Quiz("What is the boiling point of water in Celsius?", 2)),
)
})
)
.toRoutes).provide(Server.default, Scope.default)
}
```
Expand Down Expand Up @@ -417,7 +417,7 @@ case class Book(
The `OpenAPIGen.fromEndpoints` constructor generates OpenAPI documentation from the endpoints. By having the OpenAPI documentation, we can easily generate Swagger UI routes using the `SwaggerUI.routes` constructor:

```scala
val booksRoute = endpoint.implement(handler((query: String) => BookRepo.find(query)))
val booksRoute = endpoint.implement(query => BookRepo.find(query))
val openAPI = OpenAPIGen.fromEndpoints(title = "Library API", version = "1.0", endpoint)
val swaggerRoutes = SwaggerUI.routes("docs" / "openapi", openAPI)
val routes = Routes(booksRoute) ++ swaggerRoutes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ object ZIOHttpGRPCGenSpec extends ZIOSpecDefault {
assertTrue(true)
},
test("plugin generates Endpoint") {
val impl = V1.test.implement {
Handler.fromFunction[TestMsg] { msg =>
msg
}
}
val impl = V1.test.implementPurely { msg => msg }
assertTrue(true)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class EndpointBenchmark {
.out[ExampleData]

val handledUsersPosts =
usersPosts.implement {
usersPosts.implementHandler {
Handler.fromFunction { case (userId, postId, limit) =>
ExampleData(userId, postId, limit)
}
Expand Down Expand Up @@ -218,7 +218,7 @@ class EndpointBenchmark {
) / "seventh" / int("id5"),
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
.toRoutes

// Collect DSL
Expand Down Expand Up @@ -333,20 +333,20 @@ class EndpointBenchmark {

// API DSL

val broadUsers = Endpoint(Method.GET / "users").out[Unit].implement(Handler.unit)
val broadUsers = Endpoint(Method.GET / "users").out[Unit].implementHandler(Handler.unit)
val broadUsersId =
Endpoint(Method.GET / "users" / int("userId")).out[Unit].implement(Handler.unit)
Endpoint(Method.GET / "users" / int("userId")).out[Unit].implementHandler(Handler.unit)
val boardUsersPosts =
Endpoint(Method.GET / "users" / int("userId") / "posts")
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardUsersPostsId =
Endpoint(
Method.GET /
"users" / int("userId") / "posts" / int("postId"),
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardUsersPostsComments =
Endpoint(
Method.GET /
Expand All @@ -355,7 +355,7 @@ class EndpointBenchmark {
) / "comments",
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardUsersPostsCommentsId =
Endpoint(
Method.GET /
Expand All @@ -364,14 +364,14 @@ class EndpointBenchmark {
) / "comments" / int("commentId"),
)
.out[Unit]
.implement(Handler.unit)
val broadPosts = Endpoint(Method.GET / "posts").out[Unit].implement(Handler.unit)
.implementHandler(Handler.unit)
val broadPosts = Endpoint(Method.GET / "posts").out[Unit].implementHandler(Handler.unit)
val broadPostsId =
Endpoint(Method.GET / "posts" / int("postId")).out[Unit].implement(Handler.unit)
Endpoint(Method.GET / "posts" / int("postId")).out[Unit].implementHandler(Handler.unit)
val boardPostsComments =
Endpoint(Method.GET / "posts" / int("postId") / "comments")
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardPostsCommentsId =
Endpoint(
Method.GET /
Expand All @@ -380,14 +380,14 @@ class EndpointBenchmark {
),
)
.out[Unit]
.implement(Handler.unit)
val broadComments = Endpoint(Method.GET / "comments").out[Unit].implement(Handler.unit)
.implementHandler(Handler.unit)
val broadComments = Endpoint(Method.GET / "comments").out[Unit].implementHandler(Handler.unit)
val broadCommentsId =
Endpoint(Method.GET / "comments" / int("commentId")).out[Unit].implement(Handler.unit)
Endpoint(Method.GET / "comments" / int("commentId")).out[Unit].implementHandler(Handler.unit)
val broadUsersComments =
Endpoint(Method.GET / "users" / int("userId") / "comments")
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val broadUsersCommentsId =
Endpoint(
Method.GET /
Expand All @@ -396,7 +396,7 @@ class EndpointBenchmark {
),
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardUsersPostsCommentsReplies =
Endpoint(
Method.GET /
Expand All @@ -406,7 +406,7 @@ class EndpointBenchmark {
"replies",
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)
val boardUsersPostsCommentsRepliesId =
Endpoint(
Method.GET /
Expand All @@ -415,7 +415,7 @@ class EndpointBenchmark {
) / "comments" / int("commentId") / "replies" / int("replyId"),
)
.out[Unit]
.implement(Handler.unit)
.implementHandler(Handler.unit)

val broadApiApp =
Routes(
Expand Down
12 changes: 3 additions & 9 deletions zio-http-example/src/main/scala/example/EndpointExamples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,16 @@ object EndpointExamples extends ZIOAppDefault {
Endpoint(Method.GET / "users" / int("userId")).out[Int] @@ auth

val getUserRoute =
getUser.implement {
Handler.fromFunction[Int] { id =>
id
}
}
getUser.implement { id => ZIO.succeed(id) }

val getUserPosts =
Endpoint(Method.GET / "users" / int("userId") / "posts" / int("postId"))
.query(query("name"))
.out[List[String]] @@ auth

val getUserPostsRoute =
getUserPosts.implement[Any] {
Handler.fromFunctionZIO[(Int, Int, String)] { case (id1: Int, id2: Int, query: String) =>
ZIO.succeed(List(s"API2 RESULT parsed: users/$id1/posts/$id2?name=$query"))
}
getUserPosts.implement { case (id1: Int, id2: Int, query: String) =>
ZIO.succeed(List(s"API2 RESULT parsed: users/$id1/posts/$id2?name=$query"))
}

val openAPI = OpenAPIGen.fromEndpoints(title = "Endpoint Example", version = "1.0", getUser, getUserPosts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object ServerSentEventEndpoint extends ZIOAppDefault {
val sseEndpoint: Endpoint[Unit, Unit, ZNothing, ZStream[Any, Nothing, ServerSentEvent], None] =
Endpoint(Method.GET / "sse").outStream[ServerSentEvent]

val sseRoute = sseEndpoint.implement(Handler.succeed(stream))
val sseRoute = sseEndpoint.implementHandler(Handler.succeed(stream))

val routes: Routes[Any, Response] = sseRoute.toRoutes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ object BooksEndpointExample extends ZIOAppDefault {
"Endpoint to query books based on a search query",
)

val booksRoute = endpoint.implement(handler((query: String) => BookRepo.find(query)))
val booksRoute = endpoint.implementHandler(handler((query: String) => BookRepo.find(query)))
val openAPI = OpenAPIGen.fromEndpoints(title = "Library API", version = "1.0", endpoint)
val swaggerRoutes = SwaggerUI.routes("docs" / "openapi", openAPI)
val routes = Routes(booksRoute) ++ swaggerRoutes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,21 @@ object TestCliApp extends zio.cli.ZIOCliDefault with TestCliEndpoints {

object TestCliServer extends zio.ZIOAppDefault with TestCliEndpoints {
val getUserRoute =
getUser.implement {
getUser.implementHandler {
Handler.fromFunctionZIO { case (id, _) =>
ZIO.succeed(User(id, "Juanito", Some("[email protected]"))).debug("Hello")
}
}

val getUserPostsRoute =
getUserPosts.implement {
getUserPosts.implementHandler {
Handler.fromFunction { case (userId, postId, name) =>
List(Post(userId, postId, name))
}
}

val createUserRoute =
createUser.implement {
createUser.implementHandler {
Handler.fromFunction { user =>
user.name
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object EndpointWithMultipleErrorsUsingEither extends ZIOAppDefault {
ZIO.fail(Left(AuthenticationError("User is not authenticated", 123)))
}

val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug
val routes = endpoint.implementHandler(getBookHandler).toRoutes @@ Middleware.debug

def run = Server.serve(routes).provide(Server.default)
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object EndpointWithMultipleUnifiedErrors extends ZIOAppDefault {
ZIO.fail(AuthenticationError("User is not authenticated", 123))
}

val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug
val routes = endpoint.implementHandler(getBookHandler).toRoutes @@ Middleware.debug

def run = Server.serve(routes).provide(Server.default)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object DeclarativeProgrammingExample extends ZIOAppDefault {
val getBookHandler: Handler[Any, NotFoundError, String, Book] =
handler(BookRepo.find(_))

val routes = endpoint.implement(getBookHandler).toRoutes @@ Middleware.debug
val routes = endpoint.implementHandler(getBookHandler).toRoutes @@ Middleware.debug

def run = Server.serve(routes).provide(Server.default)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package zio.http

import java.lang.System
import java.nio.file.{Files, Path => NIOPath}

import zio._
Expand All @@ -32,7 +31,7 @@ object StaticFileRoutesSpec extends HttpRunnableSpec {
private def deleteTempFile(tempPath: NIOPath) = ZIO.attempt(Files.deleteIfExists(tempPath)).ignore
private val createAndDeleteTempFile = createTempFile.flatMap(f => deleteTempFile(f).as(f))

override def spec = suite("StaticFileServerSpec") {
override def spec = suite("StaticFileRoutesSpec") {
serve.as(List(staticSpec))
}
.provideSome[DynamicServer & Server & Client](Scope.default)
Expand Down Expand Up @@ -78,7 +77,9 @@ object StaticFileRoutesSpec extends HttpRunnableSpec {
assert(response.status)(equalTo(Status.Ok)) &&
assert(response.header(Header.ContentLength))(isSome(equalTo(Header.ContentLength(7L)))) &&
assert(body)(equalTo("foo\nbar")) &&
assert(response.header(Header.ContentType))(isSome(equalTo(Header.ContentType(MediaType.text.plain))))
assert(response.header(Header.ContentType))(
isSome(equalTo(Header.ContentType(MediaType.text.plain, charset = Some(Charsets.Utf8)))),
)
}
},
test("serve a non-existing resource") {
Expand Down
4 changes: 3 additions & 1 deletion zio-http/jvm/src/test/scala/zio/http/endpoint/AuthSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ object AuthSpec extends ZIOSpecDefault {
test("Auth with context") {
val endpoint = Endpoint(Method.GET / "test").out[String](MediaType.text.`plain`)
val routes =
Routes(endpoint.implement(handler((_: Unit) => ZIO.serviceWith[AuthContext](_.value)))) @@ basicAuthContext
Routes(
endpoint.implementHandler(handler((_: Unit) => ZIO.serviceWith[AuthContext](_.value))),
) @@ basicAuthContext
val response = routes.run(
Request(
method = Method.GET,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object BadRequestSpec extends ZIOSpecDefault {
val endpoint = Endpoint(Method.GET / "test")
.query(QueryCodec.queryInt("age"))
.out[Unit]
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2").addHeader(Header.Accept(MediaType.text.`html`))
val expectedBody =
Expand All @@ -38,7 +38,7 @@ object BadRequestSpec extends ZIOSpecDefault {
val endpoint = Endpoint(Method.GET / "test")
.query(QueryCodec.queryInt("age"))
.out[Unit]
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2")
.addHeader(Header.Accept(MediaType.application.json))
Expand All @@ -53,7 +53,7 @@ object BadRequestSpec extends ZIOSpecDefault {
val endpoint = Endpoint(Method.GET / "test")
.query(QueryCodec.queryInt("age"))
.out[Unit]
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2")
.addHeader(Header.Accept(MediaType.application.`atf`))
Expand All @@ -69,7 +69,7 @@ object BadRequestSpec extends ZIOSpecDefault {
.query(QueryCodec.queryInt("age"))
.out[Unit]
.emptyErrorResponse
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2")
.addHeader(Header.Accept(MediaType.application.`atf`))
Expand All @@ -83,7 +83,7 @@ object BadRequestSpec extends ZIOSpecDefault {
val endpoint = Endpoint(Method.GET / "test")
.query(QueryCodec.queryInt("age"))
.out[Unit]
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2")
.addHeader(Header.Accept(MediaType.application.json))
Expand All @@ -99,7 +99,7 @@ object BadRequestSpec extends ZIOSpecDefault {
.query(QueryCodec.queryInt("age"))
.out[Unit]
.outCodecError(default)
val route = endpoint.implement(handler((_: Int) => ()))
val route = endpoint.implementHandler(handler((_: Int) => ()))
val request =
Request(method = Method.GET, url = url"/test?age=1&age=2")
.addHeader(Header.Accept(MediaType.application.json))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object CustomErrorSpec extends ZIOHttpSpec {
Endpoint(GET / "users" / int("userId"))
.out[String]
.outError[String](Status.Custom(customCode))
.implement {
.implementHandler {
Handler.fromFunctionZIO { userId =>
ZIO.fail(s"path(users, $userId)")
}
Expand All @@ -66,7 +66,7 @@ object CustomErrorSpec extends ZIOHttpSpec {
HttpCodec.error[TestError.UnexpectedError](Status.InternalServerError),
HttpCodec.error[TestError.InvalidUser](Status.NotFound),
)
.implement {
.implementHandler {
Handler.fromFunctionZIO { userId =>
if (userId == myUserId) ZIO.fail(TestError.InvalidUser(userId))
else ZIO.fail(TestError.UnexpectedError("something went wrong"))
Expand Down Expand Up @@ -100,7 +100,7 @@ object CustomErrorSpec extends ZIOHttpSpec {
.in[User](Doc.p("User schema with id"))
.out[String]
.emptyErrorResponse
.implement {
.implementHandler {
Handler.fromFunctionZIO { _ =>
ZIO.succeed("User ID is greater than 0")
}
Expand Down
Loading

0 comments on commit fcbbebf

Please sign in to comment.