A ZIO + http4s + Circe + Quill + Tapir giter8 template

# Prerequisites
1. Lanuch H2 database at your local machine
For example: using H2 docker image
```
docker pull oscarfonts/h2
docker run -d -p 1521:1521 -p 81:81 -v /path/to/local/data_dir:/opt/h2-data --name=MyH2Instance oscarfonts/h2
```

2. Import SQL to H2 database
```
CREATE TABLE IF NOT EXISTS user
(
    id INT NOT NULL,
    name VARCHAR(255) NOT NULL,
    age INT NOT NULL,
    PRIMARY KEY(id)
);

```

# How to install
```sh
brew update && brew install giter8
g8 pandaforme/ultron.g8
```

# How to add a new API
1. Create a package in `module`
for example: `xyz`

2. Create an interface in `module.xyz`
```scala
trait XYZ {

  val service: XYZ.Service
}

object XYZ {

  trait Service {

    def doXYZ(): ZIO[Any, Error, Unit]
  }
}
```

3. Create a package object in `module.xyz`
```scala
package object xyz {

  def doXYZ(id: Long): ZIO[XYZ, Error, Unit] =
    ZIO.accessM(_.service.doXYZ())
}
```

4. Create an instance for test/live in `module.xyz`
```scala
trait LiveXYZ extends XYZ {
    override val service: XYZ.Service = new XYZ.Service {
        def doXYZ(): ZIO[Any, Error, Unit] = ???
    }
}
```

5. Create your own route in `route` and pass your interface into enviroment type
```scala
class XyzRoute[R <: XYZ] extends Http4sDsl[TaskR[R, ?]] {
  private val xyzEndPoint = endpoint.get
    .in("xyz" / path[Long]("user id"))
    .errorOut(emptyOutput)
    .out(emptyOutput)    

  val getRoutes: HttpRoutes[TaskR[R, ?]] = ???
  val getEndPoints = List(xyzEndPoint)   
}
```
6. Write unit test

7. Add your interfaces to `AppEnvironment`, routes to `httpApp` and provide Live instances in `Main.scala`
```scala
object Main extends App {
  type AppEnvironment = Clock with Console with UserRepository with MyLogger with XYZ
  private val userRoute = new UserRoute[AppEnvironment]
  private val xyzRoute = new XyzRoute[AppEnvironment]
  private val yaml = userRoute.getEndPoints.toOpenAPI("User", "1.0").toYaml

  override def run(args: List[String]): ZIO[Main.Environment, Nothing, Int] = {
    val result = for {
      application <- ZIO.fromTry(Try(Application.getConfig))

      httpApp = Router(
          "/" -> userRoute.getRoutes,
          "/" -> xyzRoute.getRoutes, 
          "/docs" -> new SwaggerHttp4s(yaml).routes[TaskR[AppEnvironment, ?]]).orNotFound
      finalHttpApp = Logger.httpApp[ZIO[AppEnvironment, Throwable, ?]](true, true)(httpApp)

      server = ZIO.runtime[AppEnvironment].flatMap { implicit rts =>
        BlazeServerBuilder[ZIO[AppEnvironment, Throwable, ?]]
          .bindHttp(application.server.port, application.server.host.getHostAddress)
          .withHttpApp(finalHttpApp)
          .serve
          .compile[ZIO[AppEnvironment, Throwable, ?], ZIO[AppEnvironment, Throwable, ?], ExitCode]
          .drain
      }
      program <- server.provideSome[Environment] { base =>
        new Clock with Console with LiveUserRepository with LiveLogger with LiveXyz{
          val clock: Clock.Service[Any] = base.clock
          val console: Console.Service[Any] = base.console
          val config: Config = ConfigFactory.parseMap(
            Map(
              "dataSourceClassName" -> application.database.className.value,
              "dataSource.url" -> application.database.url.value,
              "dataSource.user" -> application.database.user.value,
              "dataSource.password" -> application.database.password.value
            ).asJava)
        }
      }
    } yield program

    result
      .foldM(failure = err => putStrLn(s"Execution failed with: $err") *> ZIO.succeed(1), success = _ => ZIO.succeed(0))
  }
}
```

# API Endpoints
```
Swagger: http://localhost:5566/docs
User API: http://localhost:5566/user
```
# Challenges
1. Try to implement `LiveLogger`
2. Because quill driver of H2 database is not Asynced, we need to push blocking IO to another thread pool. 
How to achieve it via `ZIO`?


# Referneces
* [ZIO with http4s and doobie](https://medium.com/@wiemzin/zio-with-http4s-and-doobie-952fba51d089)
* [mschuwalow/zio-todo-backend](https://github.com/mschuwalow/zio-todo-backend/)
* [loicdescotte/pureWebappSample](https://github.com/loicdescotte/pureWebappSample)