Skip to content

Commit 990d9d9

Browse files
committed
Implement bank http api
Use http4k library to implement http wrapper to the bank application. This represent an adapter to the Bank interface, an implementation of the driving port that defines the bank capabilities, and it trigger actions on the application, the BankService. Alongside the actual http application, create a client that can be used externally to speak to the api, so that urls don't have to leak. Even better, the client can implement the Bank contract so that tests are implemented based on it. Include 2 levels of testing, a simple in-memory test and an integration test that spins up an http server. As there's no intention to use a db or any other type of permanent storage for this simple example, move the in-memory implementation of the repository to production code so that it can be re-used.
1 parent 3740252 commit 990d9d9

7 files changed

Lines changed: 96 additions & 1 deletion

File tree

domain/src/testFixtures/kotlin/lmirabal/bank/data/InMemoryBankAccountRepository.kt renamed to domain/src/main/kotlin/lmirabal/bank/data/InMemoryBankAccountRepository.kt

File renamed without changes.

http/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
dependencies {
2+
implementation project(':domain')
3+
implementation platform('org.http4k:http4k-bom:3.284.0')
4+
implementation 'org.http4k:http4k-core'
5+
implementation 'org.http4k:http4k-format-jackson'
6+
7+
testImplementation testFixtures(project(":domain"))
8+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package lmirabal.bank.http
2+
3+
import lmirabal.bank.Bank
4+
import lmirabal.bank.BankService
5+
import lmirabal.bank.data.InMemoryBankAccountRepository
6+
import lmirabal.bank.model.BankAccount
7+
import org.http4k.core.Body
8+
import org.http4k.core.HttpHandler
9+
import org.http4k.core.Method.GET
10+
import org.http4k.core.Method.POST
11+
import org.http4k.core.Response
12+
import org.http4k.core.Status.Companion.OK
13+
import org.http4k.core.with
14+
import org.http4k.format.Jackson.auto
15+
import org.http4k.routing.bind
16+
import org.http4k.routing.routes
17+
18+
fun bankHttp() = bankHttp(BankService(InMemoryBankAccountRepository()))
19+
20+
internal const val BANK_ACCOUNTS_URL = "/bank/accounts"
21+
internal val bankAccountLens = Body.auto<BankAccount>().toLens()
22+
internal val bankAccountListLens = Body.auto<List<BankAccount>>().toLens()
23+
24+
internal fun bankHttp(bank: Bank): HttpHandler {
25+
return routes(
26+
BANK_ACCOUNTS_URL bind routes(
27+
POST to { Response(OK).with(bankAccountLens of bank.createAccount()) },
28+
GET to { Response(OK).with(bankAccountListLens of bank.listAccounts()) }
29+
)
30+
)
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package lmirabal.bank.http
2+
3+
import lmirabal.bank.Bank
4+
import lmirabal.bank.model.BankAccount
5+
import org.http4k.core.HttpHandler
6+
import org.http4k.core.Method.GET
7+
import org.http4k.core.Method.POST
8+
import org.http4k.core.Request
9+
10+
class BankHttpClient(val http: HttpHandler) : Bank {
11+
override fun createAccount(): BankAccount {
12+
val response = http(Request(POST, BANK_ACCOUNTS_URL))
13+
return bankAccountLens(response)
14+
}
15+
16+
override fun listAccounts(): List<BankAccount> {
17+
val response = http(Request(GET, BANK_ACCOUNTS_URL))
18+
return bankAccountListLens(response)
19+
}
20+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package lmirabal.bank.http
2+
3+
import lmirabal.bank.BankTest
4+
import org.http4k.client.JavaHttpClient
5+
import org.http4k.core.Uri
6+
import org.http4k.core.then
7+
import org.http4k.filter.ClientFilters.SetBaseUriFrom
8+
import org.http4k.server.SunHttp
9+
import org.http4k.server.asServer
10+
import org.junit.jupiter.api.AfterEach
11+
import org.junit.jupiter.api.BeforeEach
12+
13+
class BankHttpIntegrationTest : BankTest() {
14+
private val server = bankHttp().asServer(SunHttp())
15+
override val bank = BankHttpClient(
16+
SetBaseUriFrom(Uri.of("http://localhost:${server.port()}")).then(JavaHttpClient())
17+
)
18+
19+
@BeforeEach
20+
fun setUp() {
21+
server.start()
22+
}
23+
24+
@AfterEach
25+
fun tearDown() {
26+
server.stop()
27+
}
28+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package lmirabal.bank.http
2+
3+
import lmirabal.bank.BankTest
4+
5+
class BankHttpTest : BankTest() {
6+
override val bank = BankHttpClient(bankHttp())
7+
}

settings.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
rootProject.name = 'bank'
22

3-
include ':domain'
3+
include ':domain'
4+
include ':http'

0 commit comments

Comments
 (0)