How do I receive a <ArrayList> with Google Cloud Endpoints? - java

I have a API endpoint method like this:
#ApiMethod(name = "test")
public TestModel test(#Named("testArray") ArrayList<String> myTest) {
for (String i:myTest){
log.warning("i=="+i);
}
A request is made as such:
{
"testArray":[
"ID1",
"ID2"
]
}
However, when I check my log (and also the problems this caused in my app), I see
i=="ID1,ID2"
not how i expected to see:
i=="ID1"
i=="ID2"
as the output. It is putting both elements of the array into myTest(0).
How do I populate the Array correctly?

This issue doesn't appear to occur on the latest SDK 1.9.22.
I'm wondering how you're creating the request, and if it's possible that you're just joining the strings with commas as a single element in the array that you send. While I know it sounds crazy to do this deliberately and I don't think you're doing that, it's possible that some layer of abstraction below your code does it?
Another possibility is that you're not using the generated client library for your Endpoints API (you really should, it does a lot of work that you'd end up replicating on your own), and you're forming raw JSON to send over? In that case, I can see how maybe the request that ultimately gets sent might be different from what you expect, collapsing all the values inside the array that "testArray" is a key to into a comma-separated list.
So, my best advice is to examine how you form the request, and if possible, get access to the raw request itself inside your endpoints method to see what was sent.

The easiest way, since this seems like a bug, is to not use a named parameter. Create a new request class that has a list field and use that as an unnamed (aka resource) parameter, instead.

Related

REST API- use same URI & same method for different parameter to call different methods

I have a tricky situation where, I need to use same URI to call POST operation, one with single object & another with array of same type of objects. Issue is I cant change URIs.
e.g.
POST /my-services/v1/users with single user object as part of request body &
POST /my-services/v1/users with array of user objects as part of request body
I cant change URI for 2nd operation e.g. /my-services/v1/bulk-users
So, the question is, how to get such methods added in REST API?
In most JSON mappers (in example Jackson) you can set a property ACCEPT_SINGLE_VALUE_AS_ARRAY, Which will basically treat a single object as an array, so you can define your endpoints once (for collections).
Then you implement your endpoint as it always takes a Collection as an input, and it will be handled by mapper even if a client will send single JSON object.
I would say add another param.
For example,
POST ... type=single&req=(user object)... for the first one.
POST ... type=array&req=[user object]... for the second one.
The use switch case or if to check the type at the server.
Send the data and check the type at the server as Tim says.

Java's Jersey, RESTful API, and JSONP

This must have been answered previously, but my Google powers are off today and I have been struggling with this for a bit. We are migrating from an old PHP base to a Jersey-based JVM stack, which will ultimately provide a JSON-based RESTful API that can be consumed from many applications. Things have been really good so far and we love the easy POJO-to-JSON conversion. However, we are dealing with difficulties in Cross-Domain JSON requests. We essentially have all of our responses returning JSON (using #Produces("application/json") and the com.sun.jersey.api.json.POJOMappingFeature set to true) but for JSONP support we need to change our methods to return an instance of JSONWithPadding. This of course also requires us to add a #QueryParam("callback") parameter to each method, which will essentially duplicate our efforts, causing two methods to be needed to respond with the same data depending on whether or not there is a callback parameter in the request. Obviously, this is not what we want.
So we essentially have tried a couple different options. Being relatively new to Jersey, I am sure this problem has been solved. I read from a few places that I could write a request filter or I could extend the JSON Provider. My ideal solution is to have no impact on our data or logic layers and instead have some code that says "if there is a call back parameter, surround the JSON with the callback, otherwise just return the JSON". A solution was found here:
http://jersey.576304.n2.nabble.com/JsonP-without-using-JSONWithPadding-td7015082.html
However, that solution extends the Jackson JSON object, not the default JSON provider.
What are the best practices? If I am on the right track, what is class for the default JSON filter that I can extend? Is there any additional configuration needed? Am I completely off track?
If all your resource methods return JSONWithPadding object, then Jersey automatically figures out if it should return JSON (i.e. just the object wrapped by it) or the callback as well based on the requested media type - i.e. if the media type requested by the client is any of application/javascript, application/x-javascript, text/ecmascript, application/ecmascript or text/jscript, then Jersey returns the object wrapped by the callback. If the requested media type is application/json, Jersey returns the JSON object (i.e. does not wrap it with the callback). So, one way to make this work is to make your resource method produce all the above media types (including application/json), always return JSONWithPadding and let Jersey figure out what to do.
If this does not work for you, let us know why it does not cover your use case (at users at jersey.java.net). Anyway, in that case you can use ContainerRequest/ResponseFilters. In the request filter you can modify the request headers any way you want (e.g. adjust the accept header) to ensure it matches the right resource method. Then in the response filter you can wrap the response entity using the JSONWithPadding depending on whether the callback query param is available and adjust the content type header.
So what I ultimately ended up doing (before Martin's great response came in) was creating a Filter and a ResponseWrapper that intercepted the output. The basis for the code is at http://docs.oracle.com/cd/B31017_01/web.1013/b28959/filters.htm
Essentially, the filter checks to see if the callback parameter exists. If it does, it prepends the callback to the outputted JSON and appends the ) at the end. This works great for us in our testing, although it has not been hardened yet. While I would have loved for Jersey to be able to handle it automatically, I could not get it to work with jQuery correctly (probably something on my side, not a problem with Jersey). We have pre-existing jQuery calls and we are changing the URLs to look at the new Jersey Server and we really didn't want to go into each $.ajax call to change any headers or content types in the calls if we didn't have to.
Aside from the small issue, Jersey has been great to work with!

RESTful Spring service with multiple parameters

I'm constructing a restful service which needs to accept any number of parameters instead of the one from the sample below.
Assuming the following service routine
#RequestMapping("/start/id/{id}", RequestMethod.GET)
public void startService(#PathVariable String id) {...}
there's a client implementation based on RestTemplate
restTemplate.getForObject("/start/id/{id}", null, id);
Question: But given that it might be thousands of ids, what restful approaches do I have to sending all parameters in one request using RestTemplate? I've seen the suggestions
Add request body to GET request - Doesn't seem possible with RestTemplate?
Use a separator in id, (e.g., id1|id2|....|idn) - Seems like a hack
PUT the parameters first, then issue a GET to reference the ids - Double requests, seems non-intuitive
Adding multiple URL parameters (?id=foo&id=bar&.....&id=foobar)
I know similar questions (calling-a-restful-service-with-many-parameters, how-to-create-rest-urls-without-verbs, can-you-build-a-truly-restful-service-that-takes-many-parameters) has been asked before but I found it hard to spot a satisfactory answer, or at least an answer based on RestTemplate.
I don't think any part of RESTful design states that your url structure should be able to resolve entire collections. Your first (request parameter) and third (url parameter) suggestions are likely the best.
I would recommend the first. I'm sure its allowed in resttemplate. Looking at the documentation you provided, just implement one of the post methods. Each of them takes the request as a parameter. Inside there, I'm sure there is some kind of implementation of a getRequestParameters() method you can use to parse json/xml from the request body containing your ids.
Or, even better, how are all of these id's related? Do they all have a common parent resource? If so, then you could (and probably should) do something like...
/commonparent/{parentId}
And then inside your request handler, query for all of the ids, and procede like normal.
You could use a query parameter for all the ids:
/search?ids=1,2,3,4,5,6,7
Then tokenize by the comma and do your search. Remember that you will be capped by the maximum URL length if you issue this as a GET query string parameter.

Preferred method for REST-style URL's?

I am creating a web application that incorporates REST-style services and I wanted some clarification as to the preferred (standard) method of how the POST requests should be accepted by my Java server side:
Method 1:
http://localhost:8080/services/processser/uid/{uidvalue}/eid/{eidvalue}
Method 2:
http://localhost:8080/services/processuser
{uid:"",eid:""} - this would be sent as JSON in the post body
Both methods would use the "application/json" content-type, but are there advantages, disadvantages to each method. One disadvantage to method 2, I can immediately think of is that the JSON data, would need to be mapped to a Java Object, thus creating a Java object any time any user access the "processuser" servlet api. Your input is much appreciated.
In this particular instance, the data would be used to query the database, to return a json response back to the client.
I think we need to go back a little from your question. Your path segment starts with:
/services/processuser
This is a mistake. The URI should identify a resource, not an operation. This may not be always possible, but it's something you should strive for.
In this case, you seem to identify your user with a uid and an eid (whatever those are). You could build paths such as a user is referred to by /user/<uid>/<eid>, /user/<uid>-<eid> (if you must /user/uid/<uid>/eid/<eid>); if eid is a specialization, and not on equal footing with uid, then /user/<uid>;eid=<eid> would be more appropriate.
You would create new users by posting to /user/ or /user/<uid>/<eid> if you knew the identifiers in advance, deleting users by using DELETE on /user/<uid>/<eid> and change state by using PUT on /user/<uid>/<eid>.
So to answer your question, you should use PUT on /user/<uid>/<eid> if "processuser" aims to change the state of the user with data you provide. Otherwise, the mapping to the REST model is not so clean, possibly the best option would be to define a resource /user/process/<uid>/<eid> and POST there with all the data, but a POST to /user/process with all the data would be more or less the same, since we're already in RPC-like camp.
For POST requests, Method 2 is usually preferred, although often the resource name will be pluralized, so that you actually post to:
http://localhost:8080/services/processusers
This is for creating new records, however.
It looks like you're really using what most RESTful services would use a GET request for (retrieving a record), in which case, Method 1 is preferred.
Edit:
I realize I didn't source my answer, so consider the standards set by Rails. You may or may not agree that it is a valid standard.

How am I supposed to use Apache XML-RPC's TypeConvertorFactory on the server side?

I am struggling to get Apache XML-RPC to call my TypeConvertorFactory at all. It is calling it on the client side (only return values confirmed to work so far, haven't tested parameters) but the server side isn't calling it at all.
My initialisation code looks like this:
XmlRpcServlet servlet = new XmlRpcServlet();
XmlRpcServerConfigImpl config = new XmlRpcServerConfigImpl();
config.setEnabledForExtensions(true);
servlet.getXmlRpcServletServer().setConfig(config);
servlet.getXmlRpcServletServer().setTypeConverterFactory(
new ServerTypeConvertorFactory());
The API looks like this:
private interface API {
AvailableLicencesResponse availableLicences();
}
AvailableLicencesResponse is just an ordinary boring, albeit deeply nested JavaBean.
At the moment, the server sends this response as Base64 (this works because I called setEnabledForExtensions(true) - but if I don't call that, I get "unexpected end of stream" type errors instead, with no additional error anywhere to tell me why.)
I have set breakpoints inside ServerTypeConvertorFactory and it seems that none of the methods are being called on the server. The same breakpoints show the client calling convert() when the server hands back the result, but the result is already the correct type due to serialisation magic so I don't need to convert it.
Essentially, what I am trying to do is to implement a wire protocol which conforms to standard XML-RPC (and doesn't use huge amounts of Base64 data...) while still having an API which doesn't require a thousand casts and calls to Map.get(). I also want to avoid having to make more calls than necessary, which is why I'm returning a bean instead of having separate methods to get each property of it, which would have worked too.
(Also, if there is a simpler to use API than this one, I'm open for suggestions. It started out being really easy, but that's until you need to customise it. Also, anyone suggesting Axis or other SOAP-based APIs will be shot at dawn.)

Categories

Resources