Skip to content

Commit

Permalink
Http4s interop docs, example project (zio#244)
Browse files Browse the repository at this point in the history
* Add HTTP4s interop example

* Interop module docs

* .gitignore
  • Loading branch information
fsvehla authored Apr 7, 2021
1 parent 6eb41b5 commit e7a3342
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,12 @@ project/plugins/project/
*.class
*.log
.bsp
.vscode
.hydra

.metals/
project/metals.sbt
project/project
.bloop/
project/secret

Expand All @@ -416,3 +419,4 @@ website/node_modules
website/build
website/i18n/en.json
website/static/api
website/yarn.lock
36 changes: 36 additions & 0 deletions docs/interop/interop_http4s.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: interop_http4s
title: "HTTP4s Interop"
---

An interop module is provided for [HTTP4s v0.21](https://http4s.org/v0.21)

## Installation

```scala
libraryDependencies ++= Seq(
"@ORG@" % "zio-json-interop-http4s" % "@RELEASE_VERSION@"
)
```

## Usage

```scala
import zio.json._
import zio.json.interop.http4s._

final case class Greeting(greeting: String)

object Greeting {
// This JsonCodec[A] will be picked up by the `jsonEncoderOf` method provided by zio-json-interop-http4s
implicit val encoder: JsonCodec[Greeting] =
DeriveJsonCodec.gen

implicit def entityEncoder[F[_]: Applicative]: EntityEncoder[F, Greeting] =
jsonEncoderOf[F, Greeting]
}
```

## Example project

A fully working example project [can be found here](https://github.com/zio/zio-json/examples/interop-http4s)
8 changes: 8 additions & 0 deletions docs/interop/interop_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
id: interop_index
title: "Interop modules"
---

## List of Interop modules

* [HTTP4s](interop_http4s)
21 changes: 21 additions & 0 deletions examples/interop-http4s/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
val Http4sVersion = "0.21.21"
val ZioJsonVersion = "0.1.3+8-6eb41b5a-SNAPSHOT"

lazy val zioJsonHttp4sExample = (project in file("."))
.settings(
name := "zio-json-http4s-example",
version := "1.0",
scalaVersion := "2.13.5",

scalacOptions ++= Seq("-Xlint:_"),

// Only required when using a zio-json snapshot
resolvers ++= Seq("public", "snapshots", "releases").map(Resolver.sonatypeRepo),

libraryDependencies ++= Seq(
"org.http4s" %% "http4s-blaze-server" % Http4sVersion,
"org.http4s" %% "http4s-dsl" % Http4sVersion,
"dev.zio" %% "zio-json" % ZioJsonVersion,
"dev.zio" %% "zio-json-interop-http4s" % ZioJsonVersion,
)
)
1 change: 1 addition & 0 deletions examples/interop-http4s/project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.5.0
32 changes: 32 additions & 0 deletions examples/interop-http4s/src/main/scala/example/HelloWorld.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package example

import cats.Applicative
import cats.implicits._
import org.http4s.EntityEncoder

import zio.json._
import zio.json.interop.http4s._

trait HelloWorld[F[_]]{
def hello(n: HelloWorld.Name): F[HelloWorld.Greeting]
}

object HelloWorld {
implicit def apply[F[_]](implicit ev: HelloWorld[F]): HelloWorld[F] = ev

final case class Name(name: String)
final case class Greeting(greeting: String)

object Greeting {
implicit val encoder: JsonCodec[Greeting] =
DeriveJsonCodec.gen

implicit def entityEncoder[F[_]: Applicative]: EntityEncoder[F, Greeting] =
jsonEncoderOf[F, Greeting]
}

def impl[F[_]: Applicative]: HelloWorld[F] = new HelloWorld[F]{
def hello(n: HelloWorld.Name): F[HelloWorld.Greeting] =
Greeting("Hello, " + n.name).pure[F]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package example

import cats.effect.Sync
import cats.implicits._
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl

object HelloWorldRoutes {
def routes[F[_]: Sync](H: HelloWorld[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._

HttpRoutes.of[F] {
case GET -> Root / "hello" / name =>
for {
greeting <- H.hello(HelloWorld.Name(name))
resp <- Ok(greeting)
} yield resp
}
}
}
8 changes: 8 additions & 0 deletions examples/interop-http4s/src/main/scala/example/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package example

import cats.effect.{ExitCode, IO, IOApp}

object Main extends IOApp {
def run(args: List[String]) =
Server.stream[IO].compile.drain.as(ExitCode.Success)
}
13 changes: 13 additions & 0 deletions examples/interop-http4s/src/main/scala/example/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# HTTP4s + zio-json example

This example was adopted from HTTP4s’ [Quickstart example](https://http4s.org/v0.21)

```bash
sbt run
```

```text
$ curl http://127.0.0.1:8080/hello/sarah
{"greeting":"Hello, sarah"}
```
22 changes: 22 additions & 0 deletions examples/interop-http4s/src/main/scala/example/Server.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package example

import cats.effect.{ConcurrentEffect, Timer}

import fs2.Stream

import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder

import scala.concurrent.ExecutionContext.global

object Server {
def stream[F[_]: ConcurrentEffect](implicit T: Timer[F]): Stream[F, Nothing] = {
val httpApp =
HelloWorldRoutes.routes[F](HelloWorld.impl[F]).orNotFound

BlazeServerBuilder[F](global)
.bindHttp(8080, "0.0.0.0")
.withHttpApp(httpApp)
.serve
}.drain
}
1 change: 1 addition & 0 deletions website/pages/en/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class HomeSplash extends React.Component {
<ProjectTitle siteConfig={siteConfig}/>
<PromoSection>
<Button href={docUrl('overview/overview_index')}>Overview</Button>
<Button href={docUrl('interop/interop_index')}>Interop modules</Button>
<Button href="https://github.com/zio/zio-json" target="_blank">GitHub</Button>
</PromoSection>
</div>
Expand Down
8 changes: 8 additions & 0 deletions website/sidebars.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
"overview/overview_encoding"
]
},

"interop-sidebar": {
"Interop": [
"interop/interop_index",
"interop/interop_http4s"
]
},

"about-sidebar": {
"About": [
"about/about_index",
Expand Down
5 changes: 3 additions & 2 deletions website/siteConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ const siteConfig = {
// For no header links in the top nav bar -> headerLinks: [],
headerLinks: [
{doc: 'overview/overview_index', label: 'Overview'},
{href: 'api/index.html', label: 'API'},
{doc: 'about/about_index', label: 'About'}
{doc: 'interop/interop_index', label: 'Interop modules'},
// {href: 'api/index.html', label: 'API'}, -- currently broken.
{doc: 'about/about_index', label: 'About'}
],

// by default Docusaurus combines CSS files in a way that doesn't play nicely with Scaladoc
Expand Down

0 comments on commit e7a3342

Please sign in to comment.