org.http4k.serverless.OpenWhiskFunction.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http4k-serverless-openwhisk Show documentation
Show all versions of http4k-serverless-openwhisk Show documentation
Http4k Serverless support for Apache OpenWhisk
The newest version!
package org.http4k.serverless
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import org.http4k.base64DecodedByteBuffer
import org.http4k.base64Encode
import org.http4k.core.Body
import org.http4k.core.Filter
import org.http4k.core.Method
import org.http4k.core.Request
import org.http4k.core.RequestContexts
import org.http4k.core.Response
import org.http4k.core.then
import org.http4k.filter.ServerFilters.CatchAll
import org.http4k.filter.ServerFilters.InitialiseRequestContext
import org.http4k.serverless.DetectBinaryBody.Companion.NonBinary
import java.util.Locale.getDefault
const val OW_REQUEST_KEY = "HTTP4K_OW_REQUEST"
class OpenWhiskFunction(
appLoader: AppLoaderWithContexts,
private val detectBinaryBody: DetectBinaryBody = NonBinary
) : (JsonObject) -> JsonObject {
constructor(
input: AppLoader,
detectBinaryBody: DetectBinaryBody = NonBinary
) : this(AppLoaderWithContexts { env, _ -> input(env) }, detectBinaryBody)
private val contexts = RequestContexts("openwhisk")
private val app = appLoader(System.getenv(), contexts)
override fun invoke(request: JsonObject) =
CatchAll()
.then(InitialiseRequestContext(contexts))
.then(AddOpenWhiskRequest(request, contexts))
.then(app)
.invoke(request.asHttp4k()).toGson()
private fun Response.toGson() = JsonObject().apply {
addProperty("statusCode", status.code)
addProperty(
"body",
if (detectBinaryBody.isBinary(this@toGson)) body.payload.base64Encode() else bodyString()
)
add("headers", JsonObject().apply {
headers.forEach {
addProperty(it.first, it.second)
}
})
}
private fun JsonObject.asHttp4k(): Request {
val baseRequest = Request(
Method.valueOf(getAsJsonPrimitive("__ow_method").asString.uppercase(getDefault())),
stringOrEmpty("__ow_path") + if (has("__ow_query")) "?" + get("__ow_query").asJsonPrimitive.asString else ""
).body(stringOrEmpty("__ow_body"))
val withQueries = getQueries().fold(baseRequest) { acc, next ->
acc.query(next.key, next.value.takeIf { it.isJsonPrimitive }?.asJsonPrimitive?.asString ?: "")
}
val fullRequest = mapFrom("__ow_headers").fold(withQueries) { acc, next ->
acc.header(next.key, next.value.asJsonPrimitive.asString)
}
return if (detectBinaryBody.isBinary(fullRequest)) fullRequest.body(
Body(fullRequest.body.payload.base64DecodedByteBuffer())
)
else fullRequest
}
}
private fun AddOpenWhiskRequest(request: JsonElement, contexts: RequestContexts) = Filter { next ->
{
contexts[it][OW_REQUEST_KEY] = request
next(it)
}
}
private fun JsonObject.getQueries() = entrySet().filterNot { it.key.startsWith("__ow_") }
private fun JsonObject.mapFrom(key: String) =
get(key)?.takeIf { get(key).isJsonObject }?.asJsonObject?.entrySet() ?: emptySet()
private fun JsonObject.stringOrEmpty(key: String) = get(key)?.takeIf { get(key).isJsonPrimitive }?.asString ?: ""