URL Mapping a Rest Webservice - rest

I have to map a REST Webservice URL like "http://server:8080/application/service/customer/v1"
to createCustomer method in CreateCustomerBean class..
I have done the following mappings..
*Web.xml*
<servlet-mapping>
<servlet-name>RestiveServlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
*Rest-Config.xml*
<jaxrs:server address="/customer/"
<jaxrs:serviceBean>
<ref bean="CreateCustomerBean"/>
</jaxrs:serviceBean>
</jaxrs:server>
Now the problem is the remaining path of the url("http://server:8080/application/service/customer/v1") is v1 rest all is mapped and i have to specify 2 #Path attributes one at the CreateCustomerBean class level and one at the createCustomer method in that bean.. so i have to append "create" before v1 .. and the url becomes
#Path (/create/)
CreateCustomerBean{
#Path(/v1)
createClient(String request){
}
}
http://server:8080/application/service/customer/create/v1/ which i dont want.. is there any way to avoid the #Path attribute at the class level and direct all the request to the createCustomer method.

In you code you can re-write code like this
#Path ("/v1")
CreateCustomerBean{
#Post
createClient(String request){ }
}
As long as you specify the POST attribute all the post request should be re-directed to the respective method.
Hope it helps.
Cheers

Related

How JAXB mapping is done in Spring boot SOAP webservices

I have a question on JAXB mapping using org.springframework.ws.server.endpoint.annotations.
I was able to generate Java domain object with provided *.xsd. The thing is after I define my endpoint with
#PayloadRoot, I have to wrap my request and response as below to successfully trigger the method and return a result:
#PayloadRoot( localPart = "PmtAuthAddRequest",
namespace = "http://*com/emb/webseries")
#ResponsePayload
public JAXBElement billPayment(#RequestPayload JAXBElement var1){
PmtAuthAddResponseType response=billPaymentHandler.execute(var1.getValue());
return of.createPmtAuthAddResponse(response); // Used ObjectFactory to create JAXBElement.
}`
`
From all the tutorial I see, they dont need to wrap it as JAXBElement to return the correct type, but the below code does not work for me:
`
`#PayloadRoot( localPart = "PmtAuthAddRequest",
namespace = "http://*com/emb/webseries")
#ResponsePayload
public PmtAuthAddResponseType billPayment(#RequestPayload PmtAuthAddRequestType> var1){
PmtAuthAddResponseType response=billPaymentHandler.execute(var1.getValue());
return response;
}`
`
Do you guys know why? How can I resolve this? Thanks
I tried without wrapping it as JAXBElement, but soap UI return with error message:
`no adapter for endpoint [public com.*.*.*.webseries.billpay.CustPayee50InqResponseType com.*.Endpoint.InquirePayeeEndpoint.inquirepayees(com.*.*.*.webseries.billpay.CustPayee50InqRequestType) throws javax.xml.bind.JAXBException]: Is your endpoint annotated with #Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?</faultstring>
`
Actually solved my own question....
The way to do it is to add #XmlRootElement under generated Java class from JAXB2 with below to correctly mapping:
#XmlRootElement(namespace = "http://..*/emb/webseries",name = "CustPayee50InqRequest")
The name should match with the localPart provided name from #PayloadRoot.
Added both for request and response makes it work for me

Adding Header in REST API breaks backward compatibility

I have a REST interface defined as below
public interface UserService {
#GZIP
#POST
Response createUser(#HeaderParam("hostName") String hostName, User user);
}
I want to read two more headers - addToCache and useCache . The obvious solution is to add the headers in the above signature.
While that would work for explicit HTTP calls over rest clients, modifying the interface signature breaks the backward compatibility in functional test codebase which already connect to the above service using REST proxy service.
The only way out I see is to pass the two params inside the User object. Is there another way out?
You can inject header params as fields in the implementation class:
public interface UserService {
Response createUser(String hostName, User user);
}
#Path("/userservice")
public class UserServiceRestImpl implements UserService{
#HeaderParam("addToCache")
private String addToCache;
#HeaderParam("useCache")
private String useCache;
#GZIP
#POST
Response createUser(#HeaderParam("hostName") String hostName, User user){
System.out.println(addToCache);
System.out.println(useCache);
}
}
UPDATED:
try to disable auto scan and specify the resource explicitly:
<!-- disabled auto scanning
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
-->
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>com.yourpackage.UserServiceRestImpl</param-value>
</context-param>
UPDATED2: Also you can try to inject #Context HttpHeaders instead of #HeaderParam:
private #Context HttpHeaders headers;
...
String addToCache = headers.getHeaderString("addToCache");

jaxrs/resteasy custom method paramater

I would like to have my JaxRs resource to take a custom method argument that is built from some parameter in the request.
Something to be used in conjunction with another object created from the body.
Something like:
#Resource
public class MyResource {
#Path("/resource")
public Object resource(MyResourceDTO body, AConfiguration conf){
}
}
For which the AConfiguration is created from some headers in the request.
How can I achive it?
I need something like th spring webargumentresovler: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/support/WebArgumentResolver.html
For my case MyResource is a subresource, the method should work also in this case...
If you add a DTO as parameter of your resource method your JAX-RS runtime will try to convert the body of the request into this type. You can additionally add any of the #xParam parameters like #QueryParam as parameters of your resource method. (The only exception is #FormParam as they are found in the body).
If you want to encapsulate multiple of your Params in one object you can use #BeanParam. Your Configuration class could look like this:
public class Configuration {
#QueryParam("foo")
private String foo;
#HeaderParam("bar")
private String bar;
// getters + setters
}
And can be used like this:
#POST
public Response someMethod(Dto dto, #BeanParam Configuration conf) {}
You can use something like below. Your conf object have be sent as json from the client. If the parameters in conf object have to change dynamically you have to follow the second approach.
#Resource
public class MyResource {
#POST
#Consumes("application/json")
#Path("/resource")
public Object resource(AConfiguration conf){
// This method can receive multiple objects here. Currently it receives
// conf object only as the payload of the post method.
}
}
To change the conf object dynamically, You can send json String.
public Object resource(String confJson){
// Collect parameters manually here.
}
In your pom.xml, you should include,
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.1.GA</version>
</dependency>
Edit:
You can set a json string as a header param (But, not the best practice.) Or you can set different headers at you will and access them using HttpHeaders. Here is an example.
public Object resource(#Context HttpHeaders confHeaders){
// Collect parameters manually.
String confJson = confHeaders.getRequestHeader("confJson").get(0);
// cast your `confJson` to `AConfiguration aConf` here.
// process query params and set them to aConf here.
}

How to add multiple Get Post and Delete methods in RESTful Service

I am new to REST Services and would like to know how we can add multiple Get / Post / Delete methods.
for e.g.
We are having following Get Methods: -
GetAllUsers()
GetUserByID(int id)
GetUserByName(string name)
Similarly, Delete methods: -
DeleteAllUsers()
DeleteUserByID(int id)
DeleteUserByName(string name)
Post/Put Methods: -
PutCreateDefaultUser()
PutCreateUser(User user)
PutCreateMultipleUsers(User[] users)
So how to define Get/Delete/Post/Put methods in above case. Is that name it self says which is get / delete /put / post
Also How to set the uri template for each?
What will be the URI of each method?
Note: I am using MVC4 .Net Web API project, I am NOT using WCF
Your examples point out to more of an RPC implementation. REST is based on resources. Each resource has its methods. to Get, Update, Insert and Delete. If you are planning to have what you said in your question, you can do it in your ASP.NET API with no problem: (But be sure that this is NOT REST)
Update (2018)
After some time and experience (and after a user comment on this old answer) I realized it was wrong to say that OP endpoints were not Restfull. The routes can be easily done to achieve that, as my examples already have shown. Funny how we learn and change our own ideas/opinions with time. :)
UserController
[RoutePrefix("api/v1")]
public class UserController : ApiController
{
[HttpGet]
[Route("users")]
public HttpResponseMessage GetAllUsers()
{
...
}
[HttpGet]
[Route("users/{id:int}")]
public HttpResponseMessage GetUserByID(int id)
{
...
}
[HttpGet]
[Route("users/{name:string}")]
public HttpResponseMessage GetUserByName(string name)
{
...
}
[HttpDelete]
public HttpResponseMessage DeleteAllUsers()
{
...
}
[HttpDelete]
[Route("users/{id:int}")]
public HttpResponseMessage DeleteUserByID(int id)
{
...
}
}
With the HttpAttributes, you can have as many HttpDeletes you want. Just put the attribute on top of the action and you're good to go. It also enforces that the methods can only be called using that HTTP verb. So in the Delete above, if you do a call with a GET verb, you'll get nothing. (The action will not be found)
You can also explicitly give a custom route to your action if you so desire. For instance, your call to GetUserByID would be:
GET: http://localhost:2020/api/v1/users/1
Most of the information you require can be found here:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection
You can specify the HTTP method with an attribute: AcceptVerbs, HttpDelete, HttpGet, HttpHead, HttpOptions, HttpPatch, HttpPost, HttpPut.
Otherwise, if the name of the controller method starts with "Get", "Post", "Put", "Delete", "Head", "Options", or "Patch", then by convention the action supports that HTTP method.
If none of the above, the method supports POST.
The Uri will depend on the name of the controller:
/api/controller-name/GetAllUsers

How to fix my url in spring framework

I am working with Spring MVC3.2 and I have a registration form(http://my-server.com:8080/tracks/apks). Users post it to the server and the server will return error message when validation fails. But I got the error message from the server, the URL was different from what I wanted. Here is my code:
Web.xml
<servlet-mapping>
<servlet-name>tracks</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
applicationContext.xml
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
#Controller
#RequestMapping("/apks")
public class ApkController {
#RequestMapping()
public ModelAndView index() {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("menus", AdminService.getMenus("apks"));
return new ModelAndView("apks", "model", modelMap);
}
#RequestMapping(value = "/insert", method = RequestMethod.POST)
public ModelAndView uploadApk(ApkInfo apkInfo, BindingResult bindingResult) {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("menus", AdminService.getMenus("apks"));
if (!fileExists(apk.getFileName())){
modelMap.put("message", message);
}
//Do something
return new ModelAndView("apks", "model", modelMap);
}
After calling uploadApk, I expected http://my-server.com:8080/tracks/apks but The returned URL was http://my-server.com:8080/tracks/apks/insert.
What do I do to fix it?
Thanks in advance.
Couple of observation.
In your web.xml, do you specify context-paran, the servlet tracks and the listener?
Is context:component-scan enabled in your spring configuration file?
Use requestMapping at method level to map request to specific method.
What does 'The returned URL' mean?
You should access 'http://my-server.com:8080/apks/insert' to call 'uploadApk' method
cause you have
#RequestMapping("/apks")
on your controller and
#RequestMapping(value = "/insert", method = RequestMethod.POST)
on your 'uploadApk' method.
How did you call the 'uploadApk' method?
I think that you should explain about it more to get an appropriate answer.
Since the url-pattern of servlet-mapping in your web.xml is '/',
you should remove '/tracks' in your url.
'tracks' is just a servlet name and not a servlet path.
So if you access to /tracks/apks/insert then you will got an 404 error.
Access to /apks/insert instead.
I guess that you may want a redirection after calling 'uploadApk' method
cause you attached 'redirect' tag on your question and used the word 'returned URL'. (Right?)
If my guess is right and you want to redirect the browser, then see SpringMVC 3.2 Redirect View docs.
Use below codes to redirect.
return new RedirectView("url-you-want");
or
return "redirect:url-you-want"