Created
June 15, 2024 07:58
-
-
Save dacr/62d5760356927be012449fbfad39a1f0 to your computer and use it in GitHub Desktop.
tapir with iron for data validity and better documentation / published by https://github.com/dacr/code-examples-manager #c100bdc5-c628-4aa7-86f3-f838a07a6266/d1df5513fa32f68df76ca706304d0a3d71cae9d7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// summary : tapir with iron for data validity and better documentation | |
// keywords : scala, zio, tapir, iron, @testable, @exclusive | |
// publish : gist | |
// authors : David Crosson | |
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2) | |
// id : c100bdc5-c628-4aa7-86f3-f838a07a6266 | |
// created-on : 2024-06-06T13:37:39+02:00 | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// run-with : scala-cli $file | |
// test-with : curl -L http://127.0.0.1:8080/hello/david | |
// --------------------- | |
//> using scala "3.4.2" | |
//> using dep "com.softwaremill.sttp.tapir::tapir-zio:1.10.9" | |
//> using dep "com.softwaremill.sttp.tapir::tapir-zio-http-server:1.10.9" | |
//> using dep "com.softwaremill.sttp.tapir::tapir-iron:1.10.9" | |
//> using dep "com.softwaremill.sttp.tapir::tapir-json-zio:1.10.9" | |
//> using dep "com.softwaremill.sttp.tapir::tapir-swagger-ui-bundle:1.10.9" | |
//> using dep "io.github.iltotore::iron-zio:2.5.0" | |
//> using dep "io.github.iltotore::iron-zio-json:2.5.0" | |
// --------------------- | |
import zio.* | |
import zio.json.* | |
import zio.http.Server | |
import io.github.iltotore.iron.* | |
import io.github.iltotore.iron.constraint.all.* | |
import io.github.iltotore.iron.zioJson.given | |
import sttp.tapir.ztapir.* | |
import sttp.tapir.server.ziohttp.ZioHttpInterpreter | |
import sttp.tapir.swagger.bundle.SwaggerInterpreter | |
import sttp.tapir.json.zio.* | |
import sttp.tapir.Schema | |
import sttp.tapir.generic.auto.* | |
import sttp.tapir.codec.iron.* | |
import sttp.apispec.openapi.Info | |
object WebApp extends ZIOAppDefault { | |
enum Gender derives JsonCodec { | |
case Female, Male | |
} | |
object Gender { | |
given JsonEncoder[Gender] = JsonEncoder[String].contramap(p => p.toString) | |
given JsonDecoder[Gender] = JsonDecoder[String].map(p => Gender.valueOf(p)) | |
given Schema[Gender] = Schema.derivedEnumeration.defaultStringBased | |
} | |
case class Salute( | |
name: String :| Not[Empty] :| Alphanumeric, | |
age: Option[Int :| Positive] /*DescribedAs "Age should be positive"*/, | |
gender: Option[Gender], | |
nicknames: List[String :| (MinLength[3] & MaxLength[6])] :| Not[Empty] | |
) | |
object Salute { | |
given JsonEncoder[Salute] = DeriveJsonEncoder.gen | |
given JsonDecoder[Salute] = DeriveJsonDecoder.gen | |
} | |
case class Greeting(message: String) derives JsonCodec | |
// -------------------------------------------------- | |
def helloLogic(salute: Salute): UIO[Greeting] = { | |
val nicknames:List[String] = salute.nicknames | |
for { | |
nickName <- Random.shuffle(nicknames).map(_.headOption) // .when(!salute.nicknames.isEmpty) | |
name = nickName.getOrElse(salute.name) | |
message = salute match { | |
case Salute(name, Some(foundAge:Int), _, _) if foundAge < 18 => s"Hi $name" | |
case Salute(name, Some(foundAge), Some(Gender.Female), _) => s"Hello madam $name" | |
case Salute(name, Some(foundAge), Some(Gender.Male), _) => s"Hello mister $name" | |
case Salute(name, _, _, _) => s"Good morning $name" | |
} | |
} yield Greeting(message) | |
} | |
val helloEndPoint = | |
endpoint | |
.tag("Greetings") | |
.name("hello") | |
.description("Returns stateful greeting") | |
.post | |
.in("hello") | |
//.in(jsonBody[Salute].example(Salute("Joe", None, None, List("joe")))) | |
.in(jsonBody[Salute]) | |
.out(jsonBody[Greeting]) | |
val helloRoute = helloEndPoint.zServerLogic[Any](helloLogic) | |
// -------------------------------------------------- | |
val apiDocRoute = | |
SwaggerInterpreter() | |
.fromServerEndpoints( | |
List(helloRoute), | |
Info( | |
title = "Greeting API", | |
version = "1.0", | |
description = Some("Everything required to be polite") | |
) | |
) | |
// -------------------------------------------------- | |
val routes = ZioHttpInterpreter().toHttp(List(helloRoute) ++ apiDocRoute) | |
// -------------------------------------------------- | |
val server = for { | |
_ <- ZIO.log("API documentation : http://127.0.0.1:8080/docs") | |
_ <- Server.serve(routes) | |
} yield () | |
override def run = server.provide(Server.default) | |
} | |
WebApp.main(Array.empty) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment