[Plugin] Http/s REST, blueprintable JSON and Parse REST API manager at once (VaRest)

Thanks @.

Another noob question.

Now I want to bind a function in my plugin’s class to the UVaRestRequestJSON::OnRequestComplete delegate. I’ve followed some tutorials (e.g. UE4 c++ Event Dispatchers syntax - YouTube) about how to register the funciton using UVaRestRequestJSON::OnRequestComplete.AddDynamic() method. However, it looks like the AddDynamic() function requires that the class and method be declared using the UCLASS() and UFUNCTION() macros. However my plugin’s class is derived from the IAnalyticsProvider class, which is not derived from any other class. Thus I’m not able to successfully add my class’s method as delegate using AddDynamic(). So is there any other way to bind/register delegate function?

Ok, looks like I have to use a class that is derived from UObject. So I’ve done this:

header:



/**
*
*/
UCLASS()
class MYOBJECT_API URestCommunicator : public UObject
{ GENERATED_BODY()
 
public: UFUNCTION()
bool Initialize();

UFUNCTION()
void OnRESTComplete(UVaRestRequestJSON* Request);

UFUNCTION()
void OnRESTFail(UVaRestRequestJSON* Request);
 
private: /** The REST system that is used to send data via REST. */
UPROPERTY()
UVaRestSubsystem* RESTSystem;

UPROPERTY()
UVaRestRequestJSON* JSONRequest;
 };


Then in the class’s cpp file:



bool URestCommunicator::Initialize()
{ if (GEngine != nullptr)
{
  [INDENT=2]RESTSystem = GEngine->GetEngineSubsystem<UVaRestSubsystem>();
if (RESTSystem == nullptr)
{[/INDENT]
  [INDENT=3]return false;[/INDENT]
  [INDENT=2]}[/INDENT]
  }
else
{
  [INDENT=2]return false;[/INDENT]
  }
  
JSONRequest = RESTSystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
if (JSONRequest != nullptr)
{
  [INDENT=2]JSONRequest->OnRequestComplete.AddDynamic(this, &URestCommunicator::OnRESTComplete);
JSONRequest->OnRequestFail.AddDynamic(this, &URestCommunicator::OnRESTFail);[/INDENT]
  }
  [INDENT=2] [/INDENT]
  return true;
 }


I was able to compile the code. However when I run it, during the Initialize(), I got the following error in the Output Log:



LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: this->IsBound() [File:C:\Program Files\Epic Games\UE_4.24\Engine\Source\Runtime\Core\Public\Delegates/DelegateSignatureImpl.inl] [Line: 1132]
LogOutputDevice: Error: Unable to bind delegate to 'OnRESTComplete' (function might not be marked as a UFUNCTION or object may be pending kill)


As can be seen in my code, I have included UFUNCTION in front of my methods that should handle the delegate. I checked to make sure the JSONRequest object is valid. Could it be that the JSONRequest object really is already in pending state?
I know this is probably not a problem with the plugin, and more to do with the delegate add/bind issue. But just wondering if someone else has tried to do this in C++ and can spot where my problem is.

Please check two things:

  1. Solution should be generated again after UFUNCTION was added
  2. How URestCommunicator class object is created and exists

I was looking for some help, I want to know how to get the VaRestSubsystem node that is in blueprints in c++.
When I use the blueprint node I get no warnings and everything works, when I use my code below it still works but it gives a warning in the log that I can’t understand why.
Even though it works, I run a lot of json messages in my project and I don’t want my dedicated server to be pushing a lot of warning messages into the log file.

The Error I get when I run in c++ is below:

My c++ header code has:

UPROPERTY()
UVaRestSubsystem* VSubsystem;

UPROPERTY(replicated, EditAnywhere, BlueprintReadWrite, Category = Database)
UVaRestRequestJSON* RequestBP;

UPROPERTY(replicated, EditAnywhere, BlueprintReadWrite, Category = Database)
UVaRestJsonObject* RequestObjectBP;

and my cpp code is:

VSubsystem = GEngine->GetEngineSubsystem<UVaRestSubsystem>();
RequestBP = VSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::x_www_form_urlencoded_url);
RequestObjectBP = VSubsystem->ConstructVaRestJsonObject();

As soon as the second line and third line in my cpp file runs it pops the warning error and I narrowed it down to those exact lines that make the warning log.

When I do the exact same thing using the blueprint nodes it doesn’t pop up with this warning log because it is using the actual VaRestSubsytem Node.

So is my line:
VSubsystem = GEngine->GetEngineSubsystem<UVaRestSubsystem>();
not the same thing as using the blueprint node??

Thank you for your time.

You shouldn’t use “replicated” keyword with requests

1 Like

THANK YOU SO MUCH!
that was the issue and I wouldn’t have realized it, Ive been using your plugin since 4.15 I believe and have loved it! I appreciate the work you do and help!!

@ Hope you can help in pointing me to a tutorial on how to POST with VaREST. I have watched a few, all old and did not look like it had the same nodes as 4.25. I am looking to send a player name to a PHP server ( I have it talking to the server ), but I cannot see what the JSON looks like. So in PHP if($_POST) always fails. I have more complex coding to do, so would like to see a tutorial on it all. I can appreciate your busy so any pointers ?

@
Using the “Construct Json Request”-node, can you explain what PUT and CUSTOM do and how to use them ?
I want to embeed a small game on a wordpress-site. I want to activate a wordpress shortcode when clicking on a widget button inside the game. How can I achieve this?
I think all I need is to just show and hide stuff on the wordpress site. Nothing too special stuff…

@

Do you have a discord server?

LogHttp: Warning: 000001A8BA567380: invalid HTTP response code received. URL: https://uapi.ust.hk/sensor-data_search?q=scan&sort=@timestamp:desc&size=1000, HTTP code: 0, content length: 0, actual payload size: 0
LogHttp: Warning: 000001A8BA567380: request failed, libcurl error: 60 (Peer certificate cannot be authenticated with given CA certificates)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 0 ( Trying 143.89.12.89…)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 1 (TCP_NODELAY set)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 2 (Connected to uapi.ust.hk (143.89.12.89) port 443 (#106))
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 3 (ALPN, offering http/1.1)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 4 (Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 5 (TLSv1.3 (OUT), TLS handshake, Client hello (1):slight_smile:
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 6 (TLSv1.3 (IN), TLS handshake, Server hello (2):slight_smile:
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 7 (TLSv1.2 (IN), TLS handshake, Certificate (11):slight_smile:
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 8 (TLSv1.2 (OUT), TLS alert, Server hello (2):slight_smile:
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 9 (SSL certificate problem: unable to get local issuer certificate)
LogHttp: Warning: 000001A8BA567380: libcurl info message cache 10 (Closing connection 106)
LogVaRest: Error: Request failed (0): https://uapi.ust.hk/sensor-data_search?q=scan&sort=@timestamp:desc&size=1000

why? I can get it correctly through authorization on postman, but use varest to get error reports. What should I do?

Dont know if this is failsafe but i got it working.

.h



#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "VaRestJsonObject.h"
#include "VaRestRequestJSON.h"
#include "VaRestSubsystem.h"
#include "CLInternalSave.h"
#include "CLGameInstance.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FReqComplete, UVaRestRequestJSON*, VarName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FRequestFail, UVaRestRequestJSON*, VarName);

UCLASS()
class CODENAMELOKA_API UCLGameInstance : public UGameInstance
{
GENERATED_BODY()

public:

UFUNCTION()
void RequestComplete(UVaRestRequestJSON* VarName);

UFUNCTION()
void RequestFail(UVaRestRequestJSON* VarName);

UPROPERTY()
FReqComplete RComplete;

UPROPERTY()
FRequestFail RFail;

UPROPERTY()
UCLInternalSave* SaveObj;

UPROPERTY()
UCLInternalSave* LoadObj;

UFUNCTION()
virtual void Init() override;

UFUNCTION()
bool Initialize();

UPROPERTY(BlueprintReadOnly)
bool KeepLoggedIn;

UPROPERTY(BlueprintReadOnly)
bool DoWeHaveSave;

UPROPERTY(BlueprintReadOnly)
FString Username;

UPROPERTY(BlueprintReadOnly)
FString Password;

UPROPERTY(BlueprintReadOnly)
FString OldSessionID;

UPROPERTY(BlueprintReadOnly)
FString NewSessionID;

private:

UPROPERTY()
UVaRestSubsystem* RESTSystem;

UPROPERTY()
UVaRestRequestJSON* JsonRequest;

UPROPERTY()
UVaRestJsonObject* JsonObject;
};



.cpp



#include "CLGameInstance.h"
#include "CLInternalSave.h"
#include "Kismet/GameplayStatics.h"


// Callback if Request Completed
void UCLGameInstance::RequestComplete(UVaRestRequestJSON* VarName)
{
UE_LOG(LogTemp, Warning, TEXT("Request Sucess!"));
}

// Callback if Request Failed!
void UCLGameInstance::RequestFail(UVaRestRequestJSON* VarName)
{
UE_LOG(LogTemp, Warning, TEXT("Request Failed!!"));
}

void UCLGameInstance::Init()
{
UE_LOG(LogTemp, Log, TEXT("Initializing GameInstance!"));

// Run this only for client
if (!IsRunningDedicatedServer())
{
// Create our internal save object.
SaveObj = Cast<UCLInternalSave>(UGameplayStatics::CreateSaveGameObject(UCLInternalSave::StaticClass()));

// Check if we have internal save file
if (UGameplayStatics::DoesSaveGameExist("InternalSave", 0))
{
// Create our internal load object.
LoadObj = Cast<UCLInternalSave>(UGameplayStatics::LoadGameFromSlot("InternalSave", 0));

DoWeHaveSave = false;
if (LoadObj->Username != "")
{
DoWeHaveSave = true;
// Get data from savefile.
KeepLoggedIn = LoadObj->KeeploggedIn;
Username = LoadObj->Username;
OldSessionID = LoadObj->OldSessionID;
}

if (KeepLoggedIn)
{
Password = LoadObj->Password;
}
else
{
UE_LOG(LogTemp, Log, TEXT("Save data found. Not logged in."));
return;
}
}
else
{
UE_LOG(LogTemp, Log, TEXT("Save data not found!"));
return;
}
if (UGameplayStatics::SaveGameToSlot(SaveObj, "internalSave", 0))
{
UE_LOG(LogTemp, Log, TEXT("Saved Sucessfull!"));
}
}
Initialize(); // Send Request to loginserver
}

bool UCLGameInstance::Initialize()
{
if (GEngine != nullptr)
{
// VaRest Subsystem
RESTSystem = GEngine->GetEngineSubsystem<UVaRestSubsystem>();

if (RESTSystem == nullptr)
{
return false;
}
}
else
{
return false;
}

// Create Json request object
JsonRequest = RESTSystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::x_www_form_urlencoded_url);
if (JsonRequest != nullptr)
{
// Create our response object
JsonObject = JsonRequest->GetRequestObject();
// Any data we want to send to the server
JsonObject->SetStringField("key", "value");
// Send the request
JsonRequest->ProcessURL("http://localhost/reguser.php?user=test");

// Handle the callback
JsonRequest->OnRequestComplete.AddDynamic(this, &UCLGameInstance::RequestComplete);
JsonRequest->OnRequestFail.AddDynamic(this, &UCLGameInstance::RequestFail);

}
return true;
}




Hello guys!
I am bit stuck need to send request with paticular body that starts from " " , string like this
decode1.jpg
But when i use this node ,
decode.jpg
output print say that in there just empty {}. Plz help

Crash when converting Json code obtained by POST to a string

I want to send the DbAccess API in POST and output the value obtained in Json as a string.
UE4 crashes when I try to convert the response from the server to a string from Json
I would like to know what the solution to this problem is.

I’d like to send a Json request, but please tell me how I can set up a node to do the same results in UE4 that are shown in POSTMAN.

Hello. Please help with the format. I serialized to json and send. And I get it on the server in a different format. How do I make it send Json?

Hello everyone,

I’m kindda stuck with some simple.

I have a data table on the engine with some info, and I want to change that info through a Json file on a server.

I was able to make the json file communicate with UE4 but I have not been able to make the changes that I make in the Json file be reflected in the compiled one. When I do a print string I can see all the code from the Json file on the screen but I have not been able to get the change done when I edit the json on the server.

Thanks for the Help !

1 Like

Trying to catch up on the changes this plugin has gone through, everything seems to be getting simpler to use. Thank you!

I have one question: Both of these methods work, is there a reason to use one over the other?

Hi all, I create some widgets in BP, for register an ID in my db, first time the game is launched, and after the user can manage his profile. All is working, but I can’t test connection…
In general, the BindEvent on RequestFail never fire, if I remove or delete my php page, or set a fake url, i can’t get a fail notification.
I tried with CallUrl, and in Callback test if IsValid Json, so I could print a error message (test-connection.jpg)

In (test2.jpg) I tried ExecuteProcessRequest, in this case EventFail fired, but immediatly UE crashed.

Please can someone help me for check connection before load php page, or check if the response fail?
Thanks

Sorry for wrong large images in text, is my first post on forum…

Hello everyone.

I am a student in Game Design and programming. We need to create a UE4 project in combination with our own API. I’m stuck with the implementation of VaRest in UE4 and I would like to ask you a question in regards of my configuration.

But first, here is a screenshot of Postman:


When the login is successful, the api sends some strings, including a bearer token.

Here is how my nodes are looking like in Unreal:


When I check the Api, after UE4 sent the GET as seen above, the header is always undefined. Is using the “set header” node the right solution? Or has it anything to do because I’m not using HTTPS?

PS: I’ve got the login working in UE4 (that’s how I got the “token” from).

Thanks in advance for your help

1 Like