Mini Builds

HTTP Requests with JSON in Unity Using UnityWebRequest

May 2, 2021

In this article we will demonstrate how to use UnityWebRequest to make GET and POST requests with JSON payloads and responses.

The first step is to create a UnityWebRequest. The UnityWebRequest constructor requires a url and optionally accepts a method (default method is GET). The UnityWebRequest class has methods to set headers, and the upload and download handlers which are used to set the request body and read from the response.

The method SendWebRequest is used to start the request, it returns a WebRequestAsyncOperation which can be yielded in a coroutine freeing the frame to continue it’s execution while the request is handled.

Checkout on GitHub

You can find the full Unity project in the GitHub repo: https://github.com/mini-builds/unity-coin-flip-http.

Backend

The backend used in this example is a small Python/Flask app that runs as a server playing a coin flip game. The backend has two endpoints:

Checkout the GitHub repo and read the README for more details.

Get Request

Below is a method that calls the /balance endpoint which returns a response of the form { "balance": 100 }. The response is parsed to a BalanceResponse, logged and used to update the UI.

To access the response from the request we set the downloadHandler to an instance of DownloadHandlerBuffer. This object processes the response body and provides it to us in the text field;

private IEnumerator balance()
{
  UnityWebRequest request = new UnityWebRequest("http://localhost:5000/balance");

  request.SetRequestHeader("Content-Type", "application/json");
  request.downloadHandler = new DownloadHandlerBuffer();

  yield return request.SendWebRequest();

  Debug.Log("Balance: " + request.downloadHandler.text);

  BalanceResponse balance = BalanceResponse.FromJson(request.downloadHandler.text);

  // update balance text
}

To execute the request we start it using MonoBehaviour.StartCoroutine().

void Start() 
{
  StartCoroutine(balance());
}

Above we use the class BalanceResponse, which is a simple POCO, to parse the JSON response into.

public class BalanceResponse
{
  public int balance;

  public static BalanceResponse FromJson(string json)
  {
    return JsonUtility.FromJson<BalanceResponse>(json);
  }
}

Post Request

Below is a method that calls the /play endpoint which takes a PlayRequest in the request body and returns a response of the form { "balance": 100, "payout": 2, "result": "heads" }. The response is parsed to a PlayResponse, logged and used to update the UI.

The main differences between this and the GET example are:

private IEnumerator play()
{
  UnityWebRequest request = new UnityWebRequest("http://localhost:5000/play", "POST");
  PlayRequest playRequest = new PlayRequest("coin-flip");

  request.SetRequestHeader("Content-Type", "application/json");

  byte[] body = Encoding.UTF8.GetBytes(JsonUtility.ToJson(playRequest));
  request.uploadHandler = new UploadHandlerRaw(body);
  request.downloadHandler = new DownloadHandlerBuffer();

  yield return request.SendWebRequest();

  Debug.Log("Play: " + request.downloadHandler.text);

  PlayResponse response = PlayResponse.FromJson(request.downloadHandler.text);

  // start animations, etc
}

POCOs used in the POST example.

public class PlayRequest
{
  public string game;

  public PlayRequest(string game) {
    this.game = game;
  }
}


public class PlayResponse
{
  public int balance;
  public string result;
  public int payout;

  public static PlayResponse FromJson(string json)
  {
    return JsonUtility.FromJson<PlayResponse>(json);
  }
}

Notes

What about HttpClient?

In a regular .NET application you’d use System.Net.Http.HttpClient to send HTTP however in Unity HttpClient is not supported on all platforms hence isn’t recommended. Also UnityWebRequest integrates well with Unity’s coroutine style of performing asynchronous operations whereas HttpClient doesn’t.

Why not use UnityWebRequests static methods?

UnityWebRequest has static methods Get, Post, etc to create requests however the Post method expects form data (e.g. hello=world&name=barry) and will not work with a JSON payload. Therefore, you have to use the constructor for JSON payloads

I’d personally recommend using the constructors as above to avoid having your request screwed with behind the scenes and for consistence with any POST requests.