Parsing JSON POST data sent from Unity to Ruby On Rails - ruby-on-rails

I'm building a Rails service for a Unity front end. One of the controllers is having an issue parsing the JSON blob from my UnityWebRequest. Here is what Unity says it is sending:
[StoryPost] Sending request to localhost:3000/stories/new with post data [words, {"_array":[{"_text":"mailing"}]}]
And here is what Rails is logging when it receives the JSON:
Started POST "/stories/new" for 127.0.0.1 at 2017-08-26 20:08:40 -0400
Error occurred while parsing request parameters.
Contents:
words=%7B%22_array%22%3A%5B%7B%22_text%22%3A%22mailing%22%7D%5D%7D
ActionDispatch::Http::Parameters::ParseError (743: unexpected token at 'words=%7B%22_array%22%3A%5B%7B%22_text%22%3A%22mailing%22%7D%5D%7D'):
actionpack (5.1.3) lib/action_dispatch/http/parameters.rb:113:in `rescue in parse_formatted_parameters'
actionpack (5.1.3) lib/action_dispatch/http/parameters.rb:107:in `parse_formatted_parameters'
It looks like I have some sort of encoding error. This started happening once I added the following code to my web request:
_request.SetRequestHeader("Content-Type", "application/json");
_request.SetRequestHeader("Accept", "application/json");
If I comment out the two SetRequestHeader calls mentioned above, then here is what Rails logs:
Started POST "/stories/new" for 127.0.0.1 at 2017-08-26 23:13:14 -0400
Processing by StoriesController#new as */*
Parameters: {"words"=>"{\"_array\":[{\"_text\":\"inspectors\"}]}"}
I added this code so that Rails would automatically know to parse my POST data as JSON. Anyone seen this type of issue before? New to Rails and HTTP, but not to Unity.
Relevant Code
For reference, here is my Rails Controller:
class StoriesController < ApplicationController
def new
post_data = params["words"]
words_array = post_data["_array"];
puts "words " + words_array
story = Story.new(words_array)
story.save()
end
end
And here is my Unity code. Note: _PostData is a Dictionary<string, string>.
protected ServiceCall()
{
switch (_Type)
{
case RequestType.Get:
_request = UnityWebRequest.Get(_URL);
break;
case RequestType.Post:
_request = UnityWebRequest.Post(_URL, _PostData);
break;
default:
throw new NullReferenceException("Unknown request type " + _Type);
}
_request.SetRequestHeader("Content-Type", "application/json");
_request.SetRequestHeader("Accept", "application/json");
_request.downloadHandler = new DownloadHandlerBuffer();
Diag.Crumb(this, $"Sending request to {_URL} with post data {_PostData.Pretty()}");
_requestOperation = _request.Send();
}
Here is how I am building _PostData
protected override Dictionary<string, string> _PostData
{
get
{
var asArray = new JsonArray<Word>(Luke.GuessWords);
string json = JsonUtility.ToJson(asArray);
return new Dictionary<string, string>{{"words", json}};
}
}
JSONArray is just a simple class that has an _array field, because Unity's JsonUtility cannot serialize top-level arrays.

In response to the feedback that my entire POST body was not formatted as JSON, I instead changed _PostData to return a string, and in my deriving classes serialized _PostData to JSON. Then in the base class, I encoded the JSON as bytes and sent it up as the POST body. Here is my changed code:
In Rails:
def new
words_array = params["_array"]
puts "words " + words_array.to_s
story = Story.new(words_array)
puts "story is " + story.to_s
end
In Unity:
protected override string _PostData
{
get
{
var asArray = new JsonArray<Word>(Luke.GuessWords);
string json = JsonUtility.ToJson(asArray);
return json;
}
}
And...
case RequestType.Post:
_request = UnityWebRequest.Post(_URL, new Dictionary<string, string>());
_request.uploadHandler = new UploadHandlerRaw
(
Encoding.UTF8.GetBytes(_PostData)
);
break;

Related

TypeError (no implicit conversion of nil into String) ruby on rails 5

So I have a controller that accepts a JSON as payload
def create
#tournoi = Tournoi.new(payload: JSON.parse(params[:payload]))
if #tournoi.save
redirect_to root_url
flash[:success] = "Your tournament bracket has been validated!"
the json is from a js diagram that's editable, I am saving the JSON with XMLHttpRquest and formData :
function save() {
var tojs = myDiagram.model.toJSON();
var json = JSON.stringify(tojs);
var formData = new FormData();
formData.append("payload", json);
var request = new XMLHttpRequest();
request.open("post", "http://localhost:3000/malesingle", true);
request.send(formData);
}
The JSON is successfully inserted into my controller, I get redirected to a TypeError landing page on my create method from my tournois controller, I know my payload is nill before I save it, I don't know why the way I declared #tournoi = Tournoi.new(payload: JSON.parse(params[:payload])) isn't guaranteeing the conversion from nill to payload..
you did a wrong way to submit payload json to rails backend. So params is not json, it's string of json
You can try to remove this
var json = JSON.stringify(tojs);
line from code, and add tojs to formdata directly
formData.append("payload", tojs);

Groovy httpbuilder post list params

I'm trying to consume a web service from my grails project. I'm using httpbuilder 0.7.2. Below is my http client.
static def webServiceRequest(String baseUrl, String path, def data,method=Method.GET,contentType=ContentType.JSON){
def ret = null
def http = new HTTPBuilder(baseUrl)
http.request(method, contentType) {
uri.path = path
requestContentType = ContentType.URLENC
if(method==Method.GET)
uri.query = data
else
body = data
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
response.success = { resp, json ->
println "response status: ${resp.statusLine}"
ret = json
println '--------------------'
}
}
return ret
}
The issue is coming when i'm trying to send something like this:
def input = [:]
input['indexArray'] = [1,5]
api call
def response = webServiceRequest(url,uri,input,Method.POST)
when i'm printing the value of post data in my server it shows only last value of list.
{"indexArray":"5"}
it should show both 1 and 5
If you want to send json data using contenttype application/x-www-form-urlencoded you have to explicitly convert the data before adding it to the body, you can use (data as JSON).
I am using RESTClient (nice convenience wrapper on HTTPBuilder, https://github.com/jgritman/httpbuilder/wiki/RESTClient). It is as simple as this with Spock.
RESTClient restClient = new RESTClient("http://localhost:8080")
restClient.contentType = ContentType.JSON
Also it automatically parses the JSON data, so my Spock test is:
when: "we check the server health"
HttpResponseDecorator response = restClient.get([path : "/health"]) as HttpResponseDecorator
then: "it should be up"
response != null
200 == response.status
'application/json' == response.contentType

Facing Exception of MessageBodyWriter while sending JSONObject to Rest web service

I am newbie to web service. Due to requirement I have to send a file[most probably in txt format] to server through REST web service.
I am getting the exception like below.
MessageBodyWriter not found for media type=application/json, type=class gvjava.org.json.JSONObject, genericType=class gvjava.org.json.JSONObject.
Here is my web service method.
#Path("{c}")
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String convert(#PathParam("c") JSONObject object) throws JSONException {
String result = "";
return "<ctofservice>" + "<ctofoutput>" + result + "</ctofoutput>" + "</ctofservice>";
}
Now client code is like below
JSONObject data_file = new JSONObject();
data_file.put("file_name", uploadFile.getName());
data_file.put("description", "Something about my file....");
data_file.put("file", uploadFile);
Client client = ClientBuilder.newClient();
webTarget = client.target(uploadURL).path("ctofservice").path("convert");
Response value = webTarget.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(data_file,MediaType.APPLICATION_JSON_TYPE),
Response.class);
Please help me with this.
Thanks in advance.
------------------------------------------------------------------------
As suggested by peeskillet in the answer below, I tried to send file through multipart. Still I am facing exception of no octet stream found.
Below is my rest api
#Path("{c}")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response convert(#FormDataParam("file") FormDataContentDisposition file) {
String result = "";
Some operation with attached parameter ...
return Response.status(200).entity(result).build();
}
Here is my test client
FormDataMultiPart multiPart = new FormDataMultiPart();
multiPart.setMediaType(MediaType.MULTIPART_FORM_DATA_TYPE);
FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("file",
uploadFile,MediaType.APPLICATION_OCTET_STREAM_TYPE);
multiPart.bodyPart(fileDataBodyPart);
Client client = Client.create();
WebResource webResource = client
.resource(uploadURL).path("ctofservice");
ClientResponse response = webResource.accept("application/json")
.post(ClientResponse.class,multiPart);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
And I am getting the exception below
I am not able to understand why I need to send data as MediaType.APPLICATION_OCTET_STREAM_TYPE ? As I have used multipart as media type before ...
I appreciate your help..
Without needing to configuring anything else, the easiest way to get around this is to just use a String instead of the actual JSONObject (i.e. just passing toString())
.post(Entity.json(data_file.toString()))
The problem with using JSONObject is that there is no provider that knows how to handle the conversion. You will have the same problem on the server side, where there is no provider to handle the conversion to JSONObject. So you will need to just do
#POST
public Response post(String json) {
JSONObject jsonObject = new JSONObject(json);
}
If you really want to be able to just use JSONObject without needing to use a String, then you should check out this post.
As an aside, this is not valid JSON (it's XML)
"<ctofservice>" + "<ctofoutput>" + result + "</ctofoutput>" + "</ctofservice>"
but you are saying that the endpoint returns JSON

How to pass JSON string to another api using RESTSharp?

Problem Specification:
Resource URI : address/index.php?r=api/employee
Request Header : Content- Type: application/json
HTTP Method: POST
Request Body: { "employeeName" : "ABC","age":"20","ContactNumber": "12341234"}
The above parameters should be passed to the system as a row HTTP POST in a JSON string.
I am trying to solve this problem using RESTSharp. But I am having some problem Like after executing the request my code return a Null response and I am not sure my JSON string is passing properly or not.
Here is my Code:
public ActionResult EmployeeInfo(Employee employee)
{
//string empName = unSubscription.employeeName.ToString();
var client = new RestClient("http://localhost:21779/");
var request = new RestRequest("api/employee ", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(new Employee
{
employeeName = "ABC",
age = "20",
ContactNumber = "12341234"
});
request.AddHeader("Content-Type", #"application/json");
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
return View();
}
Is there anything wrong with my code??
And I am little bit confused about
request.AddUrlSegment("username", "Admin") and request.AddParameter("name", "value").
Basically I want to know how to utilize AdduUrlSegment() and AddParameter().
Thanks in advance.
For using request.AddUrlSegment("username", "Admin") you should define your url template properly: var request = new RestRequest("api/employee/{username} ", Method.POST);
Also you should set Content-Type
request.AddHeader("Content-Type", #"application/json");
befor adding a Body

Unable to implement Grails-jaxrs multipart file upload integration Test

I am using grails-jaxrs for exposing an api which accepts multipart/form-data..
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(['application/json'])
#Path('/addMessage')
ChatMessage addChatMessageWithAttachment(#Context HttpServletRequest req) {
log.debug "> addChatMessageWithAttachment"
def fileStores = []
def chatMessage
GrailsWebRequest request = WebUtils.retrieveGrailsWebRequest()
def params = request.getParams()
if (!(params.messageBody.length() > 0)) {
log.error("Empty message body")
throw new LocalisedException(ErrorCode.CHAT_MESSAGE_CREATE_FAILED)
}
}
The implementation is working properly as expected. I am able to send form-data (with file and other parameters successfully.
Now I am trying to implement integration test for above logic.
I am using IntegrationTestCase to achieve this.. so my code snippet is as below:
class ChatMessageResourceV1Tests extends IntegrationTestCase{
//other implementation and setup ommited
#Test
void "Create new chat message for event id - customer user"() {
def headers = ['Content-Type': 'multipart/form-data', 'Accept': 'application/json']
def data = "My message..."
def cm = new ChatMessage(messageBody: data)
def content = "{'eventId':'$event.id','messageBody':'My message...'}"
sendRequest("/api/v1/chatMessage/addMessage", 'POST', headers, content.bytes)
assertEquals(200, response.status)
}
}
When I run the test.. I can see the call reaches inside the API method.. But however, the parameter messageBody is coming as null and exception is being thrown.
I have tried every possible combination of test.. But no luck.
Any help would be appreciated.

Resources