Equivalent annotations to Jersey #Context, #FormParm and #BeanParam in Spring - web-services

Consider the following Spring MVC annotation:
#RequestMapping(value="content",
method=RequestMethod.GET,
produces = "application/json; charset=UTF-8")
The equivalent in JAX-RS/Jersey is:
#GET
#Path("content")
#Produces(MediaType.APPLICATION_JSON)
I am looking for the equivalent Spring MVC annotation for the following JAX-RS/Jersey annotations:
#Context
#FormParm
#BeanParam

#FormParam
In JAX-RS, #FormParam binds the value(s) of a form parameter contained within a request entity body to a resource method parameter.
There's no direct equivalent to #FormParam in Spring MVC. The closest you will find is #RequestParam:
#RequestParam("foo") String foo
And you also can get the parameter from the request:
String foo = request.getParameter("foo");
#BeanParam
In JAX-RS, #BeanParam can be used to inject custom JAX-RS parameter aggregator value object into a resource class field, property or resource method parameter.
I'm not aware of any annotation that gives you a similar feature but according to this answer, you can create a class with field names that match your request parameters and add it as a method argument in your request handler method.
#Context
In JAX-RS, #Context is used to inject JAX-RS contextual information into a class field, bean property or method parameter. So you won't find a direct equivalent to #Context in Spring MVC either.
However Spring MVC has a predefined set of types that can automagically injected in method arguments.
And you also can use #Autowired to inject some request/response contextual information in your class fields:
#Autowired
HttpServletRequest request;

Related

How do I map path parameters from an API Gateway API to the Request Object of a Java Lambda

I have a lambda, written in Java, that accepts a Request Object of the structure
{
"id": "be1c320a-144f-464d-b32c-38ec7fb4445b",
"userId": "foobar"
}
When I call this Lambda through the test interface with such an object, it works fine.
I want to create an API where a GET request to
/users/foobar/items/be1c320a-144f-464d-b32c-38ec7fb4445b
i.e. of the form
/users/{userId}/items/{id}
calls this Lambda.
I have created the API resources /users, {userId}, items, and {id} appropriately.
And I have created the GET method (on /users/{userId}/items/{id})and associated it to the lambda.
When I test the API, it invokes the lambda, but with null values in the request. I can see it package the path as {"id":"be1c320a-144f-464d-b32c-38ec7fb4445b","userId": "foobar"} in the logs, but that's not being sent in the body.
I have tried creating a template map (and have tried RTFM), but cannot see how to map path parameters to a body.
How do I achieve this mapping?
I think your Request Object structure may not be properly configured. There may be a few ways to configure this. Here is some information that has helped me.
How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway - Demonstrates this mapping (albeit with python). However, taking the top response, if you enable "Use Lambda Proxy integration", you can similarily do this with Java as so:
#Override
public Object handleRequest(APIGatewayProxyRequestEvent input, Context context) {
Map<String, String> pathParameters = input.getPathParameters();
String id = pathParameters.get("id");
String userId = pathParameters.get("userId");
// Handle rest of request..
}
This is a tuturial using the serverless framework to create an Api with Java. This tutorial similarily accesses the pathParameters by parsing the input rather than using the APIGatewayProxyRequestEvent java class.
#Override
public Object handleRequest(Map<String, Object> input, Context context) {
try {
// get the 'pathParameters' from input
Map<String,String> pathParameters = (Map<String,String>)input.get("pathParameters");
String id = pathParameters.get("id");
String userId = pathParameters.get("userId");
} catch (Exception ex) {
logger.error("Error in retrieving product: " + ex);
}
}
Use a mapping template.
First, in the Method Request section, you should see userId and id as Request Paths
Then, in the Integration Request, do not choose Proxy Integration.
Then in the Mapping Templates section, add a new mapping template for application/json of the form
{
"id" : "$method.request.path.id",
"userId" : "$method.request.path.user_id"
}

RESTFUL Web Service - List

I have a client application requesting a list of channels from a webservice. Is it possible to take the "response" from the web service and store it in an ArrayList?
Meaning if I wanted to store a list of channels for example, it would normally come from the web service as a response, typically from ResponseBuilder.
And I want to store it in an ArrayList from the client, like List.
How would I go about doing that?
You can use TypeReference to instantiate your Channel object list, here is an example:
import com.fasterxml.jackson.core.type.TypeReference;
public class ChannelClient {
public void getChannels() {
Response serviceResponse = client.target("http://your_service_url/channels/").
request(MediaType.APPLICATION_JSON).get(Response.class);
String responseString = serviceResponse.readEntity(String.class);
List<Channel> list = new ObjectMapper().readerFor(new TypeReference<List<Channel>>() {
}).readValue(responseString);
}
}
Make sure to have Jersey JSON Jackson jar in your dependencies, you can get it from here
https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson/2.26-b07
EDIT: In case you want to consume MediaType.TEXT_PLAIN response, you will just change the request method argument to your specified type like this:
Response serviceResponse = client.target("http://your_service_url/channels/").
request(MediaType.TEXT_PLAIN).get(Response.class);

How to filter an REST Result by sending custom request header parameter

i have an ASP.NET Core 1.1 WebApi Endpoint like this one:
[ApiVersion("1.0")]
[Route("api/[controller]")]
public class SampleController : Controller
{
[HttpGet]
public IActionResult Get()
{
...
}
}
It returns a collection of 'Sample'-Objects to the caller.
Now i do like to send within the Request Header a Custom Attribute like 'App-Type' which let the Endpoint know which App asks for Data. But what is to do that the endpoint fetches this Attribute so that i have it as variable within the function?
If you want a parameter in a controller action that reads from the headers, you should use [FromHeader] attribute, in your case it will be like [FromHeader(Name="Accept-Language")]. More information in https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

How can I get this working with a GET or should it be a POST with REST Service in Spring

I am working on some web servers and I have to sent some data to the web service and get back a status code.. I am thinking maybe this should be a POST and not a GET but I would like to hear from all the pros out on the internet.
Here is my client code using Spring RESTTemplate
vars.put("lastName", "JOHN");
vars.put("firstName", "SMITH");
vars.put("middleInitial", "");
vars.put("socialSecurityNumber", "111-11-1111");
vars.put("Type","A");
vars.put("FileNumber","");
vars.put("EISNumber","");
String jsonreturn = restTemplate.getForObject("http://" + mRESTServer.getHost() + ":8080/services/api/checkstatus", String.class, vars);
Now here is my service side code (Spring MVC RESTful service). I would think all the fields I entered in the client would be in the ModelMap object but its not
#RequestMapping(value = "/checkstatus", method = RequestMethod.get)
#ResponseBody
public ResponseEntity<String> getCheckEnrollStatus(ModelMap model) throws ResourceNotFoundException
{
logger.debug("Looking for Status: " + model.toString());
}
So I have two questions:
1) Should I change the GET to a POST due to senting alot of data to the server?
2) If I leave it as a get why is my ModelMap emply?
Please help me out
For your ModelMap to be populated you probably need to annotate it with #RequestBody.
As the comment has pointed out you can't have a request body with a GET as per the specification. So you would either need to make the parameters part of the URL and use get or convert to POST.
Though POST seems to not fit with the purpose of your call.
Normally I'd say this should be a GET, but I noticed you have socialSecurityNumber as one of your parameters. You definitely do NOT want that to be part of your URL. Check out RFC 2616 section 15.1.3
Authors of services which use the HTTP protocol SHOULD NOT use GET based forms for the submission of sensitive data, because this will cause this data to be encoded in the Request-URI. Many existing servers, proxies, and user agents will log the request URI in some place where it might be visible to third parties. Servers can use POST-based form submission instead
Do a POST.
get as it is not changing anything onserver just returning data here is the spec.
Use request parameters like this
#RequestMapping(value = "/checkstatus", method = RequestMethod.get)
#ResponseBody
public ResponseEntity<String> getCheckEnrollStatus(#RequestParam final Long id)
or uri parameters, like
#RequestMapping(value = "/checkstatus/{id}", method = RequestMethod.get)
#ResponseBody
public ResponseEntity<String> getCheckEnrollStatus(#PathVariable final Long id) throws ResourceNotFoundException
{

How to unmarshall to different #RequestBody object types?

I'm using Spring in my web service which receives XML as input. It can be XML embebed in the HTTP request or as a plain text in the request attribute.
Currently my web service is handling two different XML schemas so my unmarshaller can unmarshall the XML files to two object types (for example: Foo and Bar).
In my Controller, I have the next code to handler the request attribute:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=application/x-www-form-urlencoded"})
#ResponseBody
public ResponseObject getResponse(#RequestParam("request") String request, HttpServletRequest req) {
It works perfectly, with the request string I can unmarshall to Foo object or Bar object.
The problem comes with the XML embebed:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=text/xml"})
#ResponseBody
public ResponseObject getResponse(#RequestBody Foo request, HttpServletRequest req) {
and
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=text/xml"})
#ResponseBody
public ResponseObject getResponse(#RequestBody Bar request, HttpServletRequest req) {
and here is the MessageConverter:
<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxb2Marshaller" />
<property name="unmarshaller" ref="jaxb2Marshaller" />
</bean>
<oxm:jaxb2-marshaller id="jaxb2Marshaller" contextPath="path.to.Foo:path.to.Bar"/>
I think that the MessageConverter should do the unmarshall automagically but I receive the next error:
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/ws/mypath.ws': [...] If you intend to handle the same path in multiple methods, then factor them out into a dedicated handler class with that path mapped at the type level!
How can I unmarshall automatically to different #RequestBody object types? (with the same web service path)
There has to be something in the #RequestMapping which makes each request method unique, in your case both the xml based request mappings exactly the same - the type of the parameters is figured out after the framework has found the correct method with the #RequestMapping. So essentially what you are saying is not feasible unless you have something more in the annotation to help the framework with finding the correct method.
One small simplification that you can make is the following, if you are on Spring 3.1+:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, consumes=text/xml)