Last active
October 29, 2022 15:20
-
-
Save zetashift/779b0ad550e5e6899466008081d74829 to your computer and use it in GitHub Desktop.
wooo
This file contains 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
//> using scala "3.2" | |
//> using lib "org.http4s::http4s-dsl:1.0.0-M29" | |
//> using lib "org.http4s::http4s-ember-server:1.0.0-M29" | |
//> using lib "org.http4s::http4s-ember-client:1.0.0-M29" | |
//> using lib "org.http4s::http4s-circe:1.0.0-M29" | |
//> using lib "ch.qos.logback:logback-classic:1.2.6" | |
package zetashift.todo | |
import cats.effect._ | |
import cats.effect.implicits.* | |
import cats.effect.kernel.Ref | |
import cats.effect.std.Random | |
import cats.implicits.* | |
import com.comcast.ip4s.host | |
import com.comcast.ip4s.ipv4 | |
import com.comcast.ip4s.port | |
import io.circe.Encoder.* | |
import io.circe.* | |
import io.circe.syntax.* | |
import org.http4s.EntityDecoder | |
import org.http4s.EntityEncoder | |
import org.http4s._ | |
import org.http4s.circe.CirceEntityDecoder.* | |
import org.http4s.circe.* | |
import org.http4s.dsl.io._ | |
import org.http4s.ember.server.EmberServerBuilder | |
import org.http4s.implicits.* | |
import org.http4s.server.Router | |
import org.http4s.server.middleware.Logger | |
final case class Todo(id: Long, description: String) derives Codec.AsObject | |
object Todo: | |
given EntityEncoder[IO, Todo] = | |
jsonEncoderOf[IO, Todo] | |
trait Todos: | |
def get(id: Long): IO[Option[Todo]] | |
def put(description: String): IO[Todo] | |
final class InMemoryTodos(ref: Ref[IO, Map[Long, Todo]], rand: Random[IO]) | |
extends Todos { | |
override def get(id: Long): IO[Option[Todo]] = | |
ref.get.map(db => db.get(key = id)) | |
override def put(description: String): IO[Todo] = | |
rand.nextLong.flatMap(id => | |
val todo = Todo(id, description) | |
ref | |
.update { db => | |
db.updated(key = id, value = todo) | |
} | |
.as(todo) | |
) | |
} | |
object Todos: | |
def inMemory(seed: Long): IO[Todos] = | |
( | |
IO.ref(Map[Long, Todo](1L -> Todo(1L, "Test"))), | |
Random.scalaUtilRandomSeedLong[IO](seed) | |
) | |
.mapN { case (ref, rand) => | |
new InMemoryTodos(ref, rand) | |
} | |
case class TodoRequest(description: String) derives Codec.AsObject | |
object Routes: | |
def todoRoutes(T: Todos) = | |
HttpRoutes.of[IO] { | |
case GET -> Root / "todo" / LongVar(id) => | |
val todo = T.get(id) | |
todo.flatMap { | |
case Some(todo) => Ok(todo) | |
case None => NotFound() | |
} | |
case req @ POST -> Root / "todo" => | |
for | |
todoR <- req.as[TodoRequest] | |
resp <- Ok(T.put(todoR.description)) | |
yield resp | |
} | |
def helloRoutes = HttpRoutes | |
.of[IO] { | |
case GET -> Root => Ok("Hello World!") | |
case GET -> Root / "hello" / name => Ok(s"Hello, $name!") | |
} | |
.orNotFound | |
object HelloApp extends IOApp: | |
def run(args: List[String]): IO[ExitCode] = | |
(for { | |
todoAlg <- Todos.inMemory(seed = 123L).toResource | |
httpApp = (Routes.todoRoutes(todoAlg)).orNotFound | |
finalHttpApp = Logger.httpApp( | |
true, | |
true, | |
logAction = Some(payload => IO.println(payload)) | |
)( | |
httpApp | |
) | |
_ <- EmberServerBuilder | |
.default[IO] | |
.withHost(ipv4"0.0.0.0") | |
.withPort(port"8080") | |
.withHttpApp(finalHttpApp) | |
.build | |
} yield ()).useForever |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment