Skip to main content
Version: 2.x

CLI Client-Server Examples

zio-http-example/src/main/scala/example/endpoint/CliExamples.scala
package example.endpoint

import zio._
import zio.cli._

import zio.schema._
import zio.schema.annotation.description

import zio.http.Header.Location
import zio.http._
import zio.http.codec._
import zio.http.endpoint.cli._
import zio.http.endpoint.{Endpoint, EndpointExecutor}

final case class User(
@description("The unique identifier of the User")
id: Int,
@description("The user's name")
name: String,
@description("The user's email")
email: Option[String],
)
object User {
implicit val schema: Schema[User] = DeriveSchema.gen[User]
}
final case class Post(
@description("The unique identifier of the User")
userId: Int,
@description("The unique identifier of the Post")
postId: Int,
@description("The post's contents")
contents: String,
)
object Post {
implicit val schema: Schema[Post] = DeriveSchema.gen[Post]
}

trait TestCliEndpoints {

val getUser =
Endpoint(Method.GET / "users" / int("userId") ?? Doc.p("The unique identifier of the user"))
.header(HeaderCodec.location ?? Doc.p("The user's location"))
.out[User] ?? Doc.p("Get a user by ID")

val getUserPosts =
Endpoint(
Method.GET /
"users" / int("userId") ?? Doc.p("The unique identifier of the user") /
"posts" / int("postId") ?? Doc.p("The unique identifier of the post"),
)
.query(
HttpCodec.query[String]("user-name") ?? Doc.p(
"The user's name",
),
)
.out[List[Post]] ?? Doc.p("Get a user's posts by userId and postId")

val createUser =
Endpoint(Method.POST / "users")
.in[User]
.out[String] ?? Doc.p("Create a new user")
}

object TestCliApp extends zio.cli.ZIOCliDefault with TestCliEndpoints {
val cliApp =
HttpCliApp
.fromEndpoints(
name = "users-mgmt",
version = "0.0.1",
summary = HelpDoc.Span.text("Users management CLI"),
footer = HelpDoc.p("Copyright 2023"),
host = "localhost",
port = 8080,
endpoints = Chunk(getUser, getUserPosts, createUser),
cliStyle = true,
)
.cliApp
}

object TestCliServer extends zio.ZIOAppDefault with TestCliEndpoints {
val getUserRoute =
getUser.implementHandler {
Handler.fromFunctionZIO { case (id, _) =>
ZIO.succeed(User(id, "Juanito", Some("juanito@test.com"))).debug("Hello")
}
}

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

val createUserRoute =
createUser.implementHandler {
Handler.fromFunction { user =>
user.name
}
}

val routes = Routes(getUserRoute, getUserPostsRoute, createUserRoute) @@ Middleware.debug

val run = Server.serve(routes).provide(Server.default)
}

object TestCliClient extends zio.ZIOAppDefault with TestCliEndpoints {
val run =
clientExample
.provide(
EndpointExecutor.make(serviceName = "test"),
Client.default,
)

def clientExample: URIO[EndpointExecutor[Any, Unit], Unit] =
for {
executor <- ZIO.service[EndpointExecutor[Any, Unit]]
_ <- ZIO.scoped(executor(getUser(42, Location.parse("some-location").toOption.get))).debug("result1")
_ <- ZIO.scoped(executor(getUserPosts(42, 200, "adam")).debug("result2"))
_ <- ZIO.scoped(executor(createUser(User(2, "john", Some("john@test.com"))))).debug("result3")
} yield ()

}