UFUNCTION HTTP call is not triggering when the button on my blueprint is pressed as expected

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

#include “CoreMinimal.h”
#include “GameFramework/Character.h”
#include “Http.h”
#include “MyCharacterClasses.generated.h”

UCLASS()
class MDV_V1_API AMyCharacterClasses : public ACharacter
{
GENERATED_BODY()

public:
// Sets default values for this character’s properties
AMyCharacterClasses();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

UFUNCTION(BlueprintCallable)
	bool CheckUniqueUsername(const FString& usernameVal, int32 userId);`

And define it like this:

#include "MyCharacterClasses.h"
#include "Json.h"
#include "Http.h"

bool AMyCharacterClasses::CheckUniqueUsername(const FString& usernameVal, int32 userId)
{
	//TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();
	TSharedRef<FJsonObject> RequestObj = MakeShared<FJsonObject>();

	RequestObj->SetNumberField("userId", userId);
	RequestObj->SetStringField("usernameVal", usernameVal);

	FString RequestBody;
	TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&RequestBody);
	FJsonSerializer::Serialize(RequestObj, Writer);

	FHttpRequestRef Request = FHttpModule::Get().CreateRequest();
	Request->OnProcessRequestComplete().BindUObject(this, &AMyCharacterClasses::OnResponseReceived);
	Request->SetURL("https://medleybackendwin.azurewebsites.net/api/checkUniqueUsername");
	Request->SetVerb("POST");
	Request->SetHeader("Content-Type", "application/json");
	Request->SetContentAsString(RequestBody);
	Request->ProcessRequest();

	return true;
}

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
    }
}

Try using a BlueprintAsyncAction to wrap the call, so you can keep the request object alive and view any responses.

I am looking into this and will let you know how it goes.

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;

};

.cpp:

#include "AsyncCallRoute.h"
#include "HttpModule.h"
#include "Interfaces/IHttpResponse.h"
#include "Json.h"
#include "Dom/JsonObject.h"

DEFINE_LOG_CATEGORY(LogCallRoute);

UAsyncCallRoute* UAsyncCallRoute::CallPostRoute(const FString& InURL, const FString& InJsonString)
{
	UAsyncCallRoute* AsyncNode = NewObject<UAsyncCallRoute>();
	AsyncNode->bIsGetRoute = false;
	AsyncNode->URL = InURL;
	AsyncNode->JsonString = InJsonString;
	return AsyncNode;
}

UAsyncCallRoute* UAsyncCallRoute::CallGetRoute(const FString& InURL)
{
	UAsyncCallRoute* AsyncNode = NewObject<UAsyncCallRoute>();
	AsyncNode->bIsGetRoute = true;
	AsyncNode->URL = InURL;
	return AsyncNode;
}

void UAsyncCallRoute::Activate()
{
	Super::Activate();

	FHttpRequestRef Request = FHttpModule::Get().CreateRequest();

	Request->OnProcessRequestComplete().BindUObject(this, &UAsyncCallRoute::OnNetworkResponseReceived);
	Request->SetURL(URL);
	
	if (bIsGetRoute)
	{
		Request->SetVerb("GET");
	} 
	else
	{
		Request->SetVerb("POST");

		Request->SetHeader("Content-Type", "application/json");
		Request->SetContentAsString(JsonString);
	}

	Request->SetTimeout(20.0f);
	Request->ProcessRequest();
}

void UAsyncCallRoute::OnNetworkResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully)
{
	Request->OnProcessRequestComplete().Unbind();

	if (bConnectedSuccessfully)
	{
		UE_LOG(LogCallRoute, Log, TEXT("The response connected successfully"));

		TSharedPtr<FJsonObject> ResponseObj;
		TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
		FJsonSerializer::Deserialize(Reader, ResponseObj);

		if (ResponseObj->HasField("success"))
		{
			UE_LOG(LogCallRoute, Log, TEXT("Response has success field"));
			const bool bIsSuccess = ResponseObj->GetBoolField("success");
			if (bIsSuccess)
			{
				if (ResponseObj->HasField("message"))
				{
					FString Message = ResponseObj->GetStringField("message");
					UE_LOG(LogCallRoute, Log, TEXT("Succesful response with a message of %s"), *Message);
				}

				HandleSuccess(Response->GetContentAsString());
			}
			else
			{
				UE_LOG(LogCallRoute, Warning, TEXT("Failed to set server status"));
				HandleFailure(Response->GetContentAsString());
			}
		}
	}
	else
	{
		UE_LOG(LogCallRoute, Warning, TEXT("Request failed because HTTP request couldn't connect"));
		HandleFailure(Response->GetContentAsString());
	}
}

void UAsyncCallRoute::HandleSuccess(const FString& ResponseContentString)
{
	AsyncTask(ENamedThreads::GameThread, [this, ResponseContentString]()
	{
		OnSuccess.Broadcast(ResponseContentString);
		SetReadyToDestroy();
	});
}

void UAsyncCallRoute::HandleFailure(const FString& ResponseContentString)
{
	AsyncTask(ENamedThreads::GameThread, [this, ResponseContentString]()
	{
		OnFailure.Broadcast(ResponseContentString);
		SetReadyToDestroy();
	});
}