Connecting to a remote service in client applications both standardizes the bussines logic and increases the efficiency of the program. “UnityWebRequest”, one of Unity’s network-related classes, replaces WWW and offers us a more successful and recommended solution.

Token for Authentication

We must first decide how to communicate securely with a web service. For WebClients, there is an attribute for the query to be made just like in Unity, “Credentials”, with this attribute we can enter the authentication information here, for example, username, password, mail address. This solution is a very heavy one whether for unity or any other platform. So we need to develop a lighter and simpler solution. For this, we will provide security via “Token”.

The token has two important characteristics:

  • Represents unique authentication.
  • It is time sensitive.

We understand the first point, uniqueness is an important point for a security, so what is the importance of the second point? The token is an encrypted string value and if it is not time sensitive, it will be easy for others to forge if stolen. An algorithm is needed to generate tokens, in the simplest form it would look like this:

md5(((day*10) + (month*100) + (last2DigitsofYear)*1000)+userId+deviceId)

In the same way, you can find out if the Token is correct by adding filters in front of the Web Service like this.

Request Pipeline

Pipline is used to represent a request flow. We have to use StartCoroutine due to UnityWebRequest itself, and using StartCoroutine under View will cause a stratification conflict which is something we don’t want in MVVM. We have to separate WebRequest which is Bussines Logic in MVVM from View. In this case the best solution is to use an HttpTool as a Singleton.

public class HttpTool : Singleton<HttpTool>
{
    // Cannot use the constructor in the outside world, ensure Singleton
    protected HttpTool() { }
}

Whether it’s Request or Response, it’s important to keep data as a Collection. It is easiest to define and manage this data as an object. In this case, we create a model structure that we can create an HttpRequest object and associate with the incoming Request.

public class HttpRequest
{
    public string Url { get; set; }
    public HttpMethod Method { get; set; }
    public string Parameters { get; set; }
}

And in the same way, we make the HttpResponse model and encapsulate the response returned from the Web service.

public class HttpResponse
{
    public bool IsSuccess { get; set; }
    public string Error { get; set; }
    public long StatusCode { get; set; }
    public string Data { get; set; }
}

Get and Post parameters create the same format, ie “field1=value1&field2=value2”. The difference between them; Get appends the parameters it wants to the URL, and Post adds it to the Request Body.
The core of Web Request is implemented by implementing UnityWebRequest provided by Unity and waiting for yield.

using (var www = UnityWebRequest.Get(url + parameters))
{
    yield return www.Send();
    var response = new HttpResponse
    {
        IsSuccess = !www.isError, Error = www.error, StatusCode = www.responseCode, Data = www.downloadHandler.text
    };
    onComplete(response);
}

Finally, the response string is deserialized into an object. The built-in JsonUtility class cannot deserialize a JSON array, but uses a type attribute inside a collection object. At this point a Request Pipline would look like this:

Request Pipeline UML

Strategy Pattern for Remote Repository

Due to many of JsonUtility’s limitations, you may want to consider using another third-party library. Or you use XML instead of deserialize as Json. So the codes in the RemoteRepository should not be restricted to deserialize. It should accept an external algorithm as “Strategy Pattern”. This also complies with SOLID principles.
To do this, we must add the serialization interface to the Remote Repository.

public ISerializer Serializer { get; set; }

Then HttpResponse deserializes the returned Json as follows:

Serializer.Deserialize<T>(httpResponse.Data)

For a correct implementation, the ISerializer interface should present a strategy form.

public class SerializerJson:ISerializer
{
    public static readonly SerializerJson Instance=new SerializerJson();
    private SerializerJson()
    {
        
    }
    public string Serialize<T>(T obj, bool readableOutput = false) where T : class, new()
    {
        throw new NotImplementedException();
    }

    public T Deserialize<T>(string json) where T : class, new()
    {
        return JsonUtility.FromJson<T>(json);
    }
}

Strategy Pattern has a widespread use, the most common is that you can send the method as Strategy in sorting algorithms.