Question on calling a REST API using juce::Thread

Hey there,

So I have a REST API for my project that I need to call semi regularly. For obvious reasons, doing this on a separate thread than the message thread is ideal. I get the idea of using juce::Thread. Create a class that inherits thread, override run, and in your run function call the function you need to do.

My question is that with the REST API I have many different functions I may need to call at some point, but I can’t just really switch out which function I call in my run function at run time? Should I be making a new class with a custom run function for each different API call I need to make? (For example, one class for my GET call, one class for my POST call). I suppose I could feed a single class object an enum and tell it which function to call based on that, but that seems incorrect and not super dynamic.

Any help appreciated.

No need for additional classes.

Here’s the general pattern you can use, notice that the reply will always come back on the message thread to avoid additional thread syncing.

using juce::String;
using ReplyFunc = std::function<void(const String&)>;
using juce::URL;

void runHTTP(const URL& url, const ReplyFunc& replyFunc)
{
    auto req = [url, replyFunc]
    {
        auto options = URL::InputStreamOptions(URL::ParameterHandling::inAddress);
        auto stream = url.createInputStream(options)->readString();
        juce::MessageManager::callAsync([replyFunc, stream] { replyFunc(stream); });
    };

    juce::Thread::launch(req);
}

And used like:

auto replyFunc = [](const String& content) { DBG(content); };
runHTTP({"https://www.google.com"}, replyFunc);

If you need to spawn a ton of requests, you can also use juce::ThreadPool.

And also some error handling on the request itself to see if it failed might be needed. Good luck! :slight_smile:

3 Likes

Thank you, this was extremely helpful!

I have one more question you might be able to answer.
From my API call, I’m retrieving some data, and filling an OwnedArray with DynamicObjects in my class Foo I called the API from. That’s working fine.

However, the GUI needs to update when the array has been filled. What would be the best method of alerting my class Foo that the API call has finished and the GUI should now update? I tried making the Foo class a thread listener and adding it to a listener to the spun up thread, but for whatever reason I did not get callbacks from it.

In that case, your code would look something like (pseudo code):

struct Foo
{
    //Parse the reply and update the array:
    void updateArrayWithAPIResponse(const String& res);
};

//Somewhere in GUI, for example:

Foo foo; 

auto replyFunc = [&](const String& content) 
{ 
    foo.updateArrayWithAPIResponse(content);
    updateGUI(foo);
};

button.onClick = [replyFunc] 
{ 
    runHTTP("https://www.api.com", replyFunc); 
};

Hey , can I also send audio buffer this way , I am attempting to do that but running into errors. I am new to JUCE and I am trying to send the audio to our server. Is there a better way to do this?

You’d need to serialize the buffer to send it as raw data, a buffer in itself is just a data structure and isn’t possible to just put in a json. A better approach would be to convert/compress the buffer into, for example, a flac file or if you don’t need lossless some other format and send the file.