How to do REST webservice url versioning? - web-services

I need to version a REST web service API. I have gone through several posts under Stack Overflow. I discovered that there are three approaches: Url versioning, Custom Request header and Accept Header. I was about to go for URL versioning.
My URL is something like this:
http://localhost:8080/api/svcs/1.0/usrLocation?1234
Now my question how to version the above url. I didn't find any practical example from server side code. I was able to find the theoretical and URL like:
http://localhost:8081/api/svc/v1/ and blah blah..
How will my jax-rs implementation code will look like and how will the actual concept will be implemented in server side?
I am a beginner to this. My JAX-RS implementation is Apache CXF
My code:
#Get
#Path("/usrLocation")
#Produces (MediaType.APPLICATION_JSON)
public Response getUsrLocation(#QueryParam ("locId") String locId){
// logic
}
How the url http://localhost:8080/api/svcs/1.0/usrLocation?1234 needs to be changed to versioning so that it will be helpful in future and how it works from jax-rs implementation side?

You can follows two design approach
Say suppose your changes( would be) are minimal and its at particular part of code, for example you have insurance policy application and you are upgrading the application to new version because govt has introduced a policy which effects commissioning. and you have module for calculating commissioning then you can pass the version as a parameter.
#Path("/svc")
public class KPApiService {
private final static Logger LOG = LoggerFactory.getLogger(KPApiService.class);
#Path("/{version}/myapp")
#GET
public Response myApp(#PathParam("version")String version, #QueryParam("kpdata")String data){
LOG.debug("You and entered version {} and data {} ", version, data);
}
}
Say suppose you are changes are effecting so much and you want to introduce new module but there are few users(legacy) who are yet to brass the changes, then you can create a separate method with different version
#Path("/svc")
public class KPApiService {
private final static Logger LOG = LoggerFactory.getLogger(KPApiService.class);
#Path("/1.0/myapp1")
#GET
public Response myApp1(#QueryParam("kpdata")String data){
LOG.debug("You and entered version v1 and data {} ", data);
}
#Path("/1.2/myapp1")
#GET
public Response myApp2(#QueryParam("kpdata")String data){
LOG.debug("You and entered version v2 and data {} ", data);
}
}

Related

cxfendpoint change WS-Addressing namespace to 2005/08 and removal of Offer in CreateSequence

I hope it is ok to ask two somehow related Questions in one.
I am using a camel route to send a SOAP message to a webservice using Reliable Messaging. Now there is two Problems i ran into, first the WS-Addressing version that is used is wrong, i need to have 2005/08 but instead it is using 2004/08.
For setting up the endpoint i am using (shortend a bit)
CxfEndpoint cxfEndpoint = new CxfEndpoint();
cxfEndpoint.setWsdlURL(getWsdlURL());
cxfEndpoint.setDataFormat(DataFormat.CXF_MESSAGE);
cxfEndpoint.setCamelContext(camelContext);
camelContext.addEndpoint(outEndpoint.getId(), cxfEndpoint);
I also set up a cxfbus in the camel-context.xml file and a seperate http-conduit.xml
now my question for the WS-Addressing is, how can i change it to use WS-Addressing 2005/08? i already tried to add following to my route, before the endpoint is called, but it did not change the Addressing Namespace.
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
AddressingPropertiesImpl addrProps =
new AddressingPropertiesImpl("http://www.w3.org/2005/08/addressing");
Map<String, Object> requestContext = new HashMap<String, Object>();
requestContext.put("javax.xml.ws.addressing.context", addrProps);
exchange.getIn().setHeader(Client.REQUEST_CONTEXT, requestContext);
}
})
Regarding the Offer in the CreateSequence added the following before the endpoint is added to the CamelContext:
RMManager rmManager = cxfEndpoint.getBus().getExtension(RMManager.class);
rmManager.getSourcePolicy().setIncludeOffer(false);
Although this worked fine it had the nasty side effect that my http-conduit was no longer used. I fixed this with following:
cxfEndpoint.setBus(bus);
where bus is being #Autowired
but in my opinion this broke the WS-Reliable Messaging for my incoming CXF Endpoint that are created in a similiar way. It still sends the correct messages but before the CreateSequenceResponse is send, there is an empty SOAP message sent, that causes the client to drop out of the Sequence creation.
Now my question would be, is there a better way to remove the Offer from the CreateSequence?

Apply HTTP basic authentication to jax ws (HttpSpiContextHandler) in embedded Jetty

There are some similar questions for earlier versions of Jetty (pre 9) but none that address this specific problem :
Server server = new Server();
System.setProperty("com.sun.net.httpserver.HttpServerProvider",
JettyHttpServerProvider.class.getName());
JettyHttpServer jettyServer = new JettyHttpServer(server, true);
Endpoint endpoint = Endpoint.create(new SOAPService()); // this class to handle all ws requests
endpoint.publish(jettyServer.createContext("/service")); // access by path
server.start()
Simplified code example above to show the only way that I have found to bridge between Jetty and incoming soap requests to my jax-ws service. All settings are in code with no web.xml, this is part of a larger solution that has multiple contexts and connections for different purposes (servlets etc..)
I have tried to add a handler class to the jettyServer.createContext("/service",new handler()) to see if I can perform a header extraction to simulate basic auth but it never gets executed.
My problem is that i cannot find a way to specify, by code against the Jetty server, to use basic authentication. Using the setSecurityHandler method of a ServletContextHandler is easy and works great for other contexts, i just can't figure out how to use this concept for the jax-ws service.
Any help would be much appreciated.
p.s. SSL is already implemented, I just need to add http basic auth.
For anyone else that may of come across the same problem here is the answer that i stumbled on eventually.
final HttpContext httpContext = jettyServer.createContext("/service");
com.sun.net.httpserver.BasicAuthenticator a = new com.sun.net.httpserver.BasicAuthenticator("") {
public boolean checkCredentials (String username, String pw)
{
return username.equals("username") && pw.equals("password");
}
};
httpContext.setAuthenticator(a);
endpoint.publish(httpContext);//access by path
You can expand the checkCredentials for something a bit more sophisticated of course, but this shows the basic working method.

Convert SOAP to REST [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
How to to Convert SOAP to REST using java language?
package net.weather;
import java.sql.*;
import javax.jws.WebService;
#WebService
public class ProjectFinalWS{
Connection con;
Statement st;
ResultSet rs;
String res;
public void connectDB()
{
String url ="jdbc:mysql://localhost:3306/";
String dbName ="project";
String driver = "com.mysql.jdbc.Driver";
String userName = "root";
String password = "root";
try
{
Class.forName(driver).newInstance();
con = DriverManager.getConnection(url+dbName,userName,password);
}catch(Exception e){}
}
public float getMaxTemp(String city)
{ float mxtemp=0;
connectDB();
try{
st=con.createStatement();
rs=st.executeQuery("select maxtemp from weather where city='"+city+"'");
rs.next();
mxtemp=rs.getFloat(1);
st.close();
con.close();
}
catch(Exception e){}
return mxtemp;
}
public float getMinTemp(String city)
{ float mntemp=0;
connectDB();
try{
st=con.createStatement();
rs=st.executeQuery("select mintemp from weather where city='"+city+"'");
rs.next();
mntemp=rs.getFloat(1);
st.close();
con.close();
}
catch(Exception e){}
return mntemp;
}
public float getHumidity(String city)
{ float humidity=0;
connectDB();
try{
st=con.createStatement();
rs=st.executeQuery("select humidity from weather where
city='"+city+"'");
rs.next();
humidity=rs.getFloat(1);
st.close();
con.close();
}
catch(Exception e){}
return humidity;
}
}
REST is a completely different way to think of a web service to SOAP. In particular, it operates in terms of resources, their representations and the links between them. (You also have HTTP verbs about, but for a simple query service like this one you'd probably only be using GET anyway.)
A RESTful version of that interface would work a bit like this:
A client would decide they want to know some information about a particular place, so they'd ask the service to search for that place and tell them the link to it, or at least to places that match the search criteria; since that might be several different places (think "London, UK" vs. "London, Ont." in response to a search for "London") the result will be a page that links to the characterization of each of the places. It might also say a bit about what each link means, but that's not necessary. (The format of the result can be HTML, or XML, or JSON, or any of a number of different formats; HTTP content negotiation makes for a great way to pick between them.)
Once the user has decided which place from the list they actually want information about, they follow the link and get a description of what information about that place is available. This is a document that provides links to a page that provides the max temperature, another page that provides the min temperature, and a third that provides the humidity.
To get the actual data, another link is followed and that data is served up. Since the data is a simple float, getting it back as plain text is quite reasonable.
Now, we need to map these things to URLs:
Searching: /search?place=somename (which is easy to hook up behind a place name), which contains links to…
Place: /place/{id} (where {id} is some general ID that probably is your DB's primary key; we don't want to use the name here because of the duplicate name problem), which contains links to…
Data: /place/{id}/maxTemp, /place/{id}/minTemp, /place/{id}/humidity.
We also need to have some way to do the document creation. JAXB is recommended. Links should probably be done in XML with attributes called xlink:href; using (by reference) the XLink specification like that states exactly that the content of the attribute is a link (the unambiguous statement of that is otherwise a real problem in XML due to its general nature).
Finally, you probably want to use JAX-RS to do the binding of your Java code to the service. That's way easier than writing it all yourself. That lets you get down to doing something like this (leaving out the data binding classes for brevity):
public class MyRestWeatherService {
#GET
#Path("/search")
#Produces("application/xml")
public SearchResults search(#QueryParam("place") String placeName) {
// ...
}
#GET
#Path("/place/{id}")
#Produces("application/xml")
public PlaceDescription place(#PathParam("id") String placeId) {
// ...
}
#GET
#Path("/place/{id}/maxTemp")
#Produces("text/plain")
public String getMaxTemperature(#PathParam("id") String placeId) {
// ...
}
// etc.
}
As you can see, it can go on a bit but it is not difficult to do so long as you start with a good plan of what everything means…
Thank goodness Donal Fellows pointed out the #WebService annotation. I didn't realize that this was a web service until he did.
You'll have more problems that API choices with this implementation. If you're deploying on a Java EE app server, I'd recommend using a JNDI data source and connection pool instead of hard wired database parameters and connecting for every request.
Better to close your resources in a finally block, wrapped in individual try/catch blocks.
Those empty catch blocks will drive you crazy. Bad things will happen, but you'll never know.
SOAP clients send an XML request over HTTP to a service that parses it, binds the values to inputs, uses them to fulfill the use case, and marshals a response as XML to send back.
REST asks clients to do all the same things, except instead of packaging the request parameters into an XML request they're sent via HTTP. The API is the HTTP GET, POST, DELETE. You express your method calls as URIs.
So it'll take a good knowledge of your SOAP API and some brains on your part. I don't know of any tools to do it for you.

Multiple content type support using JAX-RS

The goal is to create a rest-full web service using JAX-RS that will selectively return the result either in json or xml format, depending on the user request. For example, if the user issues a GET request in the following fashion the results will be returned in json format:
http://api.myurl.com/order/1234.json
Similarly, if the user issues a get in the following request, the results will be returned in xml format:
http://api.myurl.com/order/123.xml
I don't want to use request parameters to do this (i.e. http://api.myurl.com/order/123?format=json). Using the .json or .xml post-fix seems more intuitive to me.
What would be the best strategy for doing this using the JAX-RS api?
One way would be to use #Path annotations more thoroughly:
#GET
#Path("/order/{id}.xml")
#Produces("application/xml")
public Order getOrderAsXML(#PathParam("id") int id) {
return realGetOrder(id);
}
#GET
#Path("/order/{id}.json")
#Produces("application/json")
public Order getOrderAsJSON(#PathParam("id") int id) {
return realGetOrder(id);
}
private Order realGetOrder(int id) {
// ...
}
However I'd be inclined to have a single method serving up both and let the client and supporting JAX-RS framework use content negotiation to decide the serialization method.

How to return HTTPResponse from ASMX web service to consumer web page

I am working on an ASMX web service; trying to create a method that will download a document from a server and show the document in the browser (the calling .aspx web page). My service builds without error but I get the following error when I try to "Add Web Reference" in my Proxy class project:
System.Web.HttpResponse cannot be serialized because it does not have a parameterless constructor.
Here is a snippet of the code in .ASMX file:
public class FileService : System.Web.Services.WebService
{
[WebMethod]
public void DownloadDocument(string URI, HttpResponse httpResponse)
{
int DownloadChunkSize = (int)Properties.Settings.Default.DownloadChunkSize;
// some more code here....
using (httpResponse.OutputStream)
{
// more code here...
}
}
}
I see I am confused about how to send back an HttpResponse from a web service to a requesting web page. Could someone please give me a tip on how to do this? Thanks.
You should look into web handlers (.ashx). They are perfect for what you are trying to achieve.
For example:
public class Download : IHttpHandler, IRequiresSessionState {
public void ProcessRequest(HttpContext context) {
var pdfBytes = /* load the file here */
context.Response.ContentType = #"Application/pdf";
context.Response.BinaryWrite(pdfBytes);
context.Response.End();
}
}
UPDATE:
An ashx handler is actually a replacement to aspx. Basically, it has no UI but still processes get / post requests just like an aspx page does. The point is to reduce the overhead generated by running a regular aspx page when all you need to do is return some simple content (like a file...) or perform a quick action.
The IRequiresSessionState interface allows you to use the SESSION object like any other page in your site can. If you don't need that, then leave it off.
This site has an interesting walk through on how to create one. Ignore Step 4 as you probably don't care about that.
Assuming that you have a regular page (aspx) that has a link to your document: The link in the aspx file would actually point directly to your ashx handler. for example:
Click Here
Then the code in the ProcessRequest method of the ashx handler would do whatever calls it needed (like talk to your DLL) to locate the document then stream it back to the browser through the context.Response.BinaryWrite method call.
That is not how standard ASMX web services work. If you want to make your own handler, or even use an ASPX page to deliver the doc, you are fine, but the standard ASMX web service method of doing this is to actually return the bits of the document as an encoded blob.
If you want to roll your own, consider this article:
http://msdn.microsoft.com/en-us/magazine/cc163879.aspx
The web smethod (from asmx) returns an object, which can be serialized.
You need to create your method like:
[WbeMethod]
public byte[] DownloadDocument(string URI)
Or if the content is some text - return string.