- Home /
Write data to Json database using SimpleJson.cs
Hello,
I would like to write player data to my JSON "database".
For the Json parser and builder I'm using:
link text
Json URI example
link text
Json Editable:
link text
I would like to add "diamonds" with a value of 20. I have the following, but it does not work. Any ideas?
using System.Collections.Generic;
using UnityEngine;
using SimpleJSON;
public class Account: MonoBehaviour
{
void Start()
{
StartCoroutine(RequestNews(new WWW("https://www.jsonblob.com/api/jsonBlob/2a285d64-aec8-11e7-9b68-511b2c1e157d")));
}
IEnumerator RequestNews(WWW www)
{
yield return www;
if(www.error == null)
{
var N = JSON.Parse(www.text);
var name = N["diamonds"] = 20;
}
}
Answer by Bunny83 · Oct 11, 2017 at 10:08 PM
Uhm i don't quite understand the question.
This line:
var name = N["diamonds"] = 20;
would add a new number "field" to the object and set it to "20".
So if the incoming JSON was
{
"id": "example of id",
"username": "example of username"
}
after that line the structure would be:
{
"id": "example of id",
"username": "example of username",
"diamonds": 20
}
This can easily be verified by just printing it out again as text:
Debug.Log(N.ToString(3));
Of course in your code you don't do anything with it so that addition it pretty pointless. I have the feeling you somehow want to save this addition somehow to the server where you get it originally from. This is not possible out of the box. The server would need some kind of web API which allows you / others to change the information stored on the server. Though the question isn't really clear.
edit
Keep in mind that this jsonBlob service ie only ment for testing purposes. I quickly created this helper class to provide the two API endpoints PUT and GET. Those are coroutines which have callbacks for the returned data:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;
public static class JSONBlobAPI
{
static string url = "https://jsonblob.com/api/jsonBlob";
public static IEnumerator Post(JSONNode aNode, System.Action<string> aCallback, System.Action<string> aError)
{
var req = new UnityWebRequest(url, "POST");
byte[] data = Encoding.UTF8.GetBytes(aNode.ToString());
req.uploadHandler = new UploadHandlerRaw(data);
req.uploadHandler.contentType = "application/json";
req.downloadHandler = new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
req.SetRequestHeader("accept", "application/json");
yield return req.Send();
if (req.responseCode != 201)
{
if (aError != null)
aError(req.error);
}
else
{
string blobURL = req.GetResponseHeader("Location");
// extract blobID from response URL and return it
int i = blobURL.LastIndexOf("/");
aCallback(blobURL.Substring(i + 1));
}
}
public static IEnumerator Put(JSONNode aNode, string aBlobID, System.Action aCallback, System.Action<string> aError)
{
var req = UnityWebRequest.Put(url +"/"+ aBlobID, aNode.ToString());
req.SetRequestHeader("Content-Type", "application/json");
yield return req.Send();
if (req.responseCode != 200)
{
if (aError != null)
aError(req.error);
}
else if (aCallback != null)
aCallback();
}
public static IEnumerator Get(string aBlobID, System.Action<JSONNode> aCallback, System.Action<string> aError)
{
var req = UnityWebRequest.Get(url +"/"+ aBlobID);
req.SetRequestHeader("accept", "application/json");
req.SetRequestHeader("Content-Type", "application/json");
yield return req.Send();
if (req.responseCode == 200 && !req.isError)
{
JSONNode N = JSON.Parse(req.downloadHandler.text);
aCallback(N);
}
else
{
if (aError != null)
aError(req.responseCode + " " + req.error);
}
}
public static IEnumerator Delete(string aBlobID, System.Action aCallback, System.Action<string> aError)
{
var req = UnityWebRequest.Delete(url + "/" + aBlobID);
req.SetRequestHeader("Content-Type", "application/json");
yield return req.Send();
if (req.responseCode != 200)
{
if (aError != null)
aError(req.error);
}
else if (aCallback != null)
aCallback();
}
}
Those two coroutines can be used in your own coroutine or just start it and wait for the callback. I've tested it with a blob i created myself and i can successfully read and parse it (Get) as well as modifying and writing it back (Put).
For example:
IEnumerator SomeCoroutine()
{
JSONNode N = null;
yield return StartCoroutine(JSONBlobAPI.Get("2a285d64-aec8-11e7-9b68-511b2c1e157d", (data)=>N = data, (e)=>Debug.Log("Error reading: " + e)));
N["diamonds"] = 20;
yield return StartCoroutine(JSONBlobAPI.Put(N, "2a285d64-aec8-11e7-9b68-511b2c1e157d",()=>Debug.Log("Update successful"), (e)=>Debug.Log("Error writing: " + e)));
}
edit
I just implemented the other two endpoints as well (POST and DELETE). Now you can create and delete blobs on that service as well. The Post request will return the blob ID of the newly created blob. This ID can be used to update (Put), read (Get) or to remove (Delete) the blob.
Note that if you had already copied the old version of the script you should replace it entirely since some things have changed in the old code.
ps: I didn't use the shortcut Unity provides for Post because it automatically does URLEncode the posted string and set the content type to "application/x-www-form-urlencoded" which won't be accepted by this service. So in the Post coroutine i actually create the UnityWebrequest "manually" because it won't work otherwise.
It looks like the service you use has a HTTP API for modifying the data. However it requires a PUT request to update a JSON blob. This can't be done with WWW. You would need to use something like the "UnityWebRequest" which is able to perform PUT requests.
Hello and thank you for your response.
Everything is working perfectly. I replaced the following:
JSONNode N;
With:
JSONNode N = null;
Because I received the following error:
Error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement.
$$anonymous$$y only question is how will I change the JsonNode create something like this:
{
"email":
{
"password": "password",
"username": "username",
"score": 0,
}
}
So whenever user created the account it must replace the "email" with the actual email and then also for the rest.
Yes, the compiler is a bit picky about not initialized local variables. Though the error you mentioned is not related to the uninitialized local variable. I haven't actually tested the example coroutine in my project. I get the correct error
error CS0165: Use of unassigned local variable `N'
The json blob you store should have one root object. If you want to store the accounts directly into that object you would just do:
var account = N[yourEmailAddressString].AsObject;
account["password"] = yourPassword;
account["username"] = yourUsername;
account["score"] = 0;
However keep in $$anonymous$$d that this approach should never be used in any product you publish. All the data you store in this way would be visible to anybody. If you treat your users data like this you can get in serious trouble. You have to take security measures to protect sensitive userdata and respect the privacy of your users. That means you can not store their email address, username and password on a public available server in a way that everybody can read this information.
Again, this service is only ment to quickly test your API as it would finally work on your production server. A server would never return things like the server side password to a client. The password is usually stored on the server and is checked on the server. Also you don't want to store passwords in plain text.
Your answer
Follow this Question
Related Questions
C# Convert json arrays to unity arrys 3 Answers
Help using LitJson 1 Answer
Write data using SimpleJSON? 0 Answers
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers