Cloud Endpoints not accepting JSON array - google-app-engine

I want to build my endpoint, which accept JSON array of below format:
[
{
"test":"Math",
"result":"Pass"
},
{
"test":"Science",
"result":"FirstClass"
}
]
It will be a POST call with the above JSON to my endpoint.
I tried it with servlet too but did not get the required result, and also tried to with list and inserting in a new class and posting to that class. Thanks in advance.

Is that an accurate representation of the JSON object which is being sent over? Because one does not simply send a a POST request with a JSON object of their param object to a cloud endpoint. See here for a thorough guide to Endpoint API interaction from a javascript perspective - notice how the client library exposes an object "gapi" through which calls are made. If you're sending this JSON from an iOS or Android app, there are similar client libraries which can be generated for you by a cloud endpoints build tool.

After much frustration, I resorted to reading the docs more carefully. In that quest, I found an important note in the doc:
https://cloud.google.com/endpoints/docs/frameworks/java/parameter-and-return-types
"Any type except a parameter or injected type is considered an entity type. ... Entity types cannot be annotated with #Named"
With all examples showing named parameters, I was stumped as the docs don't explain further, but then found a solution. It ends up that if you do not have named parameters, everything is just passed in as a LinkedHashMap. Usually, you can do any work you need to with just that data structure, but if you HAVE to have it in JSON, you can convert it. Here are some examples:
#ApiMethod(name = "endpointIterfaceName.createItems", httpMethod = "post", path = "test/items")
public WhateverReturnType createItems(LinkedHashMap<String, Object> itemsMap) {
// Do Stuff with map values
return whateverReturnValue;
}
With this, you need to be sure that you post your data with the Content-Type of json (i.e. Content-Type:application/json; charset=UTF-8). So, for example, when testing, with a jquery ajax call you would need to set dataType to "json" or with Postman, you would select "Raw" then JSON (application/json).
If you really want to convert this to a JSON object in Java because for whatever reason you can not use a hash map, you can do the following in your method:
// Use gson library to convert the map to a string
Gson gson = new Gson();
String mapAsJsonString = gson.toJson(itemsMap);
// create a JSON object from the new string representation
JSONObject obj = new JSONObject(mapAsJsonString);
As a side note, if this is passed as Content-Type:text then the whole body will be in the map as the first key of the map. You could do some inadvisable things here and just get that key and avoid converting the map to a string and then to a json object, but, like I said, that is inadvisable. :)

Related

Adding simple array to JSON payload in Bot Framework Composer

I have a simple problem where I am not able to insert an array in json payload to call graph api to update user profile while using Bot Framework Composer.
Example:
Step1. I created a property Conversation.UpdatedSkills which holds following value
["SharePoint","Dotnet","Analytics"]
Now I want to build JSON object for MS Graph service and working sample payload looks like this.
{
"skills":["SharePoint","Dotnet","Analytics"]
}
Step2. Now to build this JSON dynamically, I need pass body as JSON Object in Send an HTTP Request activity and I have folllowing code to generate payload.
{
"skills":"${conversation.UpdatedSkills}"
}
The output from Step2 looks something like this.
{
“skills”: “[\r\n “SharePoint”,\r\n “Dotnet”,\r\n “Analytics”\r\n]”
}
DESIRED JSON WAS THIS:
{
"skills":["SharePoint","Dotnet","Analytics"]
}
My question is, How do I pass my array from step 1 such a way so that it creates json object that works in service. The object created using step 2 is not the right object that service takes.
Any idea?
I tried different string manipulations but I think this is basic and there has to be something.
Don't use the string interpolation ${ }, but use an expression (=). For your example above, it should be:
{
"skills": "=conversation.UpdatedSkills"
}

CodenameOne - using terse REST api for nestoria-based demo doesn't compile

I like the look of the terse REST api as highlighted in the 8th Feb CodenameOne blog (https://www.codenameone.com/blog/new-rest-calls.html) but I am unsure how to add arguments like you do with ConnectionRequest addArgument("key","value"). Using the nestoria JSON example as a start (https://www.codenameone.com/javadoc/com/codename1/io/JSONParser.html) I have changed it to this:
JSONObject json = new JSONObject();
json.put("encoding", "json");
json.put("listing_type", "buy");
json.put("page","1");
json.put("country", "uk");
json.put("place_name", "birmingham");
Map<String, Object> jsonData = Rest.get("http://api.nestoria.co.uk/api").
contentType("application/json").
body(json).
acceptJson().
getAsJsonMap();
However, at the line:
body(json).
I get the error "body(java.lang.String) in 'com.codename1.io.rest.RequestBuilder' cannot be applied to (ca.weblite.codename1.json.JSONObject)". What is the correct way of adding arguments?
The body method accepts a String so this will compile body(json.toString()).
However, that specific call isn't a POST call so a body with JSON doesn't make sense for that API. That specific call accepts regular get arguments so what you probably wanted to do is this:
Map<String, Object> jsonData = Rest.get("https://api.nestoria.co.uk/api").
jsonContent().
queryParam("encoding", "json").
queryParam("listing_type", "buy").
queryParam("page","1").
queryParam("country", "uk").
queryParam("place_name", "birmingham").
getAsJsonMap();
Also notice I removed the contentType entry and acceptJson as both can be expressed via jsonContent. Also fixed URL to https which should be the default...

How to pass a list value to a webapp2 backend via $.post?

In my coffeescript frontend I attempt to pass a list of value to the backend
data = {
id: [2, 3, 4]
}
$.post url, data
In the handler in a Google app engine (python) backend, I read the value like so:
id_value = self.request.get('id')
LOG.info("%s", id_value)
It always print out '2' only.
How can I get the backend to obtain the list [2,3,4]?
$.post by default sends data in url-encoded format, which handles nested structures in its own way.
You might need to encode the data in JSON before sending and then decode it on the server side - an example is here.
The request object provides a get() method that returns values for arguments parsed from the query and from POST data.
If the argument appears more than once in a request, by default get()
returns the first occurrence. To get all occurrences of an argument
that might appear more than once as a list (possibly empty), give
get() the argument allow_multiple=True.
Hence you should use something like the below snippet. You can find more details here.
id_value = self.request.get('id', allow_multiple=True)
If you need to access variables url encoded in the body of a request (generally a POST form submitted using the application/x-www-form-urlencoded media type), you should use something like this.
id_value = self.request.POST.getall('id')

Parsing Swagger JSON data and storing it in .net class

I want to parse Swagger data from the JSON I get from {service}/swagger/docs/v1 into dynamically generated .NET class.
The problem I am facing is that different APIs can have different number of parameters and operations. How do I dynamically parse Swagger JSON data for different services?
My end result should be list of all APIs and it's operations in a variable on which I can perform search easily.
Did you ever find an answer for this? Today I wanted to do the same thing, so I used the AutoRest open source project from MSFT, https://github.com/Azure/autorest. While it looks like it's designed for generating client code (code to consume the API documented by your swagger document), at some point on the way producing this code it had to of done exactly what you asked in your question - parse the Swagger file and understand the operations, inputs and outputs the API supports.
In fact we can get at this information - AutoRest publically exposes this information.
So use nuget to install AutoRest. Then add a reference to AutoRest.core and AutoRest.Model.Swagger. So far I've just simply gone for:
using Microsoft.Rest.Generator;
using Microsoft.Rest.Generator.Utilities;
using System.IO;
...
var settings = new Settings();
settings.Modeler = "Swagger";
var mfs = new MemoryFileSystem();
mfs.WriteFile("AutoRest.json", File.ReadAllText("AutoRest.json"));
mfs.WriteFile("Swagger.json", File.ReadAllText("Swagger.json"));
settings.FileSystem = mfs;
var b = System.IO.File.Exists("AutoRest.json");
settings.Input = "Swagger.json";
Modeler modeler = Microsoft.Rest.Generator.Extensibility.ExtensionsLoader.GetModeler(settings);
Microsoft.Rest.Generator.ClientModel.ServiceClient serviceClient;
try
{
serviceClient = modeler.Build();
}
catch (Exception exception)
{
throw new Exception(String.Format("Something nasty hit the fan: {0}", exception.Message));
}
The swagger document you want to parse is called Swagger.json and is in your bin directory. The AutoRest.json file you can grab from their GitHub (https://github.com/Azure/autorest/tree/master/AutoRest/AutoRest.Core.Tests/Resource). I'm not 100% sure how it's used, but it seems it's needed to inform the tool about what is supports. Both JSON files need to be in your bin.
The serviceClient object is what you want. It will contain information about the methods, model types, method groups
Let me know if this works. You can try it with their resource files. I used their ExtensionLoaderTests for reference when I was playing around(https://github.com/Azure/autorest/blob/master/AutoRest/AutoRest.Core.Tests/ExtensionsLoaderTests.cs).
(Also thank you to the Denis, an author of AutoRest)
If still a question you can use Swagger Parser library:
https://github.com/swagger-api/swagger-parser
as simple as:
// parse a swagger description from the petstore and get the result
SwaggerParseResult result = new OpenAPIParser().readLocation("https://petstore3.swagger.io/api/v3/openapi.json", null, null);

ServiceStack with AngularJS: JSON Vulnerability Protection and XSRF

The AngularJS documentation provides some recommendation to protect a web side against JSON Vulnerability and XSRF Attacks (https://docs.angularjs.org/api/ng/service/$http section "Security Considerations").
How can I configure the JSON serialize to prefix my JSON?
What is the best way to get a verifiable value for the "X-XSRF-TOKEN" token value and how to validate that for each request?
You can add a GlobalResponseFilter to prefix your JSON with:
this.GlobalResponseFilters.Add((req, res, dto) =>
{
if (req.ResponseContentType.MatchesContentType(MimeTypes.Json)
&& !(dto is IHttpResult))
{
res.Write(")]}',\n");
}
});
Which will write the recommended prefix before the serialized JSON response.
This will protect against JS Array vulnerability, an alternative approach would be to wrap array responses in a DTO, e.g:
return new Response { Results = Db.Select<Poco>() };
Which would serialize as a JSON object avoids the JS Array vulnerability.
I prefer returning object responses since it doesn't limit your JSON services to only work with appropriately configured JS Apps and object responses are more forward-compatible/future-proofed as you can later modify the service to return multiple return types without breaking compatibility with existing clients.
Any random string should make a good token, e.g. hex-encoded random bytes or just a new Guid.

Resources