Making POST request to Vuforia's Web Services always results in "Fail", even though PUT request always works using same approach/body - rest

I am developing an Android app in Unity. I am trying to make UnityWebRequests to work with Vuforia's Web Services API. Currently every method works - GET/PUT/DELETE, but I cannot POST anything, I always get an error:
Error:Generic/unknown HTTP error
Response code:400
Even though according to Vuforia's documentation POST requires the same request body as PUT and I am generating it using the same approach:
public string CreateNewUpdateBody(Text name, Text width, RawImage image, Toggle active_flag, Text application_metadata)
{
dynamic BodyData = new System.Dynamic.ExpandoObject();
if (!string.IsNullOrEmpty(name.text))
{
BodyData.name = name.text; // mandatory for post
}
if (!string.IsNullOrEmpty(width.text))
{
BodyData.width = float.Parse(width.text); // mandatory for post
}
if (image.texture != null)
{
Texture2D texture = (Texture2D)image.texture;
BodyData.image = System.Convert.ToBase64String(ImageConversion.EncodeToJPG(texture)); // mandatory for post
}
if (active_flag.interactable)
{
BodyData.active_flag = active_flag.isOn;
}
if (!string.IsNullOrEmpty(application_metadata.text))
{
BodyData.application_metadata = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(application_metadata.text));
}
string json = JsonConvert.SerializeObject(BodyData);
Debug.Log("Body data: " + json);
return json;
}
Then I send the web request like this:
private IEnumerator PostTarget(MonoBehaviour mono, string postBody)
{
var request = UnityWebRequest.Post(url + "/targets", postBody);
SetHeaders(request); // Must be done after setting the body
Debug.Log("Starting request " + request.method + " " + request.url);
yield return request.SendWebRequest();
while (!request.isDone) yield return null;
if (request.isHttpError || request.isNetworkError)
{
Debug.LogError("Request was not completed");
Debug.LogError("Error:" + request.error + " Response code:" + request.responseCode);
Debug.LogError(request.downloadHandler.text); // result_code is always just "Fail"
mono.StopAllCoroutines();
yield break;
}
else
{
Debug.Log("Request completed successfuly!");
Debug.Log(request.downloadHandler.text);
}
response = JsonUtility.FromJson<ResponsePostNewTarget>(request.downloadHandler.text);
Debug.Log("\nCreated target with id: " + response.target_id);
}
Any thoughts or suggestions? I appreciate the time you take to read this.

If everything works BUT posting data, either 1 vuforia doesn't support it or 2 (most likely) you're missing something.
Try adding this to your request
private UploadHandler GetUploadHandler(string postBody)
{
UploadHandler handler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(postBody));
handler.contentType = "application/json";
return handler;
}
And call it after SetHeaders
request.uploadHandler = GetUploadHandler(postBody);

Related

A Better way to Improve the performance of a series of REST API calls

A REST client consumes a series of API calls, 6 to be exact. They take a notable time to complete those series of calls even though both applications are in the same machine. The code is something like the following:
// 1.
CreateUserOption createUserOption = new CreateUserOption(username, jobCandidatePassword, email, fullName);
Optional<User> userOptional = createUserAccount(createUserOption, tokenValue);
if (userOptional.isEmpty()) return false;
// 2.
GenerateRepoOption generateRepoOption = new GenerateRepoOption(templateName.replace("template", "") + username, templateOwner);
Optional<Repository> repositoryOptional = this.generateRepo(generateRepoOption, templateOwner, templateName, tokenValue);
if (repositoryOptional.isEmpty()) return false;
// 3.
TransferRepoOption transferRepoOption = new TransferRepoOption(username);
Optional<Repository> transferRepositoryOptional = transferRepo(
transferRepoOption,
repositoryOptional.get().getOwner().getLogin(),
repositoryOptional.get().getName(),
tokenValue
);
if (transferRepositoryOptional.isEmpty()) return false;
// 4.
List<Organization> organizations = this.getOrganizationsOfCurrentUser(tokenValue);
if (!organizations.isEmpty()) {
// 5.
Organization organization = organizations.get(0);
Optional<Team> teamOptional =
this.createTeamInOrganization(new CreateTeamOption("t-" + username), organization.getUsername(), tokenValue);
if (!teamOptional.isEmpty()) {
// 6.
this.addTeamMember(teamOptional.get().getId(), username, tokenValue);
}
}
return true;
and those functions are consuming a REST API. For example,
private Optional<User> createUserAccount(CreateUserOption account, String tokenValue) {
log.debug(":::: createUserAccount : {}", account.toString());
String postBody = createUserOptionJsonAdapter.toJson(account);
okhttp3.RequestBody body = okhttp3.RequestBody.create(postBody, okhttp3.MediaType.parse("application/json"));
Request request = new Request.Builder()
.url(apiBaseurl + "/admin/users")
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", MediaType.APPLICATION_JSON.toString())
.addHeader("Authorization", "token " + tokenValue)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error(response.code() + " - " + response.message());
return Optional.empty();
}
User user = giteaUserJsonAdapter.fromJson(response.body().string());
return Optional.of(user);
} catch (IOException ioe) {
log.error(ioe.getMessage());
return Optional.empty();
}
}
Those 6 calls can be divided into two groups and 3 calls in each group, the next call needs the returned data from the previous one. Firing another thread for one group of API calls is one way to improve the performance.
Any better approaches on the client?
The client app is built with Java and Moshi HTTP client library.

Submitting POST request to Facebook Messenger API

I'm struggling to connect to the Facebook Messenger API. The server keeps returning:
The remote server returned an error: (400) Bad Request.
I've been at this for a few days, tried multiple methods, even tried a few VS packages that don't quite work. I've checked my Auth Token several times, and I don't know what else it might be.
Is there something obvious that's causing a bad request? I've copied the root URL from Facebook's API page. The token in the code below has been removed. The application throws an exception when I attempt to read the response. (WebResponse FBresponse = FBrequest.GetResponse();)
private string FBSendMessage(string user, string message)
{
string result = null;
string FBroot = "https://graph.facebook.com/v2.6/me/messages?access_token=";
string token = "EAA...DZD";
string FBURI = FBroot + token;
string FBstring = "{ \"recipient\": { \"id\":\"" + user + "\" }, \"message\": { \"text\":\"" + message + "\" } }";
try
{
//using (WebClient FBclient = new WebClient())
//{
// result =
// FBclient.UploadString(FBURI, FBstring);
//}
HttpWebRequest FBrequest = (HttpWebRequest)WebRequest.Create(FBURI);
FBrequest.Credentials = CredentialCache.DefaultCredentials;
FBrequest.ProtocolVersion = HttpVersion.Version11;
FBrequest.Method = "POST";
FBrequest.ContentType = "application/json";
byte[] FBbytes = Encoding.UTF8.GetBytes(FBstring);
FBrequest.ContentLength = FBbytes.Length;
Stream FBstream = FBrequest.GetRequestStream();
FBstream.Write(FBbytes, 0, FBbytes.Length);
FBstream.Close();
WebResponse FBresponse = FBrequest.GetResponse();
Output((((HttpWebResponse)FBresponse).StatusDescription), Log.Error);
FBstream = FBresponse.GetResponseStream();
StreamReader FBreader = new StreamReader(FBstream);
result = FBreader.ReadToEnd();
FBreader.Close();
FBresponse.Close();
}
catch(Exception ex)
{
Output(ex.Message, Log.Error);
}
return result;
}
I have determined that my code isn't the issue. The issue is that I'm making a request with an invalid user id. Facebook creates a user ID in the application context that isn't the same as your default user id. I have to receive a message to learn that contextualized id before I can send a message.

Xamarin.Forms Consume Rest Service

I'm new to Xamarin and developing native apps in general (I have made html5 apps in the past).
I have started on a Xamarin.Forms project and I'm trying to contact a REST like API (need to GET an URL which will return a json array).
Normally from C# I would use RestSharp and perform this call using the RestClient.
I'm not having any luck installing that package from Xamarin Studio though, but I have got the Microsoft HTTP Libraries installed.
I'm pretty sure this is a very trivial task to perform, I just haven't been able to adapt the samples I have found online to work for me.
Anyone who could post how this is done please (remember I'm new to this so don't expect me to understand everything that is different from say a normal console app)?
It is easy with HTTP Client and JSON.NET here is a example of a GET:
public async Task<List<Appointment>> GetDayAppointments(DateTime day)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + App.apiToken);
//Your url.
string resourceUri = ApiBaseAddress;
HttpResponseMessage result = await client.GetAsync (resourceUri, CancellationToken.None);
if (result.IsSuccessStatusCode) {
try {
return GetDayAppointmentsList(result);
} catch (Exception ex) {
Console.WriteLine (ex.Message);
}
} else {
if(TokenExpired(result)){
App.SessionExpired = true;
App.ShowLogin();
}
return null;
}
return null;
}
private List<Appointment> GetDayAppointmentsList(HttpResponseMessage result){
string content = result.Content.ReadAsStringAsync ().Result;
JObject jresponse = JObject.Parse (content);
var jarray = jresponse ["citas"];
List<Appointment> AppoinmentsList = new List<Appointment> ();
foreach (var jObj in jarray) {
Appointment newApt = new Appointment ();
newApt.Guid = (int)jObj ["id"];
newApt.PatientId = (string)jObj ["paciente"];
newApt.Name = (string)jObj ["nombre"];
newApt.FatherLstName = (string)jObj ["paterno"];
newApt.MotherLstName = (string)jObj ["materno"];
string strStart = (string)jObj ["horaIni"];
TimeSpan start;
TimeSpan.TryParse (strStart, out start);
newApt.StartDate = start;
string strEnd = (string)jObj ["horaFin"];
TimeSpan end;
TimeSpan.TryParse (strEnd, out end);
newApt.EndDate = end;
AppoinmentsList.Add (newApt);
}
return AppoinmentsList;
}
I use System.Net.WebClient and our asp.net WebAPI interface:
public string GetData(Uri uri)
{//uri like "https://webapi.main.cz/api/root"
string ret = "ERROR";
try
{
using (WebClient webClient = new WebClient())
{
//You can set webClient.Headers there
webClient.Encoding = System.Text.Encoding.UTF8;
ret = webClient.DownloadString(uri));//Test some data received
//In ret you can have JSON string
}
}
catch (Exception ex) { ret = ex.Message; }
return ret;
}
4
public string SendData(Uri uri, byte[] data)
{//uri like https://webapi.main.cz/api/PostCheckLicence/
string ret = "ERROR";
try
{
using (WebClient webClient = new WebClient())
{
webClient.Headers[HttpRequestHeader.Accept] = "application/octet-stream";
webClient.Headers[HttpRequestHeader.ContentType] = "text/bytes";
webClient.Encoding = System.Text.Encoding.ASCII;
byte[] result = webClient.UploadData(uri, data);
ret = Encoding.ASCII.GetString(result);
if (ret.Contains("\"ResultWebApi\":\"OK"))
{//In ret you can have JSON string
}
else
{
}
}
}
catch (Exception ex) { ret = ex.Message; }
return ret;
}
x
I've some examples in my Github repo. Just grab the classes there and give them a try. The API is really easy to use:
await new Request<T>()
.SetHttpMethod(HttpMethod.[Post|Put|Get|Delete].Method) //Obligatory
.SetEndpoint("http://www.yourserver.com/profilepic/") //Obligatory
.SetJsonPayload(someJsonObject) //Optional if you're using Get or Delete, Obligatory if you're using Put or Post
.OnSuccess((serverResponse) => {
//Optional action triggered when you have a succesful 200 response from the server
//serverResponse is of type T
})
.OnNoInternetConnection(() =>
{
// Optional action triggered when you try to make a request without internet connetion
})
.OnRequestStarted(() =>
{
// Optional action triggered always as soon as we start making the request i.e. very useful when
// We want to start an UI related action such as showing a ProgressBar or a Spinner.
})
.OnRequestCompleted(() =>
{
// Optional action triggered always when a request finishes, no matter if it finished successufully or
// It failed. It's useful for when you need to finish some UI related action such as hiding a ProgressBar or
// a Spinner.
})
.OnError((exception) =>
{
// Optional action triggered always when something went wrong it can be caused by a server-side error, for
// example a internal server error or for something in the callbacks, for example a NullPointerException.
})
.OnHttpError((httpErrorStatus) =>
{
// Optional action triggered when something when sending a request, for example, the server returned a internal
// server error, a bad request error, an unauthorize error, etc. The httpErrorStatus variable is the error code.
})
.OnBadRequest(() =>
{
// Optional action triggered when the server returned a bad request error.
})
.OnUnauthorize(() =>
{
// Optional action triggered when the server returned an unauthorize error.
})
.OnInternalServerError(() =>
{
// Optional action triggered when the server returned an internal server error.
})
//AND THERE'S A LOT MORE OF CALLBACKS THAT YOU CAN HOOK OF, CHECK THE REQUEST CLASS TO MORE INFO.
.Start();
And there's a couple of examples.
For all my Xamarin Forms app I use Tiny.RestClient.
It's easy to get it and easy to use it.
You have to download this nuget.
And after it just very easy to use it :
var client = new TinyRestClient(new HttpClient(), "http://MyAPI.com/api");
var cities = client.
GetRequest("City").
AddQueryParameter("id", 2).
AddQueryParameter("country", "France").
ExecuteAsync<City>> ();
Hopes that helps.

Headers in POST in Grails 3 app are not being sent with rest of service

Using Grails 3.0.9, and grabbing the freshest REST API with this snippet in gradle.build:
compile 'org.grails:grails-datastore-rest-client:4.0.7.RELEASE', {
['commons-codec', 'grails-async', 'grails-core',
'grails-plugin-converters', 'grails-web', 'groovy'].each {
exclude module: it
}
}
I am trying to make the following POST request:
def rest = new RestBuilder(headers:["X-LSS-Env":"devmo"], connectTimeout:10000, readTimeout:20000)
response = rest.post("http://..../..") {
accept "application/json"
contentType "application/json"
json jsonBuilder
}
Now, the POST receiver gets the json okay, give back a response okay, but this is the problem: it receives the headers as an empty map or as null!
So, what is the correct way of passing header data to the POST receiver? This is needed because the environment key X-LSS-Env could have different values, which instructs the receiver to do further routing based on it. Same with the GET request of course.
* UPDATE *
The consumer of my POST requests is actually a Java application, running on Apache Tomcat/8.0.26. The is how the service looks on the other side:
private javax.servlet.http.HttpServletRequest hsr;
#POST
#Path("/na")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response postSomething(Ggfp ggfp ){
try {
Enumeration<String> hnames = hsr.getHeaderNames();
int i = 0;
while (hnames.hasMoreElements()) {
String headerName = hnames.nextElement();
System.out.println(++i+ " headerName: " + headerName);
String val = hsr.getHeader(headerName);
System.out.println(" val: " + val);
}
String hval = hsr.getHeader("X-LSS-Env");
return Response.status(Status.OK).entity("X-LSS-Env is " + hval).build();
} catch (Exception e) {
}
}
Calling this service from Postman works, headers are identified. Calling it from the Grails app results into an empty map - like I am sending no headers!
The RestBuilder constructor never liked the way I used (or abused) it. Here is a clean way of achieving what I set out to do, with tryCatch logic if a timeout transpires.
def makePostWsr(serviceUrl, jsonBuilder) {
try {
def rest = new RestBuilder(connectTimeout:connectTimeout, readTimeout:readTimeout)
def response = rest.post("$wsUrl/$serviceUrl") {
header 'X-LSS-Env', 'devmo'
accept "application/json"
contentType "application/json"
json jsonBuilder
}
response
} catch (Exception e) {
println "== problem makePostWsr on $serviceUrl"
null
}
}

REST Services - JSON deserialization error: Encountered unexpected character '<'

public async void MakeRequest(string requestUrl)
{
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(string.Format(
"Server error(HTTP {0}:{1}.",
response.StatusCode,
response.StatusDescription));
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
object objResponse = jsonSerializer.ReadObject(response.GetResponseStream());
root = (RootObject)objResponse;
if (root == null)
this.Frame.Navigate(typeof(MainPage));
}
}
catch (Exception ex)
{
ThrowException(ex);
}
}
Link : http://dev.virtualearth.net/REST/V1/Routes?wp.0=39.920829,32.853883&wp.1=39.877666,32.864728&key=BingMapsKey
Is there anything wrong in my in the codes above?
Just change this line for make the query with JSON and not XML format
So from this ...
string query = "http://dev.virtualearth.net/REST/v1/Locations/" +
queryString + "?output=xml" + " &key=" + BingMapsKey;
To this ...
string query = "http://dev.virtualearth.net/REST/v1/Locations/" +
queryString + "?output=json" + " &key=" + BingMapsKey;
i.e. just change output=xml to output=json
This code is working fine for me once I replace the undefined RootObject in your code with the BingMapsRESTService.Common.JSON.Response type found in the Bing Maps REST Service .NET Libraries that #rbrundritt suggested you use in your other post