1

I am working on sending data to Spiff (https://app.getguru.com/card/iXpEBagT/How-to-send-data-to-Spiffs-API) but I'm having trouble getting the headers they want added. From the linked site here is their example:

curl -X PUT -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'Signature: t=1606767397,v1=DIGEST' -d '{"Id":"Thor","nickname":"Strongest Avenger"}' https://app.spiff.com/_webhook/mapping/123

So using VB.Net (Core 6) I'm attempting to do this with a HttpClient but keep getting a Status Code 400: Bad Response. Here is my sample code:

Public Async Function SendRequest(uri As Uri, data As String, signature As String) As Task(Of JsonObject)
    Dim httpClient = New HttpClient()
    httpClient.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
    httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Signature", signature)
    Dim content = New StringContent(data, Encoding.UTF8, "application/json")
    Dim response = New HttpResponseMessage
    response = Await httpClient.PutAsync(uri, content)
    response.EnsureSuccessStatusCode()
End Function

I'm guessing the BadRequest is due to the extra Signature header but I can't figure out what I'm doing wrong. I'm using the default request headers since the program executes, sends the data, then ends so I have no need to keep the httpclient around or reuse it. I tried using a WebRequest but on top of being depreciated I had the same issues. I thought maybe I'm messing up the signature as they use HMAC verification but I'm pretty sure that is correct also based on their documentation:

Private Sub SendDataButton_Click(sender As Object, e As EventArgs) Handles SendDataButton.Click
        Dim myKey As String = HMACKeyTextBox.Text
        Dim myUnixTime As Long = New DateTimeOffset(Date.Now.ToUniversalTime).ToUnixTimeSeconds
        Dim myData as String = "{""PrimaryKey"":""2""}"
        Dim myPreDigestString = $"{myUnixTime}.{myData}"
        Dim myDigest As String = GetHMACSHA256Hash(myPreDigestString, myKey)
        Dim myURI As New Uri(URITextBox.Text)
        Dim mySignature As String = $"t={myUnixTime},v1={myDigest}"
        Dim result_post = SendRequest(myURI, myData, mySignature)
End Sub

Which is based on some other posts on here. Am I adding the headers wrong or does this look correct? The test data is what they are expecting from me for testing, a single record setting a PrimaryKey. I should be getting back a 200 OK.

ADY
  • 101
  • 1
  • 9
  • 1
    I cannot say about your *signature*, but the request appears to be a PUT not a POST, so setup a HttpRequestMessage with `HttpMethod.Put`. -- `SendRequest()` is not returning anything. -- Using `TryAddWithoutValidation()`, you're supposed to verify that the method returned `true`. -- You're not disposing of the HttpClient object. -- When you debug this code, check what Headers have been set before the request is sent. -- See also [DateTimeOffset.ToUnixTimeMilliseconds](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset.tounixtimemilliseconds) – Jimi Feb 11 '22 at 17:56
  • You are correct, I switched it to a Put with the same bad request returned. Also updated the unix seconds code per your suggestion. Headers look ok but I could be missing something (sensitive stuff removed): {Method: PUT, RequestUri: 'https://app.spiff.com/_webhook/mapping/(removed)', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Accept: application/json Signature: t=$1644605617.4956605,v1=$(removed) Content-Type: application/json; charset=utf-8 Content-Length: 18}}. – ADY Feb 11 '22 at 19:04
  • 1
    The Unix time in seconds doesn't look right. It should be a `long`, as `1644606674`. Where is `$` coming from? Unless you wrote that part of the code wrong in your comment. I don't see that in the sample code of your service. – Jimi Feb 11 '22 at 19:12
  • Nope, they shouldn't be there and you are also correct on the time. Too much copy and pasting. Code fixed and now it looks better but still bad request: Headers: { Accept: application/json Signature: t=1644607150,v1=f4ba8947621cfa8c929ddb7797873d0ef18183c5a0c46f319ac37ef3fd0ea006 Content-Type: application/json; charset=utf-8 Content-Length: 18 } – ADY Feb 11 '22 at 19:20
  • 1
    All right, now fix the JSON, since single quotes are not necessarily accepted by all parsers. I should appear as `{"PrimaryKey":2}` or `{"PrimaryKey":"2"}`, depending on the Type of `PrimaryKey`. Possibly, use a serializer to generate your JSON. -- If this also doesn't allow a successful response, then check the code that generates your *signature*. – Jimi Feb 11 '22 at 19:40
  • I think that worked, I got a 200 OK back. I'll contact them to verify they got my simplistic data. Thank-you. – ADY Feb 11 '22 at 19:46
  • Does this answer your question? [Adding Http Headers to HttpClient](https://stackoverflow.com/questions/12022965/adding-http-headers-to-httpclient) – Jonathan Barraone Feb 11 '22 at 19:53
  • 1
    What's left is to declare a static (`Shared`) HttpClient object, set the Headers once (not *add* to them) using a `HttpClientHadler`. Dispose of this object when you're done with it entirely or the application exists. -- I still don't see your `SendRequest()` methods return anything and the local HttpClient is not disposed. – Jimi Feb 11 '22 at 20:18
  • I contacted the company and they did in fact get my data correctly so it is working so thank-you for your help. As for cleaning it up I'm planning on the program being run by Windows tasks scheduler, pulling the data from SQL, sending it to Spiff, and exiting. Could I just declare "Shared myClient as new HttpClient" at the begining then in the program shutdown do a myClient.Dispose? And leave the default header lines in there since they only would execute once? – ADY Feb 11 '22 at 20:27
  • Yes, you can. But, if you're running this code with the Scheduler, create the Request and then exit, in this case it doesn't matter much (unless the app is run very often). Call `Dispose()` on it anyway (the Connection Pool is a weird beast). You should also dispose of the Response (for the same reason). – Jimi Feb 11 '22 at 21:59
  • Ok. I declared the client and response at the begining then in the form closing I dispose of both. Gonna play with it some more and once it's stable convert it over to a windows service. Thanks for your help. Not sure if you want to post stuff as a answer so I can mark it properly. – ADY Feb 14 '22 at 16:19

0 Answers0