callWithPOST change content type
-
Re: Server.callWithPost content type
Hello everyone,
I'm currently working on implementing a licensing system using Moonbase within HISE. One issue I recently faced regarding user sign-in was working with the callWithPOST function. As the Moonbase API requires me to pass text/plain instead of a json object, I can't get the sign-in to properly work. Is there any way to just pass a simple string via the callWithPOST function? anyone else, who faced a similar issue and found an workaround?
Moonbase Docs Sign-In: https://moonbase.sh/docs/licensing/api/#sign-in-a-customer
inline function makeHttpRequest(method, endpoint, data, callback) { // Set base URL Server.setBaseURL(MOONBASE_API); Server.setHttpHeader("Content-Type: text/plain"); currentHttpCallback = callback; if (method == "POST") { Server.callWithPOST(endpoint, data, function(status, response) { if (status == Server.StatusOK) { Console.print("LicenseManager: Request successful"); currentHttpCallback(true, response); } else { Console.print("LicenseManager: Request failed with status: " + status); currentHttpCallback(false, {"error": "HTTP " + status}); } }); } else { Server.callWithGET(endpoint, data, function(status, response) { if (status == Server.StatusOK) { Console.print("LicenseManager: Request successful"); currentHttpCallback(true, response); } else { Console.print("LicenseManager: Request failed with status: " + status); currentHttpCallback(false, {"error": "HTTP " + status}); } }); } } /** * Sign in customer to get access token */ inline function signInCustomer(email, password, callback) { // Store callback in global variable for nested function access currentSignInCallback = callback; // Make sign-in request makeHttpRequest("POST", "/customer/identity/sign-in?email=" + email, password, function(success, response) { if (success) { Console.print("LicenseManager: Sign-in response received"); // Parse JSON response directly without storing in variable if (isDefined(parseSimpleJSON(response).accessToken)) { Console.print("LicenseManager: Access token received"); currentSignInCallback(true, parseSimpleJSON(response)); } else { Console.print("LicenseManager: No access token in response"); currentSignInCallback(false, "No access token received"); } } else { Console.print("LicenseManager: Sign-in request failed"); currentSignInCallback(false, "Sign-in request failed"); } }); }
@tobbentm any recommendation from your side on implementation? why cant we just pass json with the sign-in function? would have loved to use the JUCE module from you, but as you already pointed out, this is only compatible with JUCE 7.
Any help is greatly appreciated!
-
@Daanyoo looks OK and the
setHttpHeader
should change the content type, but your calls weirdly mix GET and POST parameters for the email and password so this might cause the issue.Can't you call
makeHttpRequest("POST", "/customer/identity/sign-in", { email: "my_email", password: "1234", }, // ...
This way both arguments are passed as POST parameters.
-
@Christoph-Hart ah actually there was a glitch in the URL handling which prevented this from work - passing in a string as POST data and then using the GET parameters is valid syntax but the JUCE URL class didn't parse the GET arguments correctly.
Try again now with your original snippet. Make sure that
password
is just the password as plain string, no JSON format required. -
@Christoph-Hart Okay great, this fix already allowed me to pass the plain string into the function.
Another problem, that also was mentioned in the referenced thread is that data is not being processed as text/plain or plain JSON as it looks like HISE is sending the data as URL-encoded form data (like a web form submission)
This leads to problems in calling the sign-in API endpoint of Moonbase - this is how Moonbase expects to receive sign-in data:
POST https://demo.moonbase.sh/api/customer/identity/sign-in?email=test@example.com Content-Type: text/plain Password1234!
I need to embed the mail into the URL endpoint and pass on the password as plain text. This is how I implemented it within HISE:
makeHttpRequest("POST", "/customer/identity/sign-in?email=" + email, password, function(success, response)
Due to the faulty URL encoding the data is being received in the format shown below:
I am not sure how to create a workaround for this..
-
@Daanyoo I just checked and the only thing you need to change now is to call
callWithGET
instead of callWithPOST. This is a bit misleading, but since theemail
parameter is a GET argument and the password is attached as POST data, you need to call this method, otherwise theemail
argument will be attached to the POST data as you see in your screenshot.Server.setBaseURL("https://eokdkwk38gtvvue.m.pipedream.net"); Server.setHttpHeader("Content-Type: text/plain"); Server.callWithGET("/customer/identity/sign-in?email=funky@test.com", "password1234!", function(status, obj) { Console.print(status); Console.print(trace(obj)); });
This gives me this HTTP request:
So as you can see it still comes in as POST request (I think internally it changes to a POST request as soon as there is any POST data.
-
@Christoph-Hart That was the solution! Thank you so much!!!
-
@Christoph-Hart Another problem im still facing is the JSON encoding issue that was also mentioned in the linked thread.
Im struggling to send a POST with regular application/json Data, as HISE seems to package the data into x-www-form-urlencoded when using Server.callWithPOST. Everytime I'm trying to send out a POST request to receive a license token I'm getting a 415 error.
Do you have any idea how to change the format of the request in a way that the regular JSON dictionary will be transferred?
Checked the request and its format with Postman:
Using the x-www-form-urlencoded (same as HISE probably uses)
Using the JSON dictionary to receive a license token:
-
@Daanyoo how are you passing the JSON data into the
callWithPOST()
function? If it's a JSON object, then it will be converted to post parameters, so if you want to actually send a text string containing JSON formatted data, you'll need to convert it into a string usingtrace(obj)
. -
@Christoph-Hart this is how im passing the JSON data:
inline function requestDirectLicenseActivation(deviceName, deviceSignature, accessToken) { local requestData = { "deviceName": deviceName, "deviceSignature": deviceSignature }; currentAccessToken = accessToken; makeHttpRequest("POST", "/client/licenses/" + PRODUCT_ID + "/request", trace(requestData), handleDirectLicenseResponse); }
Even when converting the JSON object using trace, I'm getting the 415 error due to an unsupported media type, as the endpoint will not receive the content as application/json, as its converted to x-www-form-urlencoded data.
-
@Daanyoo Can't reproduce it here. The content type has to be set before calling callWithPOST(), but then it goes through without problems and calling trace() makes it pass the raw JSON string instead of parsing it as POST arguments.
application/x-www-form-urlencoded
only appears if I set a empty HTTP header as this is what it defaults to. Why is there an authentication token in your header response? -
@Christoph-Hart I think this is the same issue @hisefilo and I had in the other thread.
-
@d-healey yes but this is solved - you have to pass in the JSON as string to append it as POST data - I‘ve removed the type check that only accepted JSON objects for this method.
-
@Christoph-Hart Ah yeah, just tested and it's working here
https://posttestserver.dev/p/y1n6045ukg04hp7k/latest
HiseSnippet 1210.3ocsVs0TaaDEdEfxDbZ5zLSerOriexzAhk.gSBc5zfMPvPv3h4Rxz1gYszZzhj1UY2UF6lI+m6+f1yJIrMDnMCSidvi2ys8aOmuyY2tRgOUoDRjUkiGmRQVeicuwbcXqPBiiZuEx56r6JT5ioJcOpbHUhZNNknTz.jk07uwXk0hKfx+9qeoIIlv8oSEgPmJX9z2xRX5oR6958Yww6PBnGyRlwZuW21WvaIhEY.hl21AkR7iHWP6PLlMmMZWhJDY8i19MVcs9NMB7ItubcO+0CHAj0dEwKviNvyaUGGW5.mWQGfrdz1ALsP1SSzTExZglhfw8BEWwK1fSYJV+XpYgKpGryEh2QDGXNhFonVgr3ftWmpTHHJcml3luHw881GvBXSjOaBzn.O0iYSfVycS3M+Mfm6rvyYF3cGPxZFHsPAjdlcOeIKUOUiAOOwtMWSkCHPcZVnTXKZN24saI.K35mmPhn6HgES7nVCGmkwvOK8SUpTofQ7bEU2jnnmbzaqUMTqSUaTudJPZfSjVUXR.cXUvkoNrKX2tTfAHqUsb6Vwf5MvjzzXlOQyD75WpD7emuYlNTHY+YtrMvMoDIUhUQqjJEWtRT68ECCCeyIsCVa2yXQW0g7xMujKjCNZ3ImMjNrOUddx3zNcUD0oYoMyVejely3FiF51Yz9CZuin4YeHht19eHq4wq0LtezN6c5g9tIwt+Zr2oQTUn6lmLZydC6DJ6tWDoSqAM6zMt8I9dqR1izSIx5rWiKWe02E6EPbNeTq2Gv5HOa+gMNXyp4YpJ.uVowCIRbJF+y3OVACeUSDAz3pafqdQpdEOQ0kKECUKf0q.M+VtDy2Gm7ubajhXpwyLHCW52Dc9EITi5qjLMESv.cLJCS5KxzXBq5D6+T9+9iJeJGk0qi6dXuiw9j33qKVl+eFSGZTTqZ8z5ic4Mb7VOK5BGuvzWDkWqqtLNcY7fLtuoHUSA74L0xXIUkBmb5R.7qrHTnU.redpjw00zRCgZhEPd5VFTDDP9mxygWGbrf2QnoGxqsTkOVYwJvQ31pFL3N0YHZPdKFHc2kZyvH4+li03YI.aZYnNFmQmXHzvcytX66uKd1gLkkoYLTvayY5CSo76azCprYwzwWhJvTcd+92V1u2LSqEbDCZqWztul2ixCP4Pd1Y0nSZuEQStNPPLg8IkJ0LyQvZK5PXvcwfjEs2hphzhTXqZIRf5kAAV1eAa6nYuKX7rKzzQPLdr817gLhzbvtcfeZYfeKoOMNOtOwVOx.yDXP08E41utHxOxNTDS9xh6Ssi6GeTIS7di76Ki7OXusTJjXJGGSv.gk4yzYAaf8b7fK29r4vvM.hfrXh9lWKXt7rTAvxtwrXy7VthoGOaA6+s6J9Rg3yr6xz9g2MFm6NvHvk9ZfwxaXep81CFP80SA3B167tuNWmhNBFTx3Wb.QKY.evtSVRO3UI9TX24bZroK2ZNS+XwZGyZSFvv5yW72vWoRWyZqRktWqDkP7khy8K5hM2g+3bI.l34u2YQ6CLqwt2t4EgRfmTbtu+MC0m43pOTGW6g5n2C0w0enN13g53KdnN9x+aGMu3Cd0hHonsAgNn614Casr1lS.FXNaE8OfASM7C
Edit: Actually this snippet sends it as an object, not a string, and it seems to still work.
-
@d-healey if you don‘t convert it to a string then the JSON is converted to post arguments, no?
-
@Christoph-Hart In the link I posted above, it shows the result like this, regardless of if I convert to a string first:
content-type application/json
Body
{ "model": "gpt-4o", "messages": [ { "role": "user", "content": "write a haiku about ai" } ] }
Edit: Ah but if I don't convert to string it seems to lose the authentication header, strange..
-
@d-healey ah yes true this is because the JSON has an Array element - HISE checks this and then converts it to a String internally (because it cannot pass an array as post parameter).