0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UE5のBlueprintでGraphQLをリクエストする

Last updated at Posted at 2021-10-28

UE5で簡単なGraphQLのやり取りを行いたい

マーケットプレイスで検索すると、GraphQLを扱えるようになるコンテンツが見つかります

ただ、そこそこいい値段がするので、サーバーとの簡単な(認証など不要な)やり取りができるコードを書いてみました

環境

ソフトウェア バージョン
MacOS 10.15.7
UnrealEngine 5.0.0
Visual Studio Code 1.61.2
Xcode 12.4
.NET SDK 5.0.402

基本設計

UObjectを継承して、Blueprint上でクエリー文の入力と、イベントによる結果の受信を行います
プロジェクト名はGraphqlTestとして進めます

コード

Build.csファイルのPublicDependencyModuleNamesHttp,Json,JsonUtilitiesを追加します

GraphqlTest.Build.cs
 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Http", "Json", "JsonUtilities" });
GraphqlObject.h
// Fill out your copyright notice in the Description page of Project Settings.

# pragma once

# include "Http.h" // Http関連が使用できるように追加
# include "CoreMinimal.h"
# include "UObject/NoExportTypes.h"
# include "GraphqlObject.generated.h"

/**
 * 
 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FBlueprintAssignableSignature);

UCLASS(Blueprintable, BlueprintType)
class GRAPHQLTEST_API UGraphqlObject : public UObject
{
	GENERATED_BODY()

public:
	UGraphqlObject();

	FHttpModule *Http;

private:

public:
	// GraphQLのサーバをBlueprintから指定できるようにプロパティを公開
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Graphql")
	FString url;

	// 受信結果をBlueprintから参照できるように読み込み専用のプロパティを追加
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Graphql")
	FString ContentAsString;

	// 自身のインスタンスを作成するメソッド
	UFUNCTION(BlueprintPure, Category = "Graphql", meta = (DisplayName = "Create Object", Keywords = "Create Graphql Object", ShortTooltip = "Creates an empty Graphql Object"))
	static UGraphqlObject *Create();

	// HTTP通信を行ってレスポンスが返ってきた際のイベント処理
	void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

	// 受診後のイベントを発行するためのメソッド
	UPROPERTY(BlueprintAssignable, Category = "Dynamic Delegate Component")
	FBlueprintAssignableSignature OnResponseReceivedDispatcherCalled;

	// クエリーを発行するためのメソッド
	UFUNCTION(BlueprintCallable, Category = "Graphql")
	void Query(FString document);
};

GraphqlObject.cpp
// Fill out your copyright notice in the Description page of Project Settings.


# include "GraphqlObject.h"

UGraphqlObject::UGraphqlObject() 
	: Super()
{
    Http = &FHttpModule::Get();
}

UGraphqlObject* UGraphqlObject::Create() {
    return NewObject<UGraphqlObject>();
}

void UGraphqlObject::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
    if (!Response.IsValid())
    {
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, "No Valid");
    }
    else if (EHttpResponseCodes::IsOk(Response->GetResponseCode()))
    {
        ContentAsString = Response->GetContentAsString();

        TSharedPtr<FJsonObject> JsonObject;
        TSharedRef<TJsonReader<> > Reader = TJsonReaderFactory<>::Create(ContentAsString);

        // Jsonオブジェクトをデシリアライズ
        if (FJsonSerializer::Deserialize(Reader, JsonObject))
        {
            GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, "Received JSON String");

            //ここに、JSON StringをパースしてJSON Objectとして保持する工程を追加する

            OnResponseReceivedDispatcherCalled.Broadcast();
        }
    }
}

void UGraphqlObject::Query(FString document)
{
    // Jsonデータの作成
    TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
    JsonObject->SetStringField("query", document);
    // JsonStringにJson書き出し
    FString JsonString;
    TSharedRef<TJsonWriter<TCHAR> > JsonWriter = TJsonWriterFactory<>::Create(&JsonString);
    FJsonSerializer::Serialize(JsonObject.ToSharedRef(), JsonWriter);

    // Httpリクエストの作成
    TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();
    Request->OnProcessRequestComplete().BindUObject(this, &UGraphqlObject::OnResponseReceived);
    Request->SetURL(url);
    Request->SetVerb("POST");
    Request->SetHeader(TEXT("User-Agent"), TEXT("X-UnrealEngine-Agent"));
    Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
    Request->SetHeader(TEXT("Accepts"), TEXT("application/json"));
    Request->SetContentAsString(JsonString);
    Request->ProcessRequest();
}

Blueprint上での組み立て

ノードのつなげ方.png
図の上段が、BeginPlayから始まるGraphqlObjectの準備とイベント処理

図の下段は、クエリーを発行する処理
Queryの後にDelayなどがつながっているのはテスト用につなげたもので、不要です

インスタンス化.png
変数に自作したクラスをセットして、Blueprint上にドラッグ&ドロップで配置

そこからノードをつなげていくことで、クエリーを実行できるが、createメソッドで作ったオブジェクトを、Blueprintの変数に再代入しないと、オブジェクトの要素にアクセスできません

UActorを継承すれば、こんなヘンテコなつなげ方をする必要はないのだけれど、Actorとしての機能は必要ないと考えて、UObjectを継承しています

追記(2021/10/29)

以下のようなノード接続が可能でした
直接生成可能に.png

JSONはそのままではBlueprintに出力できない

何かしらでラップしないとBlueprintでは扱えないようですが、ここでは触れません

今回は文字として出力しています

以下のソースが参考になると思います

さいごに

マーケットプレイスにあるGraphQLが扱えるようになるものは、受信後の処理をイベントではなく、Latentノードというもので実装している

こちらの方がBlueprint上での取り扱いが直感的にできそう

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?