Url as path parameter in restful api causes bad request - rest

We are developing a restful api using jersey (1.9.1) and tomcat 5.5.
A given resource is identified with a urn and we would like to address a specific instance of that resource. In order to achieve this, we used the following code:
#Path("/XXXs")
public interface XXXResource {
#GET
#Path("{id}")
#Produces({ MediaType.APPLICATION_JSON })
XXXInfo getXXX(#PathParam("id") String id);
}
The idea is to address this resource using the following url:
http://localhost:8080/restapi/XXXs/http%3A%2F%2Fns.something.com%2FXXX%2F2
The decoded path param value should be:
http://ns.something.com/XXX/2
However, when I make the request using the encoded url I get a bad request message from tomcat. So my questions are:
Is it correct to use a Urn as a path parameter?
Why is tomcat considering this request as a bad request?
Just in case, I changed the signature of the method so that the parameter is taken from the query string and it worked fine, but I want the parameter to be part of the path.
Thanks.

Ok, I solved it by adding the following line in catalina.properties:
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

Related

Spring WS remove flexible URL, Restricting WSDL URL and service URL

I'm trying to make a Spring Boot Soap WebService application, and was following the Get Started (https://spring.io/guides/gs/producing-web-service/) example to learn how to do this.
I've created what I want, but I have two URL problems with this setup and I could not find what configuration should I change to fix this :
WSDL URL basic is localhost:8080/ws/countries.wsdl but anything like localhost:8080/ws/whatever/countries.wsdl is correct
service URL for SoapUI request is localhost:8080/ws but anything like localhost:8080/ws/whatever is correct
I know that this is a feature for Spring WS, but I want a fixed URL (without 'whatever' in both cases) and could not find what to change for this
There is no straight forward way to restrict the way you want.
SOAP service is not URL based.
SOAP message body describe the endpoint.
The thing you wanted is possible following way.
Changing URL mapping in ServletRegistrationBean to restrict URL access
Existing /ws/* mapping is the reason why all the /ws/whatever url successfully responded.
Change as new ServletRegistrationBean(servlet, "/ws");
Effect will be you can not request other than /ws URL
Now the problem is, you can not get WSDL by this mapping.
Solution to get WSDL
The DefaultWsdl11Definition is actually generating WSDL from XSD on every request.
Save countries.wsdl to resource folder as static WSDL file.
Remove DefaultWsdl11Definition bean.
Create a new SimpleWsdl11Definition bean as like
#Bean(name = "countries")
public SimpleWsdl11Definition orders() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("countries.wsdl"));
return wsdl11Definition;
}
Now add another static URL mapping in ServletRegistrationBean. As it will be finally look like new ServletRegistrationBean(servlet, "/ws", "/ws/countries.wsdl");
This practice is good for development phase as you can publish easily the changed definition. But it is recommended to use static-wsdl for production environment. Details ** here
Just change
return new ServletRegistrationBean(servlet, "/ws/*");
for example to
return new ServletRegistrationBean(servlet, new String[]{
"/ws/v1/countries.wsdl",
"/ws/v2/countries.wsdl"
});

Invalid_request_parameter (create and sending envelopes)

I'm trying to use a service of DocuSign API in an abap project. I want to send a document to a specific email so it can be signed. But im getting the following error:
"errorCode": "INVALID_REQUEST_PARAMETER",## "message": "The request contained at least one invalid parameter. Query parameter 'from_date' must be set to a valid DateTime, or 'envelope_ids' or 'transaction_ids' must be specified.
I tried the following:
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = l_url (https://demo.docusign.net/restapi/v2/accounts/XXXXXX')
proxy_host = co_proxy_host
proxy_service = co_proxy_service
IMPORTING
client = lo_http_client
lo_http_client->request->set_method( method = 'POST').
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/json'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'X-DocuSign-Authentication'
value = get_auth_header( ). (json auth header)
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = create_body( ).
This is my body:
CONCATENATE
`{`
`"emailSubject": "DocuSign REST API Quickstart Sample",`
`"emailBlurb": "Shows how to create and send an envelope from a document.",`
`"recipients": {`
`"signers": [{`
`"email": "test#email",`
`"name": "test",`
`"recipientId": "1",`
`"routingOrder": "1"`
`}]`
`},`
`"documents": [{`
`"documentId": "1",`
`"name": "test.pdf",`
`"documentBase64":` `"` l_encoded_doc `"`
`}],`
`"status": "sent"`
`}` INTO re_data.
The api request to get the Baseurl is working fine. (I know the error is quite specific what the problem is, but i cant find any sources on the docusign api documentation that one of the mentioned parameters should be added to the request)
Thank you in regards
The error message seems to indicate that you're Posting to an endpoint that requires certain query string parameters -- but you're not specifying them as expected in the query string. I'd suggest you check the DocuSign API documentation for the operation you are using, to determine what query string parameters it requires, and then ensure that you're including those parameters in your request URL.
If you can't figure this out using the documentation, then I'd suggest that you update your post to clarify exactly what URL (endpoint) you are using for the request, including any querystring parameters you're specifying in the URL. You can put fake values for things like Account ID, of course -- we just need to see the endpoint you are calling, and what qs params you're sending.
To create an envelope, use
https://demo.docusign.net/restapi/v2/accounts/XXXXXX/envelopes
instead of
https://demo.docusign.net/restapi/v2/accounts/XXXXXX
Thank you for all the answers, i found the mistake. Creating the request wasn´t the problem. I was using the wrong "sending"-method -_-.
now its working :)
lo_rest_client->post( EXPORTING io_entity = lo_request_entity ).

What is a REST response, what does it do?

I had made a REST webservice using redirecting to various paths like if i need to delete some user then i will redirect the user to this address in the #Path annotation :
user/delete
and therefore there is no thing like RESPONSE i have used.
While going through a code given to me by my senior i came accross these lines :
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
Response.created(uri).build();
What are these lines doing, i have no idea.
Can someone explain me this w/o wiki links or any other 'Basic Rest Service' links.
Without any explicit details about the uriInfo object I can only speculate its type is the JAX-RS UriInfo class.
The first line can be broken down as below:
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
The getAbsolutePathBuilder is documented http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/UriInfo.html#getAbsolutePathBuilder%28%29
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
The method returns a UriBuilder object. On which the 'path(...)' method is called passing the id so if the absolute path returned http://www.host.com (this may or may not have a port number) adding the id in this method will then result in the effectively Builder holding the two parts. The base URI and the path. The two values have not yet been put together
The build method then concatenates the two values resulting a full URI. For example http://www.google.com/id (Where http://www.google.com is the absolute path)
The second line
Response.created(uri).build();
Is basically saying 'Respond with a created (201) response code, and set a Location header containing the build uri value'

http delete with REST

I am currently using Jersey Framework (JAX-RS implementation) for building RESTful Web Services. The Resource classes in the project have implemented the standard HTTP operations - GET,POST & DELETE. I am trying to figure out how to send request parameters from client to these methods.
For GET it would be in the query string(extract using #QueryParam) and POST would be name/value pair list (extract using #FormParam) sent in with the request body. I tested them using HTTPClient and worked fine. For DELETE operation, I am not finding any conclusive answers on the parameter type/format. Does DELETE operation receive parameters in the query string(extract using #QueryParam) or in the body(extract using #FormParam)?
In most DELETE examples on the web, I observe the use of #PathParam annotation for parameter extraction(this would be from the query string again).
Is this the correct way of passing parameters to the DELETE method? I just want to be careful here so that I am not violating any REST principles.
Yes, its up to you, but as I get REST ideology, DELETE URL should delete something that is returned by a GET URL request. For example, if
GET http://server/app/item/45678
returns item with id 45678,
DELETE http://server/app/item/45678
should delete it.
Thus, I think it is better to use PathParam than QueryParam, when QueryParam can be used to control some aspects of work.
DELETE http://server/app/item/45678?wipeData=true
The DELETE method should use the URL to identify the resource to delete. This means you can use either path parameters or query parameters.
Beyond that, there is no right and wrong way to construct an URL as far as REST is concerned.
You can use like this
URL is http://yourapp/person/personid
#DELETE
#Path("/person/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response deletePerson(#PathParam("id") String id){
Result result = new Result();
try{
persenService.deletePerson(id);
result.setResponce("success");
}
catch (Exception e){
result.setResponce("fail");
e.printStackTrace();
}
return Response.status(200).entity(result).build();
}
#QueryParam would be the correct way. #PathParam is only for things before any url parameters (stuff after the '?'). And #FormParam is only for submitted web forms that have the form content type.

JSON endpoint with .NET RIA Domainservice

I have created a RIA-service and added a JSON endpoint following this tutorial: http://www.c-sharpcorner.com/UploadFile/pchandraker/1320/. When testing it in the browser, hitting
http://localhost:52878/Project-Web-DomainService.svc/json/GetProjects
returns nothing. When inspecting the request in Firebug, neither the response headers or body is set. Hitting an invalid url, such as http://localhost:52878/Project-Web-DomainService.svc/json/GetProjectsINVALID returns a 404, saying "Endpoint not found" as expected.
Do I need to add additional metadata or configuration settings to either DomainService.cs or Web.config to get the JSON output?
Decorate your GetProjects functions from DomainService with [QueryAttribute(HasSideEffects = true)] attribute.
Good luck.