Making a REST service using Node and Express to use with Unity - Part 3

Making a REST service using Node and Express to use with Unity - Part 3

Greetings to all unity ninjas!

This part we’ll make a POST request from a unity client to the node server. We haven’t made a database, yet, so I’ll make an array for now.

Start with server-side. In app.js, remember that we had a single enemy object, this part, I’ll make an array and populate with some enemy.

let enemies = [
	{
		"id": 0,
		"name": "orc",
		"health": 100,
		"attack": 25
	},
	{
		"id": 1,
		"name": "wolf",
		"health": 110,
		"attack": 25
	}
];

Next, tell express to support JSON-encoded bodies.

app.use(express.json());

Next, let’s make a post method to receive a request from unity client.

app.post('/enemy/create', (req, res) => {
let newEnemy = {
	"id": req.body.id,
	"name": req.body.name,
	"health": req.body.health,
	"attack": req.body.attack
};

enemies.push(newEnemy);
console.log(enemies);
res.send(enemies);
});

And I’ll modify my get method to fetch my enemies array. Now my app.js file looks like this:

const express = require('express');
const app = express();
app.use(express.json());

app.get('/', (req, res) => {
    res.send('Hello Unity Developers!');
});

let enemies = [
	{
		"id": 0,
		"name": "orc",
		"health": 100,
		"attack": 25
	},
	{
		"id": 1,
		"name": "wolf",
		"health": 110,
		"attack": 25
	}
];

app.get('/enemy', (req, res) => {
    res.send(enemies);
});

app.post('/enemy/create', (req, res) => {
let newEnemy = {
	"id": req.body.id,
	"name": req.body.name,
	"health": req.body.health,
	"attack": req.body.attack
};

enemies.push(newEnemy);
console.log(enemies);
res.send(enemies);
});

app.listen(3000, () => console.log('started and listening.'));

Open a terminal, start node and it’s time to visit unity client.

node app.js

Let’s make an api call, I’ll use postman.

Alt Text

Don’t forget to set header and body to application/json.

Now make an enemy json string based on the enemy schema and hit to send.

Alt Text

Alt Text

Seems our enemies growing :)

Last part, we have successfully received a json object and displayed it to screen with unity ui elements. But this part our structure has changed a bit. I’ve added id property to the enemy and my response now not an object but an array.

First, add id property to Enemy class in unity.

public class Enemy
{
    public int id;
    public string name;
    public int health;
    public int attack;
}

Yeah, that was easy! But keep in mind, JsonUtility does not work with {get; set;}.

Now the important part! If your task is to send a json array and parse in unity, there is no out of the box solution with JsonUtility, unfortunately. Don’t worry, after a couple googling and experimenting, I found a workaround, for a detailed explanation, take a look here and here.

For example, If your response is like this, then JsonUtility won’t work:

[
  {
  	//item
  },
  {
  	//item
  },
  {
  	//item
  }
]

Instead, we’ll make it a single key and an array object as a value:

{
	"result": [{//item},{//item},{//item}]
}

This way, we have a one list of items and this structure works with JsonUtility.

To make this trick possible we’ll make a static class named JsonHelper. Let’s create it in the project folder.

using UnityEngine;
using System.Collections.Generic;

public static class JsonHelper
{
    public static List<T> FromJson<T>(string json)
    {
        Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
        return wrapper.result;
    }

    [System.Serializable]
    private class Wrapper<T>
    {
        public List<T> result;
    }
}

JsonHelper class has a generic FromJson method that returns a list of any class we’re going to make. Here key part is the Wrapper class that has a result list that stores the values from. In our case, when we get an array of json objects from server, we have to modify our response string like this:

{
	"result": [
		//enemy,
		//enemy
	]
}

We have discussed our schema and made a helper class to make it work, let’s write some code!

First, mark the Enemy class as Serializable, so unity will be able to convert to json. More explanation here.

[System.Serializable]
public class Enemy
{
    public int id;
    public string name;
    public int health;
    public int attack;
}

Second, open ClientApi script and make a post method. It will take two parameters, post url and an enemy object to feed in unity’s post method.

public IEnumerator Post(string url, Enemy enemy)
{
  var jsonData = JsonUtility.ToJson(enemy);
  Debug.Log(jsonData);
  
  using(UnityWebRequest www = UnityWebRequest.Post(url, jsonData))
  {

  }
}

We are converting an Enemy object to a json string with JsonUtility.

Next, configure our request’s content-type.

public IEnumerator Post(string url, Enemy enemy)
{
  var jsonData = JsonUtility.ToJson(enemy);
  Debug.Log(jsonData);
  
  using(UnityWebRequest www = UnityWebRequest.Post(url, jsonData))
  {
		www.SetRequestHeader("content-type", "application/json");
    www.uploadHandler.contentType = "application/json";
    www.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(jsonData));
    
    yield return www.SendWebRequest();
  }
}

We have set our method to send a json object and to a url endpoint.

Remember that, we send back our enemies as a response after request. So, let’s make a list from the response, then display to console. Now, time to handle response end error.

// handle the result
var result = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);  
result = "{\"result\":" + result + "}"; 
var resultEnemyList = JsonHelper.FromJson<Enemy>(result);

foreach (var item in resultEnemyList)
{
  Debug.Log(item.name);
}

This is the part that we have discussed above. As soon as I get data, I modified it to be able to work with JsonHelper.

Then just display to console each element’s name to test.

public IEnumerator Post(string url, Enemy enemy)
{
  var jsonData = JsonUtility.ToJson(enemy);
  Debug.Log(jsonData);
  
  using(UnityWebRequest www = UnityWebRequest.Post(url, jsonData))
  {
		www.SetRequestHeader("content-type", "application/json");
    www.uploadHandler.contentType = "application/json";
    www.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(jsonData));
    yield return www.SendWebRequest();
    
    if (www.isNetworkError)
    {
      Debug.Log(www.error);
    }
    else
    {
      if (www.isDone)
      {
        // handle the result
        var result = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);  
        result = "{\"result\":" + result + "}"; 
        var resultEnemyList = JsonHelper.FromJson<Enemy>(result);

        foreach (var item in resultEnemyList)
        {
          Debug.Log(item.name);
        }
      }
      else
      {
        //handle the problem
        Debug.Log("Error! data couldn't get.");
      }
    }
  }
}

To test, define a string variable for post url, make an Enemy object in Start and switch back to unity.

public string getUrl  = "localhost:3000/enemy";
public string postUrl = "localhost:3000/enemy/create";

void Start()
{
  var enemy = new Enemy(){
    id = 100,
    name = "Balrog",
    health = 1000,
    attack = 2500
  };

  StartCoroutine(Post(postUrl, enemy));
}

Time to hit Play!

Alt Text

Check console.log on terminal too.

Alt Text

Good job, our unity ninja skills improved a bit more!!🎉🎉🎉🌟🌟🌟👏👏👏😎😎

Looks like we have successfully sent data from unity client, received from the server and responded with updated data 😎👾

Grab the code here.

Next part we’ll post with the ui element’s help and to handle data in unity, we’ll use Scriptable Objects.

Until the next part, cheers!