Closed AndrewBoryk closed 2 weeks ago
Here is an example of what I am attempting to send:
let payload = TwitchTokenPayload(client_id: REDACTED,
client_secret: REDACTED,
grant_type: "client_credentials")
let response = try? await req.client.post("https://id.twitch.tv/oauth2/token", content: payload)
And seems like the body being sent in the request is always empty
@AndrewBoryk you can use the beforeSend
closure:
let response = try? await req.client.post("https://id.twitch.tv/oauth2/token", content: payload) { outgoingReq in
try outgoingReq.content.encode(payload)
}
@0xTim Yup, I tried that as well, that still wouldn't send as content is not passed through to the ClientRequest
It is, on line 69 of the code you linked above
Actually yes, sorry you are correct, although I still attempted that for it to not work
@0xTim Still no dice.
For context TwitchTokenPayload
:
struct TwitchTokenPayload: Content {
let client_id: String
let client_secret: String
let grant_type: String
}
Is there a quick method for me to be able to log all outbound requests from the client?
How about a breakpoint in line 73 from the link above and printing the request
I decoded and logged the outboundRequest.content right after, and all the data I intended on sending is in there.
Went a little deeper and I see that some body is present, but not sure if it is getting lost along the way. Would be odd to think that it would be? Not sure the best method for decoding in console
TwitchTokenPayload(client_id: "REDACTED", client_secret: "REDACTED", grant_type: "client_credentials")
This is me logging the decoded content.
Is there a place where I could log the data in the body before it is sent? Or a curl for the request? Maybe something is getting injected into body, but somewhere along the way it becomes malformed. Hard to debug without being able to peer into the contents. Maybe something to do with buffer capacity? And data maybe getting cut off?
Okay, I was able to get it to work. It took a whole bunch of playing around on Postman to recreate the issue.
So apparently the .json
format was not being received by twitch as json format, instead of was being received as plain text. Not sure why. Changing the format to .urlEncodedForm
worked.
So apparently the
.json
format was not being received by twitch as json format, instead of was being received as plain text. Not sure why. Changing the format to.urlEncodedForm
worked.
Try to provide your own HTTP headers along with request, it may help:
private var headers: HTTPHeaders {
var headers = HTTPHeaders()
headers.add(name: .contentType, value: "application/json")
return headers
}
Usage:
let response = try await req.client.send(.POST, headers: headers, to: <URI>) { outgoingReq in
try outgoingReq.content.encode(payload, as: .json)
}
@AndrewBoryk Also, you may use the following helper functions:
func printHdrs(req: Vapor.Request) {
print(req.headers.map { $0 }.map { "\($0.name): \($0.value)\n" }.joined())
}
func printClientHdrs(req: Vapor.ClientRequest) {
print(req.headers.map { $0 }.map { "\($0.name): \($0.value)\n" }.joined())
}
func printReq(req: Vapor.Request) {
let tpl = """
== <REQUEST> ======================
\(req.description)
== </REQUEST> =====================
"""
print(tpl)
}
func printClientReq(req: Vapor.ClientRequest) {
let byteBufferString = req.body?.string ?? ""
print("== <CLIENT_REQUEST> ===============")
printClientHdrs(req: req)
print("\n", byteBufferString)
print("== </CLIENT_REQUEST> ==============")
}
func printRes(res: Vapor.Response) {
let tpl = """
== <RESPONSE> =====================
\(res.description)
== </RESPONSE> ====================
"""
print(tpl)
}
func printClientRes(res: Vapor.ClientResponse) {
let tpl = """
== <CLIENT_RESPONSE> ==============
\(res.description)
== </CLIENT_RESPONSE> =============
"""
print(tpl)
}
Assuming you're using Content
then that will add the application/json
headers. Given this is an OAuth endpoint I expect Twitch requires it to be URL Form Encoded. You can set this with:
struct TwitchTokenPayload: Content {
static let defaultContentType = .urlEncodedForm
let client_id: String
let client_secret: String
let grant_type: String
}
Vapor will encode that correctly and set the correct headers
I'm going to close this now as I believe it's fixed. Feel free to reopen if it's still an issue!
I was able to reproduce by removing Content-Type from the headers in postman. I am not sure why Content-Type would not be sent correctly, maybe some strange behavior with how headers inject?
Just was strange to me that with Content-Type and setting for it to encode as .json that it wouldn't do so... very strange. Idk if there is something worth looking at here
Strange that it worked as json in Postman, maybe Postman is doing some magic under the hood
https://github.com/vapor/vapor/blob/1310c6f5462e23bca08fcf7c26448891a4908294/Sources/Vapor/Client/Client.swift#L67
I'm attempting to make a POST request to an external API. When making the post request on the client, I was noticing that I'd get an error message back that I wasn't sending the required fields in the request body.
Then tracing the request, I noticed this line was always sending body as
nil
, and so the content that is being encoded in the request is never getting forwarded along.