All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.http4k.serverless.OpenWhiskFunction.kt Maven / Gradle / Ivy

There is a newer version: 5.31.0.0
Show 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 ?: ""




© 2015 - 2024 Weber Informatics LLC | Privacy Policy