1

I am using the Uber API inside of Unity and I am able to login and then authenticate to get the Token, but I have run into a roadblock when calling the actual API.

I believe my issue is that I need to be making the call in JSON format, but I don't know how to do that. I'm new to HTTP and API's in general. Here is my code:

    private IEnumerator TestRequest(){
    Debug.Log(sToken);
    WWWForm form = new WWWForm();
    //WWW www = new WWW();
    form.headers["Content-Type"] = "application.json";
    form.headers["Authorization"] = "Bearer " +sToken;
    form.AddField( "fare_id", "abcd");
    form.AddField("product_id", "a1111c8c-c720-46c3-8534-2fcdd730040d");
    form.AddField("start_latitude", "37.761492");
    form.AddField("start_longitude", "-122.42394");
    form.AddField("end_latitude", "37.775393");
    form.AddField("end_longitude", "-122.417546");

    yield return null;

    using(UnityWebRequest uweb = UnityWebRequest.Post("https://sandbox-
    api.uber.com/v1.2/requests", form)){
        yield return uweb.Send();
        if(uweb.isError) Debug.Log(uweb.error);
        else Debug.Log(uweb.downloadHandler.text);
        //GetVals(uweb.downloadHandler.text);
    }
}

This works for me in other areas, but not in this one and I think it has something to do with the Content Type being JSON, but I can't figure out how to send it in the right format. Apologies that I can't be more specific, I'm only just getting my head around this stuff.

Any help would be greatly appreciated!

  • 1
    I wonder if you should do: `form.headers["Content-Type"] = "application/json"` (notice the slash instead of the dot) – Charlyn G May 05 '17 at 20:46
  • also, is `sToken` a server token? If it is, then that line should be: `form.headers["Authorization"] = "Token " +sToken;` – Charlyn G May 05 '17 at 20:57
  • Thanks @Charlyn, but that didn't solve the issue. I did need to change it to "application/json", and I also tried both "Bearer " and "Token " but neither worked. I have also tried with the Access token that I can generate from the developer dashboard, which leads me to believe that the issue is with the format that I'm passing the information in. Not sure though. – Nahele Allan-Moon May 06 '17 at 09:05
  • My thinking regarding the JSON format is because of this SO post: http://stackoverflow.com/questions/40945491/uber-invalid-oauth-2-0-credentials-provided-uber-authentication-in-android, but I can't figure out how to use the Unity C# functionality available to replicate the same thing. – Nahele Allan-Moon May 06 '17 at 09:09

2 Answers2

2

Like others mentioned, application.json should be application/json.

This is not the only problem. Since it is a json, you don't need to use WWWForm class. Create a class to hold the Json data then create new instance of it. Convert the instance to json and pass it to the second parameter of the UnityWebRequest Post function.

UnityWebRequest:

For UnityWebRequest, use the UnityWebRequest Post(string uri, string postData); overload which let's you pass the url and the json data. You then use SetRequestHeader to set the headers.

[Serializable]
public class UberJson
{
    public string fare_id;
    public string product_id;
    public double start_latitude;
    public double start_longitude;
    public double end_latitude;
    public double end_longitude;
}

void Start()
{
    postJson();
}

string createUberJson()
{
    UberJson uberJson = new UberJson();

    uberJson.fare_id = "abcd";
    uberJson.product_id = "a1111c8c-c720-46c3-8534-2fcdd730040d";
    uberJson.start_latitude = 37.761492f;
    uberJson.start_longitude = -122.42394f;
    uberJson.end_latitude = 37.775393f;
    uberJson.end_longitude = -122.417546f;

    //Convert to Json
    return JsonUtility.ToJson(uberJson);
}

void postJson()
{
    string URL = "https://sandbox-api.uber.com/v1.2/requests";

    //string json = "{ \"fare_id\": \"abcd\", \"product_id\": \"a1111c8c-c720-46c3-8534-2fcdd730040d\", \"start_latitude\": 37.761492, \"start_longitude\": -122.423941, \"end_latitude\": 37.775393, \"end_longitude\": -122.417546 }";

    string json = createUberJson();

    string sToken = "";

    //Set the Headers
    UnityWebRequest uwrq = UnityWebRequest.Post(URL, json);
    uwrq.SetRequestHeader("Content-Type", "application/json");
    uwrq.SetRequestHeader("Authorization", "Bearer " + sToken);

    StartCoroutine(WaitForRequest(uwrq));
}

IEnumerator WaitForRequest(UnityWebRequest uwrq)
{
    //Make the request
    yield return uwrq.Send();
    if (String.IsNullOrEmpty(null))
    {
        Debug.Log(uwrq.downloadHandler.text);
    }
    else
    {
        Debug.Log("Error while rececing: " + uwrq.error);
    }
}

If UnityWebRequest did not work, use WWW. There have been reports of bugs with UnityWebRequest but I have not personally encountered one.

WWW:

For WWW, use the public WWW(string url, byte[] postData, Dictionary<string, string> headers); constructor overload which takes in the url, the data and the headers in one function call.

[Serializable]
public class UberJson
{
    public string fare_id;
    public string product_id;
    public double start_latitude;
    public double start_longitude;
    public double end_latitude;
    public double end_longitude;
}

void Start()
{
    postJson();
}

string createUberJson()
{
    UberJson uberJson = new UberJson();

    uberJson.fare_id = "abcd";
    uberJson.product_id = "a1111c8c-c720-46c3-8534-2fcdd730040d";
    uberJson.start_latitude = 37.761492f;
    uberJson.start_longitude = -122.42394f;
    uberJson.end_latitude = 37.775393f;
    uberJson.end_longitude = -122.417546f;

    //Convert to Json
    return JsonUtility.ToJson(uberJson);
}


void postJson()
{
    string URL = "https://sandbox-api.uber.com/v1.2/requests";

    //string json = "{ \"fare_id\": \"abcd\", \"product_id\": \"a1111c8c-c720-46c3-8534-2fcdd730040d\", \"start_latitude\": 37.761492, \"start_longitude\": -122.423941, \"end_latitude\": 37.775393, \"end_longitude\": -122.417546 }";

    string json = createUberJson();

    string sToken = "";

    //Set the Headers
    Dictionary<string, string> headers = new Dictionary<string, string>();
    headers.Add("Content-Type", "application/json");
    headers.Add("Authorization", "Bearer " + sToken);
    //headers.Add("Content-Length", json.Length.ToString());

    //Encode the JSON string into a bytes
    byte[] postData = System.Text.Encoding.UTF8.GetBytes(json);

    WWW www = new WWW(URL, postData, headers);
    StartCoroutine(WaitForRequest(www));
}

IEnumerator WaitForRequest(WWW www)
{
    yield return www;
    if (String.IsNullOrEmpty(null))
    {
        Debug.Log(www.text);
    }
    else
    {
        Debug.Log("Error while rececing: " + www.error);
    }
}
Luzan Baral
  • 3,678
  • 5
  • 37
  • 68
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Thanks so much @Programmer! Using www does indeed work! It appears that there is some problem with authenticating when using UnityWebRequest, which is a bit frustrating but at least it works! I really appreciate you taking the time to help me figure this out, it's the last piece of the puzzle! – Nahele Allan-Moon May 06 '17 at 17:50
  • Yeah, it is indeed a bug with `UnityWebRequest`. Good thing `WWW` is an option and the solution. Happy coding! – Programmer May 06 '17 at 18:01
0

If you specify the ContentType to be application/json, I suppose you should also send the content in actual Json. I have written down an example. This uses Newtonsoft Json, but you should be fine with any Json implementation. Also this is more or less pseudo code, you might have to do some final adjustments.

using Newtonsoft.Json;

private IEnumerator TestRequest()
{
    var jsonObject = new
    {
        fare_id = "abcd",
        product_id = "a1111c8c-c720-46c3-8534-2fcdd730040d",
        start_latitude = 37.761492f,
        start_longitude = -122.42394f,
        end_latitude = 37.775393f,
        end_longitude = -122.417546f,
    };

    MemoryStream binaryJson = new MemoryStream();
    using (StreamWriter writer = new StreamWriter(binaryJson))
        new JsonSerializer().Serialize(writer, jsonObject);

    using (UnityWebRequest uweb = UnityWebRequest.Post("https://sandbox-api.uber.com/v1.2/requests"))
    {
        uweb.SetRequestHeader("Authorization", "Bearer " + sToken);
        uweb.SetRequestHeader("Content-Type", "application/json");

        UploadHandlerRaw uploadHandler = new UploadHandlerRaw(binaryJson.ToArray());
        uweb.uploadHandler = uploadHandler;

        yield return uweb.Send();

        if(uweb.isError)
            Debug.Log(uweb.error);
        else
            Debug.Log(uweb.downloadHandler.text);
    }
}
Thomas Hilbert
  • 3,559
  • 2
  • 13
  • 33
  • Thanks for taking the time to look at this @Thomas Hilbert, I have tried this and still can't get it to work. I used a struct outside of the Coroutine to store the values, but when I called the JsonSerializer on the BinaryJson MemoryStream, it was 0 bytes. So instead used the following: string s = JsonUtility.ToJson(j); byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(s); Do you know if that should still work? Sorry for the noobness! – Nahele Allan-Moon May 06 '17 at 13:53
  • Sorry for my late response. I fixed the example, binaryJson is now correctly filled with data. `JsonUtility` will work too, however you can't use anonymous types with it, which is why I preferred Newtonsoft.Json in the example. – Thomas Hilbert May 08 '17 at 17:05