Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
#200 Restructure http endpoints according to latest design (#203)
Browse files Browse the repository at this point in the history
* Update client to new endpoints

* Update existing endpoints in server

* Implement getExchanges server endpoint

* Pass filter to ExchangeApi.getExchanges

* PUT

* dry

* PUT and other fix

* Fix test
  • Loading branch information
Diane Huxley authored Mar 20, 2024
1 parent d43ff3f commit 926170b
Show file tree
Hide file tree
Showing 14 changed files with 391 additions and 94 deletions.
73 changes: 38 additions & 35 deletions httpclient/src/main/kotlin/tbdex/sdk/httpclient/TbdexHttpClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,6 @@ object TbdexHttpClient {
}
}

private fun sendMessage(pfiDid: String, path: String, requestBody: RequestBody) {

val pfiServiceEndpoint = getPfiServiceEndpoint(pfiDid)
val url = pfiServiceEndpoint + path

val request = buildRequest(url, requestBody)

println("Attempting to send rfq message to: ${request.url}")

executeRequest(request)
}

/**
* Send RFQ message to the PFI.
*
Expand All @@ -95,14 +83,10 @@ object TbdexHttpClient {
validateMessage(rfq)

val pfiDid = rfq.metadata.to
val exchangeId = rfq.metadata.exchangeId

val path = "/exchanges/$exchangeId"

val body: RequestBody = Json.stringify(CreateExchangeRequest(rfq))
.toRequestBody(jsonMediaType)

this.sendMessage(pfiDid, path, body)
this.createExchange(pfiDid, body)
}

/**
Expand All @@ -117,14 +101,27 @@ object TbdexHttpClient {
validateMessage(rfq)

val pfiDid = rfq.metadata.to
val exchangeId = rfq.metadata.exchangeId

val path = "/exchanges/$exchangeId"

val body: RequestBody = Json.stringify(CreateExchangeRequest(rfq, replyTo))
.toRequestBody(jsonMediaType)

this.sendMessage(pfiDid, path, body)
this.createExchange(pfiDid, body)
}

private fun createExchange(pfiDid: String, requestBody: RequestBody) {
val path = "/exchanges"

val pfiServiceEndpoint = getPfiServiceEndpoint(pfiDid)
val url = pfiServiceEndpoint + path

val request = Request.Builder()
.url(url)
.addHeader("Content-Type", JSON_HEADER)
.post(requestBody)
.build()

println("Attempting to send rfq message to: ${request.url}")

executeRequest(request)
}

/**
Expand All @@ -139,12 +136,11 @@ object TbdexHttpClient {

val pfiDid = order.metadata.to
val exchangeId = order.metadata.exchangeId
val path = "/exchanges/$exchangeId/order"

val body: RequestBody = Json.stringify(order)
.toRequestBody(jsonMediaType)

this.sendMessage(pfiDid, path, body)
this.submitMessage(pfiDid, exchangeId, body)
}

/**
Expand All @@ -159,12 +155,28 @@ object TbdexHttpClient {

val pfiDid = close.metadata.to
val exchangeId = close.metadata.exchangeId
val path = "/exchanges/$exchangeId/close"

val body: RequestBody = Json.stringify(close)
.toRequestBody(jsonMediaType)

this.sendMessage(pfiDid, path, body)
this.submitMessage(pfiDid, exchangeId, body)
}

private fun submitMessage(pfiDid: String, exchangeId: String, requestBody: RequestBody) {
val path = "/exchanges/$exchangeId"

val pfiServiceEndpoint = getPfiServiceEndpoint(pfiDid)
val url = pfiServiceEndpoint + path

val request = Request.Builder()
.url(url)
.addHeader("Content-Type", JSON_HEADER)
.post(requestBody)
.build()

println("Attempting to send message to exchange ${exchangeId} to: ${request.url}")

executeRequest(request)
}

/**
Expand Down Expand Up @@ -281,15 +293,6 @@ object TbdexHttpClient {
message.verify()
}

private fun buildRequest(url: String, body: RequestBody): Request {
val request = Request.Builder()
.url(url)
.addHeader("Content-Type", JSON_HEADER)
.post(body)
.build()
return request
}

private fun executeRequest(request: Request) {
val response: Response = client.newCall(request).execute()
if (!response.isSuccessful) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class TbdexHttpClientTest {
assertDoesNotThrow { TbdexHttpClient.createExchange(rfq) }

val request = server.takeRequest()
assertEquals(request.path, "/exchanges/${rfq.metadata.exchangeId}")
assertEquals(request.path, "/exchanges")
assertEquals(
Json.jsonMapper.readTree(request.body.readUtf8()),
Json.jsonMapper.readTree(Json.stringify(mapOf("rfq" to rfq)))
Expand All @@ -111,7 +111,7 @@ class TbdexHttpClientTest {
assertDoesNotThrow { TbdexHttpClient.createExchange(rfq, replyTo) }

val request = server.takeRequest()
assertEquals(request.path, "/exchanges/${rfq.metadata.exchangeId}")
assertEquals(request.path, "/exchanges")
assertEquals(
Json.jsonMapper.readTree(request.body.readUtf8()),
Json.jsonMapper.readTree(Json.stringify(mapOf("rfq" to rfq, "replyTo" to replyTo)))
Expand Down Expand Up @@ -195,7 +195,7 @@ class TbdexHttpClientTest {
assertDoesNotThrow { TbdexHttpClient.submitOrder(order) }

val request = server.takeRequest()
assertEquals(request.path, "/exchanges/${order.metadata.exchangeId}/order")
assertEquals(request.path, "/exchanges/${order.metadata.exchangeId}")
assertEquals(
Json.jsonMapper.readTree(request.body.readUtf8()),
Json.jsonMapper.readTree(Json.stringify(order))
Expand Down Expand Up @@ -253,7 +253,7 @@ class TbdexHttpClientTest {
assertDoesNotThrow { TbdexHttpClient.submitClose(close) }

val request = server.takeRequest()
assertEquals(request.path, "/exchanges/${close.metadata.exchangeId}/close")
assertEquals(request.path, "/exchanges/${close.metadata.exchangeId}")
assertEquals(
Json.jsonMapper.readTree(request.body.readUtf8()),
Json.jsonMapper.readTree(Json.stringify(close))
Expand Down
29 changes: 17 additions & 12 deletions httpserver/src/main/kotlin/tbdex/sdk/httpserver/TbdexHttpServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.response.respond
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.put
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import tbdex.sdk.httpserver.handlers.createExchange
import tbdex.sdk.httpserver.handlers.getExchange
import tbdex.sdk.httpserver.handlers.getExchanges
import tbdex.sdk.httpserver.handlers.getOfferings
import tbdex.sdk.httpserver.handlers.submitClose
import tbdex.sdk.httpserver.handlers.submitMessage
import tbdex.sdk.httpserver.handlers.submitOrder
import tbdex.sdk.httpserver.models.ExchangesApi
import tbdex.sdk.httpserver.models.FakeExchangesApi
Expand Down Expand Up @@ -101,7 +104,7 @@ class TbdexHttpServer(val config: TbdexHttpServerConfig) {
}

route("/exchanges") {
post("/{exchangeId}") {
post {
createExchange(
call = call,
offeringsApi = offeringsApi,
Expand All @@ -110,28 +113,30 @@ class TbdexHttpServer(val config: TbdexHttpServerConfig) {
)
}

post("/{exchangeId}/order") {
submitOrder(
put("/{exchangeId}") {
submitMessage(
call = call,
exchangesApi = exchangesApi,
callback = submitCallbacks.getOrDefault("order", null)
)
}

post("/{exchangeId}/close") {
submitClose(
call = call,
exchangesApi = exchangesApi,
callback = submitCallbacks.getOrDefault("close", null)
)
}

get {
getExchanges(
call,
exchangesApi,
getCallbacks.getOrDefault("exchanges", null),
pfiDid)
pfiDid
)
}

get("/{exchangeId}") {
getExchange(
call,
exchangesApi,
getCallbacks.getOrDefault("exchange", null),
pfiDid
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package tbdex.sdk.httpserver.handlers

import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.ApplicationCall
import io.ktor.server.response.respond
import tbdex.sdk.httpclient.RequestToken
import tbdex.sdk.httpclient.models.ErrorDetail
import tbdex.sdk.httpserver.models.ErrorResponse
import tbdex.sdk.httpserver.models.ExchangesApi
import tbdex.sdk.httpserver.models.GetCallback
import tbdex.sdk.httpserver.models.GetExchangesFilter
import tbdex.sdk.protocol.models.Message

/**
* Get exchanges response
*
* @property data list of exchanges (list of tbdex messages)
*/
class GetExchangeResponse(
val data: List<Message>?
)

/**
* Get exchanges
*
* @param call Ktor server application call
* @param exchangesApi Exchanges API interface
* @param callback Callback function to be invoked
*/
@Suppress("SwallowedException")
suspend fun getExchange(
call: ApplicationCall,
exchangesApi: ExchangesApi,
callback: GetCallback?,
pfiDid: String
) {
val authzHeader = call.request.headers[HttpHeaders.Authorization]
if (authzHeader == null) {
call.respond(
HttpStatusCode.Unauthorized,
ErrorResponse(
errors = listOf(
ErrorDetail(
detail = "Authorization header required"
)
)
)
)
return
}

val arr = authzHeader.split("Bearer ")
if (arr.size != 2) {
call.respond(
HttpStatusCode.Unauthorized,
ErrorResponse(
errors = listOf(
ErrorDetail(
detail = "Malformed Authorization header. Expected: Bearer TOKEN_HERE"
)
)
)
)
return
}

val token = arr[1]
val requesterDid: String
try {
requesterDid = RequestToken.verify(token, pfiDid)
} catch (e: Exception) {
call.respond(
HttpStatusCode.Unauthorized,
ErrorResponse(
errors = listOf(
ErrorDetail(
detail = "Could not verify Authorization header."
)
)
)
)
return
}

val exchanges = exchangesApi.getExchange(call.parameters["exchangeId"]!!)

if (callback != null) {
// TODO: figure out what to do with callback result. should we pass through the exchanges we've fetched
// and allow the callback to modify what's returned? (issue #10)
val result = callback.invoke(call, GetExchangesFilter())
}

call.respond(HttpStatusCode.OK, GetExchangeResponse(data = exchanges))
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ suspend fun getExchanges(
return
}

val exchanges = exchangesApi.getExchanges()
val ids = call.request.queryParameters.getAll("id") ?: emptyList()
val exchanges = exchangesApi.getExchanges(GetExchangesFilter(ids, requesterDid))

if (callback != null) {
// TODO: figure out what to do with callback result. should we pass through the exchanges we've fetched
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,9 @@ import tbdex.sdk.protocol.models.MessageKind
suspend fun submitClose(
call: ApplicationCall,
exchangesApi: ExchangesApi,
callback: SubmitCallback?
callback: SubmitCallback?,
message: Close,
) {
val message: Close?

try {
message = Message.parse(call.receiveText()) as Close
} catch (e: Exception) {
val errorDetail = ErrorDetail(detail = "Parsing of TBDex message failed: ${e.message}")
val errorResponse = ErrorResponse(listOf(errorDetail))
call.respond(HttpStatusCode.BadRequest, errorResponse)
return
}

val exchangeId = message.metadata.exchangeId.toString()
val exchange: List<Message>
Expand Down
Loading

0 comments on commit 926170b

Please sign in to comment.