понедельник, 23 сентября 2013 г.

Building RESTful web services with JAX-RS(Jersey)

     In this article I will focuses on explaining the REST architecture and we will build a simple RESTfull application with JAX-RS library called Jersey.
     Representational State Transfer or REST is a simple way to organize interactions between independent system. It can be used wherever HTTP can. One of the idea of the REST that application should have specific purposes, like retrieving, adding, deleting or updating data(HTTP service request). And actions should be performed no more than one at a time.
 - POST - create a new resource(resource is contained in the body of the POST request)
 - GET - retrieves a resource from the server
 - PUT - updates the state of a known resource
 - DELETE - deletes a resource on the server
      Here’re some HTTP response codes which are often used with REST.
 - 200 ok - indicates that request was successful
 - 201 created - request was successful and a resource was created
 - 400 bad request - request was malformed
 - 401 unauthorized - must perform authentication before accessing the resource
 - 404 not found - resource could not be found
 - 500 internal server error
     First, create a standard web project from maven archetype:
      mvn archetype:generate -DgroupId=com.dmitrynikol.rest -DartifactId=RESTfulApp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
Now run a command to add dependencies in project, eclipse can resolve them, we just convert maven based Java project into to support Eclipse IDE.
     mvn eclipse:eclipse -Dwtpversion=2.0
After that you will see two new files “.classpath” and “.project”. And now you can easily import a project into your Eclipse workspace. So, now we have a maven web stub project.
     Now, let’s make sure that we have all dependencies that we need in Maven pom.xml file.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dmitrynikol.rest</groupId>
  <artifactId>RESTfulApp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>RESTfulApp Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  <dependencies>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-server</artifactId>
      <version>1.9</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.9</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey.jersey-test-framework</groupId>
      <artifactId>jersey-test-framework-core</artifactId>
      <version>1.9</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey.jersey-test-framework</groupId>
      <artifactId>jersey-test-framework-external</artifactId>
      <version>1.9</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <finalName>RESTfulApp</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
          <downloadSources>true</downloadSources>
          <downloadJavadocs>true</downloadJavadocs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
     POJO class User object that mapping to JSON via JAXB with @XmlRootElement annotation.
/**
 * A typical User entity. 
 * XmlRootElement annotation enable JAXB to convert to and from JSON  
 * 
 * @author Dmitry Nikolaenko
 *
 */
@XmlRootElement
public class User {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    
    public User(){}
    
    public User(String id, String firstName, String lastName, String email) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}
     Time to create UserService class, that represent a Jersey resources as an POJO and will be manipulated by different HTTP methods. Service class contains many annotations to create different behaviours.
And Jersey provides a set of Java annotations that can be used to define the web service structure.
 - @Path - configure the URL pattern the class will handle
 - @Post, @GET, @PUT and @DELETE - method will answer to the HTTP POST, GET, PUT and DELETE request
 - @Produces - specifies the MIME type of the response that is returned to the client
 - @Consumes - specifies the content type that the service will accept as input
 - @QueryParam - mark a field that will be extracted from the URL in a GET request
 - @DefaultValue - mark the value that will be used by default
 - @PathParam - mark a field that will be extracted from a field in the URL path
/**
 * UserService represent a Jersey resources that will be 
 * manipulated by different HTTP methods.
 * 
 * @author Dmitry Nikolaenko
 *
 */
@Path("/user")
public class UserService {
     /**
     * Method handling HTTP GET requests, returned object will be
     * sent to the client as "text/plain" media type.
     * 
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/stub")
    public String getStub() {
        return "stub";
    }
    
    @GET
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/all")
    public Response getAllUsers(@QueryParam("page") @DefaultValue("1") final String page) {
        // # See all the users in the system 
        // > curl -X GET http://localhost:8080/RESTfulApp/rest/user/all?page=3
        List<User> users = new ArrayList<User>();
        final User user1 = new User("1", "Tom", "Jenkins", "tom.jenkins@gmail.com");
        final User user2 = new User("2", "Red", "Balloon", "red.balloon@gmail.com");
        users.add(user1);
        users.add(user2);
        return Response.ok(users).build();
    }
    
    @POST
    @Path("/create")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response createUser(final User user) throws URISyntaxException {
        // # Create and save new user
        // > curl -X POST http://localhost:8080/RESTfulApp/rest/user/create
        return Response.ok(user).build();
    }
    
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/id/{id}")
    public Response getUserById(@PathParam("id") final String id) throws URISyntaxException {
        // # Get the information of the user
        // > curl -X GET http://localhost:8080/RESTfulApp/rest/user/id/12345
        final User user = new User("12345", "Max", "Liano", "maxliano@gmail.com");
        return Response.ok(user).build();
    }
    
    // POST is used create a new resource, PUT method updates the state of a known resource. 
    @PUT
    @Path("/id/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateUser(@PathParam("id") final String id, final User user)  
     throws URISyntaxException {
        // # Update user information
        // > curl -X PUT http://localhost:8080/RESTfulApp/rest/user/id/12345
        return Response.ok(user).build();
    }
    
    @DELETE
    @Path("/id/{id}")
    public Response deleteUser(@PathParam("id") final String id) throws URISyntaxException {
        // create a new ResponseBuilder with an OK status and appropriate a Response instance
        // Delete user
        // > curl -X DELETE http://localhost:8080/RESTfulApp/rest/user/id/12345
        return Response.ok().entity("User with ".concat(id).concat(" is deleted successfully")).build();
    }
}
     And don’t forget to add com.sun.jersey.api.json.POJOMappingFeature to web.xml file that integrate JSON with Jersey. It will make Jersey support JSON/object mapping.
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    <display-name>Restful Web Application</display-name>
    
    <servlet>
        <servlet-name>Jersey REST Servlet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
             <param-name>com.sun.jersey.config.property.packages</param-name>
             <param-value>com.dmitrynikol.services</param-value>
        </init-param>
        <!-- integrate JSON with Jersey. It will make Jersey support JSON/object mapping -->
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>Jersey REST Servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>
     That’s all. Now we’re ready to start the rest service with tomcat instance via command - mvn tomcat:run The complete source code to this example is available on Github. Have fun with the code!

Комментариев нет:

Отправить комментарий