(Using 5.6.1)
I’m trying to build a latent blueprint node (using UBlueprintAsyncActionBase) that makes an HTTP request and passes the response to blueprint.
I’m 99% sure this used to work but then I set the project aside for a couple of months and now it’s no longer working.
Here’s the code:
#include "CoreMinimal.h"
#include "Engine/CancellableAsyncAction.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "HttpModule.h"
#include "SendStartGGRequest.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBPOutputNodePin, FString,Response);
UCLASS()
class STARTGG_API USendStartGGRequest : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, DisplayName = "Send Start.GG Request", meta = (WorldContext = "WorldContext", BlueprintInternalUseOnly = "true"))
static USendStartGGRequest* SendStartGGRequest(const UObject* WorldContext, FString Query, TMap<FName, FString> Variables);
/** A delegate called when the async action completes. */
UPROPERTY(BlueprintAssignable)
FBPOutputNodePin OnComplete;
/** A delegate called when the async action fails. */
UPROPERTY(BlueprintAssignable)
FBPOutputNodePin OnFail;
// Start UCancellableAsyncAction Functions
virtual void Activate() override;
// End UCancellableAsyncAction Functions
private:
FString ProcessRequestResponse(const FString& ResponseContent);
void HandleHttpResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
FString QueryText;
TMap<FName, FString> QueryVariables;
/** The timer handle. */
FTimerHandle OngoingDelay;
};
#include "SendStartGGRequest.h"
#include "Engine.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
USendStartGGRequest* USendStartGGRequest::SendStartGGRequest(const UObject* WorldContext, FString Query, TMap<FName, FString> Variables)
{
USendStartGGRequest* NewAction = NewObject<USendStartGGRequest>();
NewAction->QueryText = Query;
NewAction->QueryVariables = Variables;
NewAction->RegisterWithGameInstance(WorldContext);
return NewAction;
}
void USendStartGGRequest::Activate()
{
// When the async action is ready to activate, set a timer using the world's FTimerManager.
if (const UWorld* World = GetWorld())
{
FString IniLocation = FPaths::ProjectDir().Append("Config/DefaultStartGG").Append(".ini");
FString RequestURL = "";
FString AuthorizationKey = "";
GConfig->GetString(TEXT("/Script/StartGG.StartGGSettings"), TEXT("RequestURL"),RequestURL, IniLocation);
GConfig->GetString(TEXT("/Script/StartGG.StartGGSettings"), TEXT("APIKey"), AuthorizationKey, IniLocation);
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> pRequest = FHttpModule::Get().CreateRequest();
pRequest->SetURL(RequestURL);
pRequest->SetVerb(TEXT("POST"));
pRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
pRequest->SetHeader(TEXT("Authorization"), "Bearer " + AuthorizationKey);
TSharedRef<FJsonObject> requestContent = MakeShareable(new FJsonObject);
TSharedPtr<FJsonObject> queryVariables = MakeShareable(new FJsonObject);
for (auto& variable : QueryVariables) {
queryVariables->SetStringField(variable.Key.ToString(), variable.Value);
}
requestContent->SetStringField(TEXT("query"), QueryText);
requestContent->SetObjectField(TEXT("variables"), queryVariables);
FString ContentOutput;
TSharedRef<TJsonWriter<>> writer = TJsonWriterFactory<>::Create(&ContentOutput);
FJsonSerializer::Serialize(requestContent, writer);
pRequest->SetContentAsString(ContentOutput);
pRequest->OnProcessRequestComplete().BindLambda(
[&](
FHttpRequestPtr pRequest,
FHttpResponsePtr pResponse,
bool connectedSuccessfully) mutable {
if (connectedSuccessfully) {
OnComplete.Broadcast(pResponse->GetContentAsString());
}
else {
switch (pRequest->GetStatus()) {
case EHttpRequestStatus::Failed:
UE_LOG(LogTemp, Error, TEXT("Connection failed."));
default:
UE_LOG(LogTemp, Error, TEXT("Request failed."));
}
OnFail.Broadcast("");
}
});
pRequest->ProcessRequest();
}
}
The request itself is working fine and I get the data I expect. The issue is that OnComplete.Broadcast()
doesn’t trigger the corresponding blueprint node exec pin when it’s inside the lambda function so I can’t progress in the event graph once the request is complete.
I should note that I’m getting a similar issue using the HTTP request node from the Blueprint Http plugin (which 100% used to work).
Tried to replicate the issue on a fresh project, but setting up the request node (from the plugin) makes the editor crash when compiling the blueprint…
Not sure what I’m missing.