I decided to create my own HTTP calls for Blueprints as the existing ones never seem to get updated quickly enough. My UFUNCTIONS work fine when I call them in C++ but not at all when I call them from the Blueprint. I am calling external APIs to with these HTTP calls. The UFUNCTIONs show up fine in the Blueprint, they just don’t trigger. All of them are currently tied to a button press to trigger an API call. I declare them like this:`#pragma once
I am expecting it is some fairly simple reason this is consistantly failing but I have not managed to find any documentation that would point this out to me. ANy help would be greatly appreciated!!
I used to use this for my old requests. Might be helpful.
I believe yours is prone to errors because you are not binding the return value to be processed (the request is async so you can’t return true or false in same function)
void AHttpActor::MakeHttpRequest(FString url, FString payload, EHTTPMethod method, EContentType contentType, bool asByte)
{
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();
Request->OnProcessRequestComplete().BindUObject(this, &AHttpActor::OnResponseReceivedProcess);
Request->SetURL(url);
FString action = UEnum::GetValueAsString<EHTTPMethod>(method);
Request->SetVerb("POST");
if (contentType == EContentType::JSON) {
Request->SetHeader("Content-Type", TEXT("application/json"));
} else if (contentType == EContentType::PLAINTEXT) {
Request->SetHeader("Content-Type", TEXT("text/plain"));
} else if (contentType == EContentType::TEXTHTML) {
Request->SetHeader("Content-Type", TEXT("text/html"));
}
//Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
if (asByte == true) {
uint32 size = payload.Len();
TArray<uint8> data;
data.AddUninitialized(size);
StringToBytes(payload, data.GetData() + 1, size);
Request->SetContent(data);
}
else {
Request->SetContentAsString(payload);
}
//Request->SetHeader("Content-Type", TEXT("application/json"));
Request->ProcessRequest();
}
/*Assigned function on successfull http call*/
void AHttpActor::OnResponseReceivedProcess(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
// process return
//Create a pointer to hold the json serialized data
TSharedPtr<FJsonObject> JsonObject;
//Create a reader pointer to read the json data
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
//Deserialize the json data given Reader and the actual object to deserialize
if (FJsonSerializer::Deserialize(Reader, JsonObject))
{
// process returned json information
}
}
Here is the basics of what I use. I have one UBlueprintAsyncActionBase subclass that performs network calls. If I use a post route I pass in an FString that represents the JSON body to upload. When parsing a response I return the content string and use other functions to parse. Has worked quite well for me and increased development speed due to only needing to write one-off parsing functions when I need to add a new HTTP call.
.h:
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Interfaces/IHttpRequest.h"
#include "AsyncCallRoute.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogCallRoute, Log, All);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCallRouteResult, FString, ResponseContentString);
/**
*
*/
UCLASS()
class UAsyncCallRoute : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
/**
* Assumes that the HTTP response will contain a boolean field named 'success' and will determine
* the success state based on that.
*/
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"), Category = "Flow Control")
static UAsyncCallRoute* CallPostRoute(const FString& InURL, const FString& InJsonString);
/** Call an HTTP GET route using the InURL parameter. All URL parameters should already be added e.g, http://test.com/render?token=123 */
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"), Category = "Flow Control")
static UAsyncCallRoute* CallGetRoute(const FString& InURL);
virtual void Activate() override;
public:
UPROPERTY(BlueprintAssignable)
FCallRouteResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FCallRouteResult OnFailure;
protected:
void OnNetworkResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully);
private:
void HandleSuccess(const FString& ResponseContentString);
void HandleFailure(const FString& ResponseContentString);
public:
/**
* The serialized JSON string to pass along in our request
*/
UPROPERTY()
FString JsonString;
UPROPERTY()
FString URL;
UPROPERTY()
bool bIsGetRoute = false;
};