Easy HTTP (POST) communication with UnityWebRequest

thank you for your hard work.
This is Matsuyama from the System Development Office.
This time I'll be writing about HTTP (POST) communication using UnitWebRequest.
It may seem a little late, but I've only implemented communication via www, so I'll write about it again ^^;
What to make
・HTTP (POST) communication using UnitWebRequst
・Requests and responses are
in JSON format ・Simple, assuming multiple communication APIs will be created
※ Created with Unity 2019.3.5f1
JSON
First, let's look at JSON. We'll implement it using Unity's JsonUtility.
JsonUtility is a Json parser provided by Unity that
can easily serialize classes and structures that are specified as Serializable.
Although it has some limitations, such as not supporting the Dictionary type, it seems to be superior in terms of performance to other Json parsers.
Serializing to JSON format
UnityWebRequest
This is the main communication process.
UnityWebRequest can handle HTTP requests and responses.
UnityWebRequest
The process itself was quite simple.
Create a UnityWebRequest in POST format and set the request parameters in JSON format.
// Set HTTP (POST) information var req = new UnityWebRequest(url, "POST"); req.uploadHandler = (UploadHandler)new UploadHandlerRaw(postData); req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json");
One thing to note is that the parameter cannot be passed as a string, so you will need to convert it to a byte array
// Convert the request object to JSON (byte array) string reqJson = JsonUtility.ToJson(request); byte[] postData = System.Text.Encoding.UTF8.GetBytes(reqJson);
When you're ready, submit your request
// API communication (wait for completion) yield return req.SendWebRequest();
The communication result is determined to be successful if both isNetworkError and isHttpError are false.
The response is stored in downloadHandler in JSON format (text).
// Communication result if (req.isNetworkError || req.isHttpError) // Failure { Debug.Log("Network error:" + req.error); } else // Success { Debug.Log("Succeeded:" + req.downloadHandler.text); }
API Control
The idea is to create an API class that defines the requests and responses for each API, using the communication process described above as a base class.
Specifically, it looks something like this:
Create a structure for the request and response with the Serializable attribute and define the parameters.
The common part of the URL used during communication is defined on the base class side, so define the API name at the end.
using System; using System.Collections.Generic; namespace Api { ///<summary> /// API Sample B ///</summary> public class SampleB : Web.ApiBase { public const string Name = "Test/SampleB"; ///<summary> /// Request parameters ///</summary> [Serializable] public struct Request { public string userId; public List<int> values; } public Request request; ///<summary> /// Response parameters ///</summary> [Serializable] public struct Response { public int count; public List<int> values; } public Response response; } }
How to use
First, generate the API classes mentioned above
private Api.SampleB apiB; private Web.ApiBase.Result result; private void Start() { // Create a class for communication apiB = new Api.SampleB(); // API communication sendApiB(); }
After specifying the API name, set the value to be passed to the request structure. The value
is serialized to JSON format within the Send() method and communicated via HTTP (POST) using UnityWebRequest.
The communication completion is received via a callback and deserialized into the response structure.
Normally, you would write processing based on the response content, but since this is a sample, it is simply output to the console.
///<summary> /// API Sample B Communication ///</summary> private void sendApiB() { // Set the endpoint apiB.EndPoint = Api.SampleB.Name; // Set the request parameters apiB.request.userId = "beyondB"; apiB.request.values = new List<int> () { 1, 10, 100, 1000 }; // Communication apiB.Send<Api.SampleB.Request> (ref apiB.request, result => { // Result if (result.isSucceeded) // Success { // Expand response apiB.response = apiB.Response<Api.SampleB.Response> (); // Check the contents Debug.Log("SampleB Succeed!!"); Debug.Log(" count : " + apiB.response.count); foreach(var v in apiB.response.values) { Debug.Log(" val : " + v); } } else // Failed { Debug.Log("SampleB Failed : " + result.error); } }); }
summary
In this way, I was able to write a fairly simple HTTP communication process.
I think it is practical for now.
Since it is a communication process, it will not work without a server-side implementation, but I have uploaded the sample code to GitHub.
Unity Sample
The base class of the sample does not inherit MonoBehaviour, so coroutines could not be used as is.
This is how it is handled by referring to this:
Using coroutines in classes that do not inherit MonoBehavior
lastly
I have opened the system development service site "SEKARAKU Lab" to which I belong.
Beyond is a one-stop service for everything from server design and construction to operation, so if you have any trouble with server-side development, please feel free to contact us.
SEKARAKU Lab: [https://sekarakulab.beyondjapan.com/](https://sekarakulab.beyondjapan.com/)
Well, that's all for now.
3