Skip to content
This repository was archived by the owner on Sep 21, 2023. It is now read-only.

Commit

Permalink
Refactor to be generic to the server type
Browse files Browse the repository at this point in the history
  • Loading branch information
howardjohn committed May 7, 2018
1 parent e62325b commit ec4de8b
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 235 deletions.
2 changes: 0 additions & 2 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,3 @@ rewrite.rules = [RedundantBraces, SortImports, PreferCurlyFors]

docstrings = JavaDoc
importSelectors = singleLine

newlines.alwaysBeforeTopLevelStatements = true
49 changes: 33 additions & 16 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
lazy val commonSettings = Seq(
organization := "io.github.howardjohn",
scalaVersion := "2.12.4"
scalaVersion := "2.12.6"
)

lazy val core = project
lazy val root = project
.in(file("."))
.settings(commonSettings)
.settings(noPublishSettings)
.aggregate(http4s, exampleHttp4s)

lazy val CirceVersion = "0.9.0"
lazy val ScalaTestVersion = "3.0.4"

lazy val common = project
.in(file("common"))
.settings(commonSettings)
.settings(noPublishSettings)
.settings(
moduleName := "common",
libraryDependencies ++=
Seq(
"io.circe" %% "circe-generic" % CirceVersion,
"io.circe" %% "circe-parser" % CirceVersion,
"org.scalatest" %% "scalatest" % ScalaTestVersion % "test"
)
)

lazy val http4s = project
.in(file("http4s-lambda"))
.settings(publishSettings)
.settings(commonSettings)
Expand All @@ -13,37 +36,31 @@ lazy val core = project
moduleName := "http4s-lambda",
scalacOptions ++= Seq("-Ypartial-unification"),
libraryDependencies ++= {
val Http4sVersion = "0.18.0-M8"
val CirceVersion = "0.9.0"
val Http4sVersion = "0.18.10"
Seq(
"org.http4s" %% "http4s-core" % Http4sVersion,
"org.http4s" %% "http4s-circe" % Http4sVersion,
"io.circe" %% "circe-parser" % CirceVersion,
"io.circe" %% "circe-generic" % CirceVersion,
"org.scalatest" %% "scalatest" % "3.0.4" % "test",
"org.scalatest" %% "scalatest" % ScalaTestVersion % "test",
"org.http4s" %% "http4s-dsl" % Http4sVersion % "test"
)
}
)
.dependsOn(common)

lazy val example = project
.in(file("example"))
lazy val exampleHttp4s = project
.in(file("example-http4s"))
.settings(noPublishSettings)
.settings(commonSettings)
.settings(
moduleName := "example",
assemblyJarName in assembly := "example.jar",
moduleName := "example-http4s",
assemblyJarName in assembly := "example-http4s.jar",
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-dsl" % "0.18.0-M8"
)
)
.dependsOn(core)

lazy val root = project
.in(file("."))
.settings(commonSettings)
.settings(noPublishSettings)
.aggregate(core, example)
.dependsOn(http4s)

lazy val noPublishSettings = Seq(
publish := {},
Expand Down
41 changes: 41 additions & 0 deletions common/src/main/scala/io/github/howardjohn/lambda/Encoding.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.github.howardjohn.lambda

import io.circe
import io.circe.generic.auto._
import io.circe.parser.decode
import io.circe.syntax._

object Encoding {
case class ProxyRequest(
httpMethod: String,
path: String,
headers: Option[Map[String, String]],
body: Option[String],
queryStringParameters: Option[Map[String, String]]
)

case class ProxyResponse(
statusCode: Int,
headers: Map[String, String],
body: String
)

def parseRequest(rawInput: String): Either[circe.Error, ProxyRequest] = decode[ProxyRequest](rawInput)

def encodeResponse(response: ProxyResponse): String =
response.asJson.noSpaces

def reconstructPath(request: ProxyRequest): String = {
val requestString = request.queryStringParameters
.map {
_.map {
case (k, v) => s"$k=$v"
}.mkString("&")
}
.map { qs =>
if (qs.isEmpty) "" else "?" + qs
}
.getOrElse("")
request.path + requestString
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
package io.github.howardjohn.http4s.lambda
package io.github.howardjohn.lambda

import java.io.{InputStream, OutputStream}
import java.nio.charset.StandardCharsets

import cats.effect.IO

import scala.io.Source

object IOStreamOps {
object StreamOps {
implicit class InputStreamOps(val is: InputStream) extends AnyVal {

def consume(): IO[String] = IO {
def consume(): String = {
val contents = Source.fromInputStream(is).mkString
is.close()
contents
}

}

implicit class OutputStreamOps(val os: OutputStream) extends AnyVal {

def writeAndClose(contents: String): IO[Unit] = IO {
def writeAndClose(contents: String): Unit = {
os.write(contents.getBytes(StandardCharsets.UTF_8))
os.close()
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.howardjohn.lambda

import java.io.{InputStream, OutputStream}

import io.github.howardjohn.lambda.Encoding._
import io.github.howardjohn.lambda.StreamOps._

trait LambdaHandler {
def handleRequest(request: ProxyRequest): ProxyResponse

def handle(is: InputStream, os: OutputStream): Unit = {
val rawInput = is.consume()
val request = parseRequest(rawInput).fold(
e => throw e,
identity
)
val rawResponse = handleRequest(request)
val response = encodeResponse(rawResponse)
os.writeAndClose(response)
}
}
25 changes: 25 additions & 0 deletions example-http4s/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
service: example-http4s

provider:
name: aws
runtime: java8
region: us-west-2
stage: dev

package:
artifact: target/scala-2.12/example-http4s.jar

functions:
api:
handler: io.github.howardjohn.lambda.http4s.example.Route$EntryPoint::handle
events:
- http:
path: "{proxy+}"
method: any
cors: true
# Uncomment below to keep the application warm
# - schedule:
# rate: rate(4 minutes)
# input:
# httpMethod: GET
# path: /hello/keepWarm
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package io.github.howardjohn.http4s.lambda.example
package io.github.howardjohn.lambda.http4s.example

import cats.effect.IO
import io.github.howardjohn.lambda.http4s.Http4sLambdaHandler
import org.http4s.HttpService
import org.http4s.circe.jsonOf
import io.circe.generic.auto._
import io.github.howardjohn.http4s.lambda.LambdaHandler
import org.http4s._
import org.http4s.circe._
import org.http4s.dsl.io._

object Route {
implicit val InputDecoder = jsonOf[IO, Input]
implicit val inputDecoder = jsonOf[IO, Input]

// Set up the route
val service: HttpService[IO] = HttpService[IO] {
Expand All @@ -23,7 +23,7 @@ object Route {

// Define the entry point for Lambda
// Referenced as ` io.github.howardjohn.http4s.lambda.example$Route::handler` in Lambda
class EntryPoint extends LambdaHandler(service)
class EntryPoint extends Http4sLambdaHandler(service)

case class Input(
name: String,
Expand Down
24 changes: 0 additions & 24 deletions example/serverless.yml

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit ec4de8b

Please sign in to comment.