Concept: API Clients

Each system API Client is modelled as a single function with arity 1 (that is it takes only a single parameter) returning a Result4k Success/Failure monad type), which is known as an Action. The Client is responsible for managing the overall protocol with the remote system. There are also a set of extension methods generated to provide a more traditional function-based version of the same interface.

The module naming scheme for API Clients is:

org.http4k:http4k-connect-{vendor}-{system}

Action classes are responsible for constructing the HTTP requests and unmarshalling their responses into the http4k-connect types. There are lots of common actions built-in, but you can provide your own by simply implementing the relevant Action interface. The recommended pattern in http4k-connect is to use a Result monad type (we use Result4k) to represent the result type, but you can use anything to suit your programming model.

Kotlin system_interface.kt
package content.ecosystem.connect.concepts.clients

import dev.forkhandles.result4k.Result
import org.http4k.connect.Action
import org.http4k.connect.RemoteFailure

// Generic system interface
interface Example {
   operator fun <R : Any> invoke(request: ExampleAction<R>): Result<R, RemoteFailure>

   companion object
}

// System-specific action
interface ExampleAction<R> : Action<Result<R, RemoteFailure>>

// Action and response classes
data class Echo(val value: String) : ExampleAction<Echoed> {
    override fun toRequest() = org.http4k.core.Request(org.http4k.core.Method.GET, "/echo").body(value)
    override fun toResult(response: org.http4k.core.Response) = dev.forkhandles.result4k.Success(Echoed(response.bodyString()))
}
data class Echoed(val value: String)

// Traditional function helpers
fun Example.echo(value: String): Result<Echoed, RemoteFailure> = this(Echo(value))

Example usage

Kotlin example_usage.kt
package content.ecosystem.connect.concepts.clients

import dev.forkhandles.result4k.Result
import org.http4k.connect.RemoteFailure
import org.http4k.core.HttpHandler
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK

// constructing and using the clients
val httpHandler: HttpHandler = { Response(OK) }
//val example = Example.Http(httpHandler)

//val echoed: Result<Echoed, RemoteFailure> = example.echo("hello world")
// or...
//val alsoEchoed: Result<Echoed, RemoteFailure> = example(Echo("hello world"))
scarf