-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adding replyTo
field in http request body to submit RFQ
#140
Conversation
…f exists). wrote tests for client change. rename submitrfq handler to createexchange httpserver handler. checking validity of url in the handler. wrote test for handler change
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #140 +/- ##
==========================================
+ Coverage 76.19% 77.63% +1.43%
==========================================
Files 32 33 +1
Lines 752 778 +26
Branches 77 74 -3
==========================================
+ Hits 573 604 +31
Misses 133 133
+ Partials 46 41 -5
|
* @throws TbdexResponseException for request or response errors. | ||
*/ | ||
fun sendMessage(message: Message) { | ||
fun sendMessage(sendMessageRequest: SendMessageRequest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reads like javascript. We should check at compile-time that replyTo
is only present with RFQs. Currently, this does the check at runtime. I'm wondering if there's a more kotlin-idiomatic way to write this.
What do you think of separating the methods?
// Sends messages, including RFQs, but doesn't support replyTo`
sendMessage(message: Message)
// Sends only RFQs and supports replyTo
sendRfq(rfq: Rfq, replyTo: string?)
Or maybe overloaded methods if you want to keep the name sendMessage
for both.
// Sends messages, including RFQs, but doesn't support replyTo`
sendMessage(message: Message)
// Sends only RFQs and supports replyTo
sendMessage(rfq: Rfq, replyTo: string?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i did sendMessage(message:Message, replyTo: String? = null)
, since sendMessage() is used anytime the client is sending any tbdex message. i think the second option can also work...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wondering what we want the dev ex to be like. should we separate it out at the method level, or should we let the client just use one method and this method takes care of the validation / inclusion of replyTo
field in the request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussed with @diehuxx - going with the second approach, with sendMessage(rfq: Rfq, replyTo: string)
for the overloaded method.
@@ -99,7 +99,7 @@ class TbdexHttpServer(private val config: TbdexHttpServerConfig) { | |||
|
|||
route("/exchanges") { | |||
post("/{exchangeId}/rfq") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update endpoint as per spec change
https://github.com/TBD54566975/tbdex/pull/222/files#diff-1ab7678648ffe33c3535373210080ab41cd2c38573890fdfcf008700ef14c3c7R279
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. just a side q - would we leave the other endpoints as /exchanges/{exchangeId}/order|close
?
httpserver/src/main/kotlin/tbdex/sdk/httpserver/handlers/CreateExchange.kt
Outdated
Show resolved
Hide resolved
httpserver/src/main/kotlin/tbdex/sdk/httpserver/handlers/CreateExchange.kt
Outdated
Show resolved
Hide resolved
import tbdex.sdk.protocol.serialization.Json | ||
import kotlin.test.assertContains | ||
import kotlin.test.assertEquals | ||
|
||
class SubmitRfqTest : ServerTest() { | ||
class CreateExchangeTest : ServerTest() { | ||
@Test | ||
fun `returns BadRequest if no request body is provided`() = runBlocking { | ||
val response = client.post("/exchanges/123/rfq") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update endpoints in this file as per spec
https://github.com/TBD54566975/tbdex/pull/222/files#diff-1ab7678648ffe33c3535373210080ab41cd2c38573890fdfcf008700ef14c3c7R279
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think i'd like to hold off on updating the endpoints until we have the new tickets / PRs that phoebe referenced in this comment to update client and server code that incorporates the new endpoint style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually i should just get rid of the /rfq
bit since we've decided that can go, but the one up the air is whether /{exchangeId}
should go also. updating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
call.respond(HttpStatusCode.BadRequest, errorResponse) | ||
return | ||
} | ||
|
||
try { | ||
exchangesApi.getExchange(message.metadata.exchangeId.toString()) | ||
val errorDetail = ErrorDetail(detail = "RFQ already exists.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tangential to the replyTo
stuff, but can you update the catch (_: Exception)
below to catch (_: NoSuchElementException)
and add comment // exchangesApi.getExchange throws if no existing exchange is found
. For a sec I was pretty confused why we were swallowing an error so egregiously.
Further musings: maybe this isn't the most graceful API for ExchangeApi
. Personally I would return an empty list rather than throw
. But that's a separate PR if we decide to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed - yea, this try catch is a bit confusing!
in this request handler to create exchange, we want to make sure that exchangesApi.getExchange(exchangeId)
does not return an exchange.
this try catch is actually hoping an NoSuchElementException
is thrown when an exchange with the exchangeId is not found - which is what we want, because we want to create a new exchange
as you said, we should probably return an empty list if an exchange with the exchangeId is not found instead of throwing an exception.
…eExchange.kt Co-authored-by: Diane Huxley <dhuxley@tbd.email>
…eExchange.kt Co-authored-by: Diane Huxley <dhuxley@tbd.email>
…es Rfq message with a replyTo field
replyTo
field in http request body to submit RFQ
@@ -84,20 +87,41 @@ object TbdexHttpClient { | |||
val pfiServiceEndpoint = getPfiServiceEndpoint(pfiDid) | |||
val url = "$pfiServiceEndpoint/exchanges/$exchangeId/$kind" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If message
is a Rfq
, this will send to the wrong endpoint. We need to omit $kind
if kind == 'rfq'
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
absolutely correct, ty!
* @property rfq Rfq tbdex message received. | ||
* @property replyTo Optional URL to be included in the request to create exchange. | ||
*/ | ||
class CreateExchangeRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is only used in tests, can we move it into test/
directory? Or is it intended to be used by consumers of this library in some way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we do use this in Tbdexhttpclient#sendMessage method where i'm passing in rfq
and replyTo
(the new overloaded method)
val body: RequestBody = Json.stringify(CreateExchangeRequest(message, replyTo))
.toRequestBody(jsonMediaType)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good work @jiyoontbd !
* @throws TbdexResponseException for request or response errors. | ||
* @param message The message to send. | ||
* | ||
* @throws TbdexResponseException for response errors. | ||
*/ | ||
fun sendMessage(message: Message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jiyoontbd what do you think about having a separate fun createExchange(rfq: RFQ, replyTo: String?)
function for creating an exchange?
The reason being, there are now two functions that can be called to create an exchange. This one can accept messages of any type (including RFQ), but does not support replyTo
URL. The other is also called sendMessage
, but you can actually only send an RFQ, not just any message type.
You would essentially have one client method for creating an exchange, which can have a replyTo
or not (optional), and a different method for all subsequent messages.
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea. so you're saying we'd call createExchange()
for sending RFQ (with or without replyTo), and sendMessage()
for everything else? i'll give that a go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wish we could type guard for sendMessage()
to prevent RFQ from being passed in as message in kotlin. so without the type guard, i'd have to check the kind
and throw IllegalArgumentException. i'm not sure if i like that dev ex. i suppose we could explicitly say pls don't use this method if you're sending an RFQ!!11
in the ktdocs.
i'm leaning towards keeping the overloaded sendMessage()
, would love to hear @diehuxx 's thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i suppose we could explicitly say pls don't use this method if you're sending an RFQ!!11 in the ktdocs.
I would really prefer not to resort to that. IMO as long as we're leveraging the type system to enforce correct message types and options at compile-time, I can be flexible about how we name methods.
If I were writing this, I would keep the overloaded sendMessage
AND add a createExchange
endpoint which takes an RFQ and a replyTo
. Admittedly, my ruby background is showing in this suggestion, as aliasing methods is common in ruby.
Feel free to take this idea or not. As long as the type system can enforce our choices, @jiyoontbd I trust your judgement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm good with that. the code editor should show the difference between the two. commit here
@@ -208,4 +237,25 @@ object TbdexHttpClient { | |||
errors = errors | |||
) | |||
} | |||
|
|||
private fun validateMessage(message: Message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
http-client:
Add
replyTo
field to send message request if it was included with RFQ message.Updated endpoint per spec change.
Created an overloaded method to help elucidate between sendMessage() that sends a non-rfq message or an rfq message without a
replyTo
field, and sendMessage() that sends specifically an rfq message with areplyTo
fieldhttp-server
Updated endpoint per spec change. Now anticipating an optional
replyTo
field included in the request JSON.