<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kay Kreuning</title>
    <description>The latest articles on Forem by Kay Kreuning (@kkreuning).</description>
    <link>https://forem.com/kkreuning</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171018%2F508f760b-16e4-476b-9fcb-192590f5768b.jpeg</url>
      <title>Forem: Kay Kreuning</title>
      <link>https://forem.com/kkreuning</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kkreuning"/>
    <language>en</language>
    <item>
      <title>Guardrail with http4s tutorial</title>
      <dc:creator>Kay Kreuning</dc:creator>
      <pubDate>Wed, 08 May 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/kkreuning/guardrail-with-http4s-tutorial-55p2</link>
      <guid>https://forem.com/kkreuning/guardrail-with-http4s-tutorial-55p2</guid>
      <description>&lt;p&gt;This article is an introduction on how to use Twilio’s &lt;a href="https://guardrail.dev"&gt;Guardrail&lt;/a&gt; to safely generate and maintain a &lt;a href="https://http4s.org"&gt;http4s&lt;/a&gt; REST API server. I wanted to write this article as a reference for my future self and others who are interested in this technology.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CGWT0VjO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kkreuning.github.io/assets/images/guardrail.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CGWT0VjO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://kkreuning.github.io/assets/images/guardrail.jpg" alt="real guardrail in its natural habitat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr - I just want the code!
&lt;/h2&gt;

&lt;p&gt;Find the finished project at &lt;a href="https://github.com/kkreuning/guardrail-http4s-example"&gt;guardrail-http4s-tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for Guardrail
&lt;/h2&gt;

&lt;p&gt;To quote from Guardrail’s website:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Guardrail is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating Scala source code, primarily targeting the akka-http and http4s web frameworks, using circe for JSON encoding/decoding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s nice and all, but Swagger is already capable of generating Scala code, why does Guardrail exist at all?&lt;/p&gt;

&lt;p&gt;In two words &lt;strong&gt;type safety&lt;/strong&gt; , as we will see it is impossible to do the wrong thing when working with Guardrail’s generated code because the compiler’s type checker will prevent us from making mistakes.&lt;/p&gt;

&lt;p&gt;More important, when using Guardrail, we are forced to develop API first and our OpenAPI/Swagger specification functions as the single source of truth for our API’s.&lt;/p&gt;

&lt;p&gt;Now, without further ado, let’s build a http4s server using Guardrail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and setup
&lt;/h2&gt;

&lt;p&gt;For this tutorial we will need&lt;a href="http://www.scala-sbt.org/1.0/docs/Setup.html"&gt;sbt&lt;/a&gt;. To save some time we are going to use the http4s g8 template, in your terminal do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt new http4s/http4s.g8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I’m going to use the defaults. If you want to have different names, the paths and filenames in this tutorial might be different for you. When &lt;code&gt;sbt&lt;/code&gt; is done open the newly created directory. Start with deleting the standard routes since we are not going to use them. Delete the following files and directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/main/scala/com/example/quickstart/HelloWorld.scala&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/main/scala/com/example/quickstart/Jokes.scala&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/main/scala/com/example/quickstart/QuickstartRoutes.scala&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/test&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;code&gt;QuickstartServer.scala&lt;/code&gt;, remove the references to files you just deleted so that we are left with the following file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.quickstart

import cats.effect.{ConcurrentEffect, Effect, ExitCode, IO, IOApp, Timer, ContextShift}
import cats.implicits._
import fs2.Stream
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.HttpRoutes
import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.Logger
import scala.concurrent.ExecutionContext.global

object QuickstartServer {

  def stream[F[_]: ConcurrentEffect](implicit T: Timer[F], C: ContextShift[F]): Stream[F, Nothing] = {
    for {
      client &amp;lt;- BlazeClientBuilder[F](global).stream

      httpApp = (
        HttpRoutes.empty[F] // We will add our own routes here later
      ).orNotFound

      finalHttpApp = Logger.httpApp(true, true)(httpApp)

      exitCode &amp;lt;- BlazeServerBuilder[F]
        .bindHttp(8080, "0.0.0.0")
        .withHttpApp(finalHttpApp)
        .serve
    } yield exitCode
  }.drain
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let’s see if we can still run the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The application should compile and we should see some output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[scala-execution-context-global-92] INFO o.h.s.b.BlazeServerBuilder - http4s v0.20.0 on blaze v0.14.0 started at http://[0:0:0:0:0:0:0:0]:8080/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Congratulations! We have a working http4s application. Right now it just sits there doing nothing, so let us create some endpoints!&lt;/p&gt;

&lt;h2&gt;
  
  
  API specifications and the Guardrail sbt plugin
&lt;/h2&gt;

&lt;p&gt;For this tutorial, we are going to recreate the Hello World endpoint that we deleted earlier. Save the following specification as &lt;code&gt;src/main/resources/api.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openapi: "3.0.0"
info:
  title: http4s Guardrail example
  version: 0.0.1
tags:
  - name: hello
paths:
  /hello:
    get:
      tags: [hello]
      x-scala-package: hello
      operationId: getHello
      summary: Returns a hello message
      responses:
        200:
          description: Hello message
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HelloResponse'
components:
  schemas:
    HelloResponse:
      type: object
      properties:
        message:
          type: string
      required:
        - message
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Two things to notice in the specification are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We must provide an &lt;code&gt;operationId&lt;/code&gt; for our operation&lt;/li&gt;
&lt;li&gt;It is good practice to provide an &lt;code&gt;x-scala-package&lt;/code&gt; value to group related operations together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the code generation, we are going to use the &lt;a href="https://github.com/twilio/sbt-guardrail"&gt;sbt-guardrail plugin&lt;/a&gt;, to&lt;code&gt;project.plugins.sbt&lt;/code&gt; add the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addSbtPlugin("com.twilio" % "sbt-guardrail" % "0.46.0")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To &lt;code&gt;build.sbt&lt;/code&gt;, append the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;guardrailTasks in Compile := List(
  ScalaServer(
    specPath = (Compile / resourceDirectory).value / "api.yaml",
    pkg = "com.example.quickstart.endpoints",
    framework = "http4s",
    tracing = false
  )
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And add the following dependency to the existing &lt;code&gt;libraryDependencies&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"io.circe" %% "circe-java8" % CirceVersion,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To see the code generator in action, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt compile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And take a look in the&lt;code&gt;target/scala-2.12/src_managed/main/com/example/quickstart&lt;/code&gt; directory, this is where our generated code lives, lets see what is there:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;definitions&lt;/code&gt; directory contains the case classes that are used as request and response bodies and helper code for serialization and deserialization. For example, we defined a &lt;code&gt;HelloResponse&lt;/code&gt; schema in the API specification we got a corresponding &lt;code&gt;HelloResponse.scala&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hello&lt;/code&gt; package got its name from the &lt;code&gt;x-scala-package&lt;/code&gt; value.&lt;code&gt;hello/Routes.scala&lt;/code&gt; contains a &lt;code&gt;trait&lt;/code&gt; with methods that we must implement. The methods in this trait correspond the operations / &lt;code&gt;operationId&lt;/code&gt;s in the API specification.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Http4sImplicits.scala&lt;/code&gt; and &lt;code&gt;Implicits.scala&lt;/code&gt; contain, well, implicits. They are there to glue everything together.&lt;/p&gt;

&lt;p&gt;So far so good, now we must actually implement the endpoint we generated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the generated endpoint
&lt;/h2&gt;

&lt;p&gt;Create a new file at&lt;code&gt;src/main/scala/com/example/quickstart/endpoints/hello/HelloHandlerImpl.scala&lt;/code&gt;with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.quickstart.endpoints.hello

import cats.Applicative
import cats.implicits._
import com.example.quickstart.endpoints.definitions.HelloResponse

class HelloHandlerImpl[F[_] : Applicative]() extends HelloHandler[F] {
  override def getHello(respond: GetHelloResponse.type)(): F[GetHelloResponse] = {
    for {
      message &amp;lt;- "Hello, world".pure[F]
    } yield respond.Ok(HelloResponse(message))
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What we’ve done here is implement the generated &lt;code&gt;HelloHandler&lt;/code&gt;. Looking at the signature of the &lt;code&gt;getHello&lt;/code&gt; method we can see Guardrail genius, everything is typed! If this still doesn’t click with you, try to rewrite the change the code to respond with something else than a &lt;code&gt;200 OK&lt;/code&gt; and have it compile (hint, you can’t).&lt;/p&gt;

&lt;p&gt;Before we forget, lets add our hello routes to the application, open&lt;code&gt;src/main/scala/com/example/quickstart/QuickstartServer.scala&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.quickstart

import cats.effect.{ConcurrentEffect, Effect, ExitCode, IO, IOApp, Timer, ContextShift}
import cats.implicits._
import com.example.quickstart.endpoints.hello.{HelloHandlerImpl, HelloResource}
import fs2.Stream
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.HttpRoutes
import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.server.middleware.Logger
import scala.concurrent.ExecutionContext.global

object QuickstartServer {

  def stream[F[_]: ConcurrentEffect](implicit T: Timer[F], C: ContextShift[F]): Stream[F, Nothing] = {
    for {
      client &amp;lt;- BlazeClientBuilder[F](global).stream

      httpApp = (
        new HelloResource().routes(new HelloHandlerImpl())
      ).orNotFound

      finalHttpApp = Logger.httpApp(true, true)(httpApp)

      exitCode &amp;lt;- BlazeServerBuilder[F]
        .bindHttp(8080, "0.0.0.0")
        .withHttpApp(finalHttpApp)
        .serve
    } yield exitCode
  }.drain
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What changed is that we added the line&lt;code&gt;new HelloResource().routes(new HelloHandlerImpl())&lt;/code&gt; to the &lt;code&gt;httpApp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can run the application again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And once it’s running we can test our endpoint using &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; curl http://localhost:8080/hello
{"message":"Hello, world"}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;🎉 Success! Everything is well in the world now. That is, until the API requirements change…&lt;/p&gt;

&lt;h2&gt;
  
  
  API specification changes
&lt;/h2&gt;

&lt;p&gt;Guardrail makes changing the API specification a breeze. Earlier I said that we were recreating the standard hello world routes provided by the g8 http4s template. But we are missing something, namely, we want the &lt;code&gt;/hello&lt;/code&gt; endpoint to respond with any given name. Let’s change the API specification at&lt;code&gt;src/main/resources/api.yaml&lt;/code&gt; to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openapi: "3.0.0"
info:
  title: http4s Guardrail example
  version: 0.0.1
tags:
  - name: hello
paths:
  /hello:
    get:
      tags: [hello]
      x-scala-package: hello
      operationId: getHello
      summary: Returns a hello message
      parameters:
        - $ref: '#/components/parameters/NameParam'
      responses:
        200:
          description: Hello message
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HelloResponse'
components:
  parameters:
    NameParam:
      name: name
      in: query
      description: Name to greet
      schema:
        type: string
  schemas:
    HelloResponse:
      type: object
      properties:
        message:
          type: string
      required:
        - message
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What changed is that we added a parameter to the &lt;code&gt;/hello&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;If we trigger the code generator again by calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt compile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Guardrail will inform us that we are changing an existing file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning:
  The file ~/Developer/quickstart/target/scala-2.12/src_managed/main/com/example/quickstart/endpoints/hello/Routes.scala contained different content than was expected.

  Existing file: ): F[GetHelloResponse] }\nclass HelloResource[F[_]]
  New file : name: Option[String] = None): F[GetHelloResponse]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Followed by a bunch of compiler errors. This is actually the compiler telling us that we need to change our implementation because it is out of sync with the generated code. Nice. Open&lt;code&gt;src/main/scala/com/example/quickstart/endpoints/HelloHandlerImpl.scala&lt;/code&gt; and replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.quickstart.endpoints.hello

import cats.Applicative
import cats.implicits._
import com.example.quickstart.endpoints.definitions.HelloResponse

class HelloHandlerImpl[F[_] : Applicative]() extends HelloHandler[F] {
  override def getHello(respond: GetHelloResponse.type)(name: Option[String] = None): F[GetHelloResponse] = {
    for {
      message &amp;lt;- s"Hello, ${name.getOrElse("world")}".pure[F]
    } yield respond.Ok(HelloResponse(message))
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now run the application again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sbt run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And once it is running we can try to get a personalized greeting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; curl http://localhost:8080/hello\?name\=Kay
{"message":"Hello, Kay"}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that is how easy it is to update your API specification!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In a few minutes we were able to create a simple REST API server with safely typed endpoints generated from an API specification. Better yet, we now have a basis to build our application on. As we have seen Guardrail makes our lives easier by forcing us to stay true to our API specification.&lt;/p&gt;

&lt;p&gt;Guardrail is production ready IMO but can be rough around the edges sometimes. If you like Guardrail, they are looking for &lt;a href="https://github.com/twilio/guardrail/blob/master/CONTRIBUTING.md"&gt;contributions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find the finished project at &lt;a href="https://github.com/kkreuning/guardrail-http4s-example"&gt;guardrail-http4s-tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>scala</category>
      <category>guardrail</category>
      <category>http4s</category>
    </item>
  </channel>
</rss>
