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.
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.
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!
Check console.log on terminal too.
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!