© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
S. Kelly, K. KumarUnity Networking Fundamentalshttps://doi.org/10.1007/978-1-4842-7358-6_3

3. RESTful APIs

Sloan Kelly1   and Khagendra Kumar2
(1)
Niagara Falls, ON, Canada
(2)
Katihar, Bihar, India
 
Up to this point, you have been learning about low-level concepts when it comes to networking. For the most part, though, network programming is done at the Application layer. This is the top-most layer of the OSI model, as shown in Figure 3-1, where your game sits.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig1_HTML.jpg
Figure 3-1

The OSI seven-layer network model

Your game might utilize some form of web service to get data for your game, such as leaderboards, friend’s lists, etc.

The UnityWebRequest class can be used to connect to a web server and perform web requests. It is possible to write your own code to do this using Sockets or TcpClient, but because this class exists and provides a lot of the functionality that you need already, it’s best to use it instead. Among other features, it can be used to get data from web pages using what is known as RESTful APIs.

What Is a RESTful API?

In its simplest form, a RESTful API is a way for clients to request data using a web URL (Uniform Resource Locator) and the request can be given a response in a known format from the server. The client can use HTTP verbs like GET, PUT, and DELETE to perform actions on the data. This matches up with typical CRUD (Create, Read, Update and Delete) operations like getting leaderboard data, saving or replacing player state, and deleting a save slot, for example. This means that the client does not have to be written in the same language as the server. Because the requests use URLs and standard HTTP messages, there is no need to open additional ports. The developer just needs to be able to request a web page to read or write information.

REST is short for REpresentational State Transfer . API is short for Application Programming Interface . As long as the client and the server agree on the messages – the format of the requests and their responses – and how those requests are made using HTTP, both the client and the server will understand the messages passed between them.

Note

REST is a concept; it does not define the API. APIs are different for each service.

As shown in Figure 3-2, a request is made to a website using a RESTful call. The response that returns is a JSON string.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig2_HTML.jpg
Figure 3-2

A RESTful request and response showing a GET request for a leaderboard and the JSON response that’s returned

RESTful Requests

Each URL that’s used to access a RESTful API is called a request and it is made up of four things:
  • An endpoint

  • A method

  • Headers

  • The data, also known as the body

The Endpoint

This is the URL that forms the request for the data you need. It is somewhat arbitrary and depends on the API creator, but it follows the structure:
https://server/path/feature/sub-feature
For example:
https://api.example.com/games/leaderboard
There is also a root endpoint. This is the starting point of the API and usually includes the protocol. For example:
https://api.example.com

A Method

The path is what comes after the root endpoint. For example:
/games/leaderboard

You need to look at the service’s API documentation to see the paths that it offers. For example, there is extensive documentation for the Steam API at https://developer.valvesoftware.com/wiki/Steam_Web_API. You could think of paths as being synonymous with functions and methods in a normal program.

Sometimes a path in an API document will specify a colon. This means that you should put in a value there. For example, let’s say your service has leaderboards for lots of games. You might see a path defined in a document as follows:
/games/:gamename/leaderboard
To access the leaderboard of your game called “Jump Game” for example, you might have a path like so:
/games/jump-game/leaderboard

The Headers

The headers provide extra information to the client and server. Headers can be used for a number of reasons, including authentication and providing additional metadata to the receiving device.

HTTP headers are property-value pairs that are separated by a colon. The following example shows a header that identifies the content as a JSON string:
Content-Type: application/json

The Data

The data is sometimes called the body or the message. It contains information that you want to send to the server. This option is only used with POST, PUT, PATCH, and DELETE requests. Examples are shown in Table 3-1.
Table 3-1

HTTP Verbs and Their Uses

HTTP Verb

Use

POST

Create something new on the server, such as when a player logs in for the first time.

PUT

Create or update. This could be used when saving player state to the server.

PATCH

Update a small amount of information. For example, when the player updates their password.

DELETE

Remove something from the game. For example, when a player deletes their account.

RESTful Responses

The format of the response varies from service to service but it is typically formatted as a JSON string. This string can be easily converted into a class using a JSON parser like the one provided by Unity’s JsonUtility class.

Responses can also contain additional HTTP headers. These are the same HTTP headers as for the client/server requests. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers for more information.

Authentication and Restrictions

You should be respectful of the limits placed by the API provider. They usually limit you to a few hundred calls per minute. More calls than that and you could find yourself banned from the service after repeat offenses.

RESTful API providers also want to ensure that only authorized users have access to their services. This means that you will most likely have to go through some authentication process like OAuth or provide a token as part of the URL, typically called an API token, that uniquely identifies your application. Tokens usually take the form of a large hexadecimal number:
42dca02c33584aa783280d83d5e01d04

The major difference is who owns the authority to use the website. With OAuth, the user must validate themselves to a provider like Google, Facebook, Twitter, or OpenID using a username and password. The result is that they receive a token to use with the remote server. The token is unique to the user.

In the case of the client application owning the authorization, the API key becomes the token. The token is unique to the application.

Note

Always keep tokens and passwords safe! Do not let your token fall into the wrong hands!

In the weather application detailed later in this chapter, you will be using the simpler API token method for OpenWeatherMap rather than OAuth.

The UnityWebRequest Class

Reading and writing data to a remote website is made possible through the UnityWebRequest class . You do not create a UnityWebRequest class directly. Instead you use the Get() method and pass in the URL of the RESTful API endpoint.

The UnityWebRequest class is typically used in a co-routine because of its asynchronous nature. A request is made and at some point in the future that request is given a response.

A normal function in Unity must execute completely before anything else can complete. If there is a function that takes a long time, this will affect the performance of your game. To combat this, Unity created co-routines. These are functions that yield control back to Unity when they need to wait longer than a frame to complete. When the function is called again, it picks up where it left off. See https://docs.unity3d.com/Manual/Coroutines.html for more details.

Errors are handled by checking the isNetworkError and isHttpError properties once the request operation has completed. The text of the error is contained in the error property of the request instance.

The response is located in the text property of the web request’s downloadHandler. This is just C# code and no further processing is required. The response will usually be in the JSON format, so creating classes from it is a simple matter of using JsonUtility.FromJson<T>().

Fetching Text

Listing 3-1 illustrates how to fetch a web page. For this example, it’s the Google home page. The script can be attached to a game object like the Main Camera in a blank project and run.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class FetchGoogle : MonoBehaviour
{
    IEnumerator Start()
    {
        UnityWebRequest request = UnityWebRequest.Get("https://www.google.com/");
        yield return request.SendWebRequest();
        if (request.result == UnityWebRequest.Result.Success)
        {
            Debug.Log(request.downloadHandler.text);
        }
        else
        {
            Debug.Log(request.error);
        }
    }
}
Listing 3-1

Fetch the Google Home Page from the Web Using UnityWebRequest

The Start() method is a co-routine that will not stall out the game while the web request is waiting for a response. The SendWebRequest() method returns an enumerator that exits when either an error occurs or when the data has been received.

If an error occurs in this example, it is printed to the console. If data is returned it is printed to the console, as shown in Figure 3-3. This is the HTML of the Google home page—the one with the search box in the middle of the screen.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig3_HTML.jpg
Figure 3-3

The output from the FetchGoogle script showing the contents of the Google home page’s HTML

Note

A request is required for each resource. If you were building a web server, you would have to make several requests for the HTML page, each image, each stylesheet, and each JavaScript file needed to display the page completely.

Fetching Images

The UnityWebRequest class can be used to return an image. The following example fetches the Unity Logo from Wikimedia Commons, as shown in Figure 3-4.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig4_HTML.jpg
Figure 3-4

The Unity logo as shown on the Wikimedia Commons website

Creating the Project

Create the project by completing the following steps:
  1. 1.

    Create a new 2D project from Unity Hub named Fetch Example.

     
  2. 2.

    Add an empty GameObject to the scene called Logo.

     
  3. 3.

    Add a SpriteRenderer component to the Logo GameObject.

     
  4. 4.

    Create a new folder in Assets called Scripts.

     
  5. 5.

    Inside the Scripts folder, create a C# script called FetchLogo.

     
  6. 6.

    Attach the FetchLogo script to Logo using the Add Component button or by dragging the script onto Logo.

     
The GameObject’s component list should look like the one shown in Figure 3-5. Save the scene.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig5_HTML.jpg
Figure 3-5

The list of components added to the game object

Fetching the Image

The UnityWebRequest class is part of a group of classes that are used to download data from remote websites. To download an image, use the UnityWebRequestTexture class.

Open the FetchLogo script and change the script to look like Listing 3-2.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class FetchLogo : MonoBehaviour
{
    IEnumerator Start()
    {
        string url = "https://upload.wikimedia.org/wikipedia/commons/8/8a/Official_unity_logo.png";
        var request = UnityWebRequestTexture.GetTexture(url);
        yield return request.SendWebRequest();
        if (request.result == UnityWebRequest.Result.Success)
        {
            var textureHandler = request.downloadHandler as DownloadHandlerTexture;
            Texture2D texture = textureHandler.texture;
            SpriteRenderer = GetComponent<SpriteRenderer>();
            var rect = new Rect(0, 0, texture.width, texture.height);
            spriteRenderer.sprite = Sprite.Create(texture, rect, Vector2.zero);
        }
        else
        {
            Debug.Log(request.error);
        }
    }
}
Listing 3-2

Fetching an Image from a Website Using UnityWebRequestTexture

Instead of using the Get() method, as you did for the text, the GetTexture() method is used. This returns an instance of UnityWebRequestTexture, but, the actual return is an object of type UnityWebRequest. You must do some casting to get the objects back to the type that you need in order to get the texture.

The download handler that is returned from a UnityWebRequest is a standard DownloadHandler instance. However, after casting the UnityWebRequestTexture’s downloadHandler property to the DownloadHandlerTexture class, we can access the downloadHandler’s texture property.

Then it is a simple matter of creating a Sprite object and passing the downloaded texture. When run, the image is downloaded and the sprite is constructed, as shown in Figure 3-6.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig6_HTML.jpg
Figure 3-6

The Unity logo is displayed in the game after downloading it from the remote site

Fetching Other Types

Other resources can be downloaded from websites by using the appropriate UnityWebRequest class and the associated DownloadHandler :
  • Audio – UnityWebRequestMultimedia/DownloadHandlerAudioClip

  • Asset Bundle – UnityWebRequestAssetBundle/DownloadHandlerAssetBundle

  • Text – UnityWebRequest/DownloadHandler

  • Textures – UnityWebRequestTexture/DownloadHandlerTexture

Asset bundles can group assets together. Typical uses include texture packs and downloadable content (DLC).

The Weather Application

In this chapter, you are going to build a functioning application that uses data provided by a remote site. Access to the data is through a RESTful API and requires a token.

The OpenWeather project provides accurate weather forecasting data and has an API with which to build your own applications. The website, shown in Figure 3-7, is located at https://openweathermap.org/.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig7_HTML.jpg
Figure 3-7

The OpenWeather home page

Registering and Getting an API Key

Before you start, you need to obtain an API key. This key will be used in all your queries. To obtain a key, you must first get an account with the site. To do that, locate the Sign In menu option along the top of the page and click the Create an Account link. This will take you to the sign-up page, as shown in Figure 3-8.

Once completed, you will get a confirmation message sent to the email account that you provided. Do not forget to verify your email address!

Note

It can take upwards of two hours to get a confirmation back while OpenWeather creates a valid key.

../images/504537_1_En_3_Chapter/504537_1_En_3_Fig8_HTML.jpg
Figure 3-8

The OpenWeather sign-up page

Once logged in, you will be taken to your account home page. Click the API Keys link shown in Figure 3-9.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig9_HTML.jpg
Figure 3-9

The API Keys link shown in a box

By default, an API key is defined for you with the name default. You can edit this to be any name you like: for example, the name of your application. The most important part, though, is the key itself. This is what will be used to verify your application when you make a call to an API. Figure 3-10 shows my API key that I have renamed to Unity Net Book. The name is more of a mnemonic for you and is not required when making an API call.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig10_HTML.jpg
Figure 3-10

The default API key has been renamed Unity Net Book

Note

Each new application requires a different API key.

The User Interface

The application’s user interface, shown in Figure 3-11, includes a text box to allow users to enter their city and country, a button to fetch data, and a button to toggle between Celsius and Fahrenheit.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig11_HTML.jpg
Figure 3-11

The application showing the five day forecast for New York City

The resources for this project can be obtained by clicking the Download Source Code button located at www.apress.com/9781484273579. This includes the images for the weather icons, the prefabs for each day, and the fonts.

Creating the Project

Follow these instructions to create the basic WeatherApp project :
  1. 1.

    Create a new blank 2D project in Unity Hub named weather-app.

     
  2. 2.

    Import the weather-application.unitypackage from the resources folder on the GitHub repo to get the prefabs, images, fonts, and starting scene.

     

Importing the weather-application.unitypackage

In the Unity editor, choose Assets ➤ Import Package ➤ Custom Package from the main menu. In the Import Package dialog box, locate the weather-application.unitypackage and open it. Figure 3-12 shows the contents of the package. These files will be added to the blank project. Click Import at the bottom-right side of the dialog to add the files to your project.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig12_HTML.jpg
Figure 3-12

The Import Unity Package window showing the contents of the weather-package.unitypackage

The OpenWeather Daily Forecast Endpoint

The OpenWeather daily forecast endpoint allows clients to request up to 16 days of weather from the system. The endpoint documentation is located at https://openweathermap.org/forecast16. The API documentation states that the endpoint is located at:
https://api.openweathermap.org/data/2.5/forecast/daily

The endpoint takes in three parameters that will be passed to the method using an HTTP query string, which you need to provide in order to obtain the data.

A query string is set of key-value pairs that appear after the question mark (?) character in a web address. The key and the value are separated by an equals sign (=). Query strings are not secure because they are part of the web address and are sent in plain text.

The three parameters are:
  • q – The city and country code of the location.

  • cnt – The number of days to return. You will set this to 5 in your example.

  • appid – The API key for the application.

To request the forecast in Boston for the next five days, the URL would look like the following – API key truncated:
https://api.openweathermap.org/data/2.5/forecast/daily?q=Boston&cnt=5&appid=dc54fac
The API can be tested using the CURL command. Curl stands for client URL and is used to download resources from websites on the command line. It’s perfect for testing APIs because of this. Open a terminal window or DOS prompt. At the prompt, type in the command like so. Don’t forget to change your appid to your application’s ID:
$ curl "https://api.openweathermap.org/data/2.5/forecast/daily?q=Boston&cnt=5&appid=dc54fac"
The query (q) must be URL-encoded. This means that the string will have whitespace characters trimmed out and problematic characters replaced with HTML entities. For example, a space becomes a plus symbol (+). The example shows two lines—the normal text followed by the URL-encoded version:
Niagara Falls, Ontario
Niagara+Falls%2c+Ontario
The .NET framework’s HttpUtility class has a method called UrlEncode() that will take a string and return the URL-encoded version:
var urlEncodedCity = HttpUtility.UrlEncode(city);

Fetching the Data

With the barebones project imported via the package, you need to create additional scripts that will:

  • Provide classes to decode the JSON message received from the API call

  • Use a common function to make the call to the API

  • Send out the request when the user clicks the Fetch button

Let’s start by creating the script files you need. In the Unity Editor’s Project view, open the Scripts folder and add the following C# script files:
  • FetchResults

  • OpenWeatherMapAPI

Then create a new folder in Scripts called Serialization. Create the following C# script files inside the Serialization folder :
  • ResponseContainer

  • ResponseItem

  • ResponseTemperature

  • WeatherItem

The last four C# script files will hold the response from the server. You should now have a project that looks like the hierarchy shown in Figure 3-13.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig13_HTML.jpg
Figure 3-13

The project hierarchy for the weather application

Serialization Classes

The serialization classes in Scripts/Serialization will just be plain classes with public fields that will be populated with data.

Note

Unity’s JsonUtility can only serialize/deserialize public fields. Do not use properties for your serialization classes!

The shape of the data (i.e. the names of the fields and the class structure) is dictated by the application. In the case of the daily forecast from OpenWeather, this is defined at https://openweathermap.org/forecast16#JSON and a portion of it is shown in Figure 3-14.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig14_HTML.jpg
Figure 3-14

Example showing the shape of the data returned from the API endpoint for daily forecasting using the OpenWeather API

The date (dt), sunrise, and sunset fields are 10 digits long. These values are the number of seconds since midnight on 1/1/1970. You’ll learn how to create a function to convert them to something human readable later in the UnixTimeToDateTime() function .

Taking this hierarchy, you can draw a diagram to represent the parent-child relationships of each class as shown in Figure 3-15.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig15_HTML.jpg
Figure 3-15

The parent-child relationships of the response message from OpenWeather’s API call

The ResponseContainer is the message received from the server. Each ResponseItem is a day of the week.

The leaf node in this hierarchy is what I called the WeatherItem and it is defined in Listing 3-3.
using System;
[Serializable]
public class WeatherItem
{
    public int id;
    public string main;
    public string description;
    public string icon;
}
Listing 3-3

The WeatherItem Script

This class contains the icon used to visually represent the weather as well as a description of the weather itself. Paired with the WeatherItem class is the ResponseTemperature class, shown in Listing 3-4. It contains, unsurprisingly, the temperature for the parts of the day. The temperatures returned from the API are in Kelvin. You will write a function called ToHumanTemperature() that will convert the temperature from Kelvin to Celsius or Fahrenheit.

Note

Zero Kelvin is approximately -273 Celsius or -460 Fahrenheit!

using System;
[Serializable]
public class ResponseTemperature
{
    public float day;
    public float night;
    public float min;
    public float max;
    public float eve;
    public float morn;
}
Listing 3-4

The ResponseTemperature Script

Daily temperatures, icons, and descriptions are contained in the ResponseItem class , as shown in Listing 3-5. This represents a single day’s results in addition to the sunrise and sunset times for that day.
using System;
[Serializable]
public class ResponseItem
{
    public long dt;
    public ResponseTemperature temp;
    public WeatherItem[] weather;
    public long sunrise;
    public long sunset;
}
Listing 3-5

The ResponseItem Script

The dt, sunrise, and sunset fields are not in the DateTime format. This is because the OpenWeatherMap API returns times in what is called UNIX Epoch time. This is the number of seconds since midnight on 1/1/1970.

Lastly, the actual message itself is represented in code as ResponseContainer, as shown in Listing 3-6. It contains a collection of ResponseItem instances as well as the count of the number of days requested.
using System;
[Serializable]
public class ResponseContainer
{
    public string cod;
    public float message;
    public int cnt;
    public ResponseItem[] list;
}
Listing 3-6

The ResponseContainer Script

Now that the serializable classes have been defined, you can take a look at creating a MonoBehaviour that queries the OpenWeather endpoint for a particular location and returns the result to the caller.

Calling the API

As in the previous examples, you will use the UnityWebRequest class to fetch the data from the remote server. JsonUtility.FromJson<T>() is used to create the ResponseContainer from the JSON response.

There is one exposed field that is settable through the Unity editor for the API key. You will have to provide that key yourself. The entire class is shown in Listing 3-7.
using System.Collections;
using System.Web;
using UnityEngine;
using UnityEngine.Networking;
public class OpenWeatherMapAPI : MonoBehaviour
{
    private static readonly string ApiBaseUrl = "https://api.openweathermap.org/data/2.5/forecast/daily?q={0}&cnt=5&appid={1}";
    [Tooltip("The key that allows access to the OpenWeatherMap API")]
    public string apiKey;
    public ResponseContainer Response { get; private set; }
    public IEnumerator GetForecast(string city)
    {
        Response = null;
        string urlEncodedCity = HttpUtility.UrlEncode(city);
        string url = string.Format(ApiBaseUrl, urlEncodedCity, apiKey);
        UnityWebRequest webRequest = UnityWebRequest.Get(url);
        yield return webRequest.SendWebRequest();
        if (webRequest.result == UnityWebRequest.Result.Success)
        {
            string json = webRequest.downloadHandler.text;
            Response = JsonUtility.FromJson<ResponseContainer>(json);
        }
        else
        {
            Debug.Log(webRequest.error);
        }
    }
}
Listing 3-7

The OpenWeatherMapAPI MonoBehaviour Script

Notice that the endpoint is stored as a constant called ApiBaseUrl and the string.Format() method is used to place the query and the API key in the query. Also of note is the UrlEncode() method, which is used to encode the query string.

This MonoBehaviour is used by the final script that you write, which acts as a controller for the whole application. If you were writing an application that uses a lot of API calls, it would be rather inefficient to rewrite this over and over again. At the end of this chapter, you’ll take a look at making this more generic.

The Controller: Final Wiring

The controller acts as the glue code between the UI and the API. The script is attached to the FetchButton object in the project hierarchy, shown in Figure 3-16, along with the OpenWeatherMapAPI MonoBehaviour.
../images/504537_1_En_3_Chapter/504537_1_En_3_Fig16_HTML.jpg
Figure 3-16

The FetchButton GameObject with the two script components: FetchResults and OpenWeatherMapAPI

The FetchResults class, as shown in Listing 3-8, adds a click event handler to the button to which it is attached. The event handler calls the FetchData() method and that in turn calls the OpenWeatherMapAPI’s GetForecast() method. On a successful response, the day prefabs are filled.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class FetchResults : MonoBehaviour
{
    private static readonly string DefaultIcon = "01d";
    private bool isRunningQuery;
    private Button;
    private OpenWeatherMapAPI api;
    private Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
    public GameObject loadingMessage;
    public TMP_InputField cityInputField;
    public DayCard[] dayCards;
    public Sprite[] spriteIcons;
    public CanvasGroup panel;
    void Awake()
    {
        button = GetComponent<Button>();
        api = GetComponent<OpenWeatherMapAPI>();
        // Create the dictionary that maps the name of the sprite to its image
        foreach (Sprite s in spriteIcons)
        {
            sprites[s.name] = s;
        }
        button.onClick.AddListener(delegate
        {
            if (!string.IsNullOrEmpty(cityInputField.text.Trim()) && !isRunningQuery)
            {
                StartCoroutine(FetchData(cityInputField.text));
            }
        });
    }
    private IEnumerator FetchData(string query)
    {
        isRunningQuery = true;
        panel.alpha = 0;
        loadingMessage.SetActive(true);
        yield return api.GetForecast(query);
        loadingMessage.SetActive(false);
        isRunningQuery = false;
        if (api.Response != null)
        {
            FillDays(api.Response);
            panel.alpha = 1;
        }
    }
    private void FillDays(ResponseContainer response)
    {
        panel.alpha = 1;
        for (int i = 0; i < dayCards.Length; i++)
        {
            var icon = response.list[i].weather[0].icon;
            if (!sprites.ContainsKey(icon))
            {
                icon = DefaultIcon;
            }
            Sprite = sprites[icon];
            DayCardModel day = new DayCardModel(response.list[i], sprite);
            DayCard = dayCards[i];
            dayCard.SetModel(day);
        }
    }
}
Listing 3-8

The FetchResults MonoBehaviour script

The final thing to do is to enter the API token on the OpenWeatherMapAPI script in the Unity Editor. At this point, you can test the application—everything is complete!

Running the Weather Application

Save all the open code files in your editor/IDE. In the Unity Editor, click the Play button to start the app. Enter your location in the text box and click the Fetch button. You should see the days appear. If not, here are some things to check:
  • The code is typed exactly as written

  • You have a network connection

  • You have entered the API token correctly

  • Your token is valid

Remember that it can take up to two hours for the token to be validated by the OpenWeather service. Check your email!

Generic RESTful API Client

As I mentioned earlier, you may find yourself doing multiple calls to various endpoints to build your client. If this is the case, it is better to abstract the remote call out of the class and into a helper class.

Listing 3-9 shows how this can be achieved using a static method on a static class. The RestfulHelper class’ Fetch method takes three parameters:
  • endPoint – The endpoint of the API method

  • onSuccess – An action to be called when the data has been successfully received by the client

  • onError – An action to be called when the data could not be retrieved by the client

The helper class also correctly handles the disposal of the UnityWebRequest class by wrapping it inside a using block.
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public static class RestfulHelper
{
    public static IEnumerator Fetch<T>(string endPoint, Action<T> onSuccess, Action<string> onError) where T: class, new()
    {
        using (UnityWebRequest webRequest = UnityWebRequest.Get(endPoint))
        {
            yield return webRequest.SendWebRequest();
            if (webRequest.isNetworkError || webRequest.isHttpError)
            {
                onError?.Invoke(webRequest.error);
            }
            else
            {
                string json = webRequest.downloadHandler.text;
                onSuccess?.Invoke(JsonUtility.FromJson<T>(json));
            }
        }
    }
}
Listing 3-9

The RestfulHelper Class

The OpenWeatherMapAPI class can now be rewritten (see Listing 3-10) to take advantage of this new helper class. Any additional endpoint calls can be defined in this class and called each from a separate method. Because you’re calling only one endpoint, you use GetForecast(), but you could add other methods, like GetDailyForecast(), GetGlobalAlerts(), etc.
using System;
using System.Collections;
using System.Web;
using UnityEngine;
class OpenWeatherMapAPI : MonoBehaviour
{
    private static readonly string ApiBaseUrl = "https://api.openweathermap.org/data/2.5/forecast/daily?q={0}&cnt=5&appid={1}";
    [Tooltip("The key that allows access to the OpenWeatherMap API")]
    public string apiKey;
    public IEnumerator GetForecast(string city, Action<ResponseContainer> onSuccess)
    {
        string urlEncodedCity = HttpUtility.UrlEncode(city);
        string url = string.Format(ApiBaseUrl, urlEncodedCity, apiKey);
        yield return RestfulHelper.Fetch(url, onSuccess, print);
    }
}
Listing 3-10

The Refactored OpenWeatherMapAPI Class Utilizing the RestfulHelper Static Class

With the signature of GetForecast() changing, Action<ResponseContainer> has been added as a required parameter. You must also change the FetchResults.FetchData() method , as shown in Listing 3-11.
private IEnumerator FetchData(string query)
{
    runningQuery = true;
    panel.alpha = 0;
    loadingMessage.SetActive(true);
    yield return api.GetForecast(query, FillDays);
    loadingMessage.SetActive(false);
    runningQuery = false;
}
Listing 3-11

The Modified FetchData() Method in the FetchResults Class

The bold code line is the one that performs the API call to get the forecast data. The FillDays() method will be called automatically once the remote call has completed successfully.

Summary

Your game can act as a client to a remote service that exposes various methods using a RESTful interface. This will allow you to perform read and write operations on remote data. These are performed by requesting a particular URL or endpoint.

There are two methods of authentication: one is per user, the other is per application. OAuth requires users to sign in to a service like Google, Twitter, etc. and obtain a token. The alternative is that the application provides the token. The token is then passed via each call to the remote server to validate the request. Out of date or invalid tokens will get rejected.

Results from the remote service are usually returned in a JSON format. Classes can be easily created using the JSON function built into Unity.

If you are making multiple calls to different endpoints, it is a good idea to create a generic function to perform the remote calls.

The weather application uses a high-level client server architecture. It’s now time to switch gears and look at the lower-level socket programming that is provided as part of the .NET framework, as this will allow you to create your own protocols.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.40.207