• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer

REST API Tutorial

  • REST
  • JSON
  • Dark Mode
Home / Tech Guides / Create REST APIs with JAX-RS

Create REST APIs with JAX-RS

In REST API Design Tutorial, we learned to put the REST principles onto design process of a network application. In this post, we will learn to create REST APIs using JAX-RS 2.0 (Java API for RESTful Services).

Table of Contents

JAX-RS 2.0 Specification
JAX-RS 2.0 Annotations
Create Maven Application
Include JAX-RS Dependencies to Application
Create Resource Representations
Create REST Resource
Register Resource in runtime
Demo

JAX-RS 2.0 Specification

JAX-RS provides portable APIs for developing, exposing, and accessing Web applications designed and implemented in compliance with principles of REST architectural style.

The Java EE 6 release took the first step towards standardizing RESTful web service APIs by introducing a Java API for RESTful web services (JAX-RS) [JSR 311]. JAX-RS ensures portability of REST API code across all Java EE-compliant application servers. The latest version is JAX-RS 2.0 [JSR 339], which was released as part of the Java EE 7 platform.

JAX-RS focuses on applying Java annotations to plain Java objects. JAX-RS has annotations to bind specific URI patterns and HTTP operations to specific methods of your Java class. It also has annotations that can help you handle input/output parameters.

As we already said that JAX-RS is specification; it means we need to have its implementation to run REST API code. Some of the popular JAX-RS implementations available today are:

  • Jersey
  • RESTEasy
  • Apache CXF
  • Restlet

JAX-RS 2.0 Annotations

Let’s go through some essential annotations provided by JAX-RS 2.0.

@Path(‘resourcePath’)

It is used to match the URI path, which is relative to base URI. It can be specified on resource class or method.

@Path("/configurations")
public class ConfigurationResource 
{
	@Path("/{id}")
	@GET
	public Response getConfigurationById(@PathParam("id") Integer id){
		...
	}
}

Sets the path to base URL + /resourcePath. The base URL is based on your application name, the servlet and the URL pattern from the web.xml configuration file.

@POST

Annotated method will handle the HTTP POST requests on matching resource path.

@POST
@Consumes("application/xml")
public Response createConfiguration(Configuration config) {
	...
}

@PUT

Annotated method will handle the HTTP PUT requests on matching resource path.

@PUT
@Consumes("application/xml")
public Response updateConfiguration(@PathParam("id") Integer id, Configuration config){
	...
}

@GET

Annotated method will handle the HTTP GET requests on matching resource path.

@GET
@Path("/{id}")
public Response getConfigurationById(@PathParam("id") Integer id){
	...
}

@DELETE

Annotated method will handle the HTTP DELETE requests on matching resource path.

@DELETE
@Path("/{id}")
public Response deleteConfiguration(@PathParam("id") Integer id){
	...
}

@PathParam(“parameterName”)

It is used to inject values (resource identifiers) from the URL into a method parameter.

@DELETE
@Path("/{id}")
public Response deleteConfiguration(@PathParam("id") Integer id){
	...
}

In above example, the value of id from /{id} will match to @PathParam("id") Integer id. For example, URI HTTP DELETE /configurations/22312 will be mapped to above method and id will be populated with value 22312.

@Produces

It defines which MIME type is delivered by annotated resource methods. It can be defined at class level as well as method level. If defined at class level, all methods inside resource class will be returning the same MIME type, if not overridden in any method.

@Path("/configurations")
@Produces("application/xml")
public class ConfigurationResource {
	...
}

@Consumes

It defines which MIME type is consumed by annotated resource method.

@POST
@Consumes("application/xml")
public Response createConfiguration(Configuration config) {
	...
}

@Context

To build HATEOAS links, JAX-RS 2.0 provides UriInfo class which can be obtained using the @Context annotation.

@Context
UriInfo uriInfo;
By default the JAX-RS runtime will automatically support the methods HEAD and OPTIONS, if not explicitly implemented. For HEAD the runtime will invoke the implemented GET method (if present) and ignore the response entity (if set). The OPTIONS method can return a response with a set of supported resource methods in the ‘Allow’ header.

Create Maven Application

Maven is a software project management and comprehension tool including project build, reporting and documentation from a central piece of information i.e. pom.xml.

To create an application using maven in eclipse, follow these steps:

  • Open new project wizard from File > New > Maven Project
    Create Maven Application - Step 1
    Create Maven Application – Step 1
  • Click on Next
    Create Maven Application - Step 2
    Create Maven Application – Step 2
  • Select maven-archtype-webapp
    Create Maven Application - Step 3
    Create Maven Application – Step 3
  • Fill project details and click on Finish
    Create Maven Application - Step 4
    Create Maven Application – Step 4

Include JAX-RS Dependencies to Application

JAX-RS 2.0 comes bundled with JDK 1.7, so if you have JDK 1.7 or higher version in JAVA_HOME then you don’t need to include JAX-RS separately. However, you will need to include one of its implementations listed above.

In this example, I am using RESTEasy 3.1.2.Final.

<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>net.restfulapi.app</groupId>
	<artifactId>NetworkManagement</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>NetworkManagement</name>
	<url>http://maven.apache.org</url>
	<repositories>
		<repository>
			<id>jboss</id>
			<name>jboss repo</name>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
		</repository>
	</repositories>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.2</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
		<finalName>NetworkManagement</finalName>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.jboss.resteasy</groupId>
			<artifactId>resteasy-jaxrs</artifactId>
			<version>3.1.2.Final</version>
		</dependency>
		<dependency>
			<groupId>org.jboss.resteasy</groupId>
			<artifactId>resteasy-jaxb-provider</artifactId>
			<version>3.1.2.Final</version>
		</dependency>
		<dependency>
			<groupId>org.jboss.resteasy</groupId>
			<artifactId>resteasy-servlet-initializer</artifactId>
			<version>3.1.2.Final</version>
		</dependency>
		
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>
resteasy-servlet-initializer artifact enable automatic scanning for resources and providers in Servlet 3.0 containers.

Create Resource Representations

In JAX-RS, resource representations are POJO classes annotated with JAXB annotations i.e. @XmlRootElement, @XmlAttribute and @XmlElement etc.

In this example, we are exposing two representations. Let’s create java classes for them.

1) Configurations collection resource
package net.restfulapi.app.rest.domain;

import java.util.List;

import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement(name = "configurations")
@XmlAccessorType(XmlAccessType.FIELD)
public class Configurations 
{
	@XmlAttribute
	private Integer size;
	
	@XmlJavaTypeAdapter(Link.JaxbAdapter.class)
	@XmlElement
	private Link link;
	
	@XmlElement
	private List<Configuration> configurations;

	public Integer getSize() {
		return size;
	}

	public void setSize(Integer size) {
		this.size = size;
	}

	public Link getLink() {
		return link;
	}

	public void setLink(Link link) {
		this.link = link;
	}

	public List<Configuration> getConfigurations() {
		return configurations;
	}

	public void setConfigurations(List<Configuration> configurations) {
		this.configurations = configurations;
	}
}
2) Configuration resource
package net.restfulapi.app.rest.domain;

import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import net.restfulapi.app.rest.domain.common.Status;

@XmlRootElement(name="configuration")
@XmlAccessorType(XmlAccessType.FIELD)
public class Configuration 
{
	@XmlAttribute
	private Integer id;
	@XmlJavaTypeAdapter(Link.JaxbAdapter.class)
	@XmlElement
	private Link link;
	@XmlElement
	private String content;
	@XmlElement
	private Status status;

	public Link getLink() {
		return link;
	}

	public void setLink(Link link) {
		this.link = link;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}
}
3) Message resource [to inform client when no resource representation needed]
package net.restfulapi.app.rest.domain.common;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "message")
public class Message {
	
	public Message() {
		super();
	}

	public Message(String content) {
		super();
		this.content = content;
	}

	private String content;

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}
}

Additionally, we have simulated the DB functionality using ConfigurationDB class. It exposes static utility methods for CRUD operations in configuration resource collection and individual configuration resources.

package net.restfulapi.app.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import net.restfulapi.app.rest.domain.Configuration;
import net.restfulapi.app.rest.domain.common.Status;

public class ConfigurationDB {
	private static Map<Integer, Configuration> configurationDB = new ConcurrentHashMap<Integer, Configuration>();
	private static AtomicInteger idCounter = new AtomicInteger();
	
	public static Integer createConfiguration(String content, Status status){
		Configuration c = new Configuration();
		c.setId(idCounter.incrementAndGet());
		c.setContent(content);
		c.setStatus(status);
		configurationDB.put(c.getId(), c);
		
		return c.getId();
	}
	
	public static Configuration getConfiguration(Integer id){
		return configurationDB.get(id);
	}
	
	public static List<Configuration> getAllConfigurations(){
		return new ArrayList<Configuration>(configurationDB.values());
	}
	
	public static Configuration removeConfiguration(Integer id){
		return configurationDB.remove(id);
	}
	
	public static Configuration updateConfiguration(Integer id, Configuration c){
		return configurationDB.put(id, c);
	}
}

Create REST Resource

We have already learned about JAX-RS annotations in the second section. Let’s apply them to REST resources and map HTTP methods on operations on REST resources.

I have added self-explanatory code comments above each method to explain it.

package net.restfulapi.app.rest.service;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import net.restfulapi.app.dao.ConfigurationDB;
import net.restfulapi.app.rest.domain.Configuration;
import net.restfulapi.app.rest.domain.Configurations;
import net.restfulapi.app.rest.domain.common.Message;
import net.restfulapi.app.rest.domain.common.Status;

/**
 * This REST resource has common path "/configurations" and 
 * represents configurations collection resources as well as individual collection resources.
 * 
 * Default MIME type for this resource is "application/XML"
 * */
@Path("/configurations")
@Produces("application/xml")
public class ConfigurationResource 
{
	/**
	 * Use uriInfo to get current context path and to build HATEOAS links 
	 * */
    @Context
    UriInfo uriInfo;
    
    /**
     * Get configurations collection resource mapped at path "HTTP GET /configurations"
     * */
    @GET
    public Configurations getConfigurations() {
         
        List<Configuration> list = ConfigurationDB.getAllConfigurations();
         
        Configurations configurations = new Configurations();
        configurations.setConfigurations(list);
        configurations.setSize(list.size());
         
        //Set link for primary collection
        Link link = Link.fromUri(uriInfo.getPath()).rel("uri").build();
        configurations.setLink(link);
         
        //Set links in configuration items
        for(Configuration c: list){
            Link lnk = Link.fromUri(uriInfo.getPath() + "/" + c.getId()).rel("self").build();
            c.setLink(lnk);
        }
        return configurations;
    }
     
    /**
     * Get individual configuration resource mapped at path "HTTP GET /configurations/{id}"
     * */
    @GET
    @Path("/{id}")
    public Response getConfigurationById(@PathParam("id") Integer id){
        Configuration config = ConfigurationDB.getConfiguration(id);
        
        if(config == null) {
    		return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND).build();
    	}
         
        if(config != null){
            UriBuilder builder = UriBuilder.fromResource(ConfigurationResource.class)
                    						.path(ConfigurationResource.class, "getConfigurationById");
            Link link = Link.fromUri(builder.build(id)).rel("self").build();
            config.setLink(link);
        }
         
        return Response.status(javax.ws.rs.core.Response.Status.OK).entity(config).build();
    }
    
    /**
     * Create NEW configuration resource in configurations collection resource
     * */
    @POST
    @Consumes("application/xml")
    public Response createConfiguration(Configuration config){
    	if(config.getContent() == null)  {
    		return Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST)
    						.entity(new Message("Config content not found"))
    						.build();
    	}

    	Integer id = ConfigurationDB.createConfiguration(config.getContent(), config.getStatus());
    	Link lnk = Link.fromUri(uriInfo.getPath() + "/" + id).rel("self").build();
    	return Response.status(javax.ws.rs.core.Response.Status.CREATED).location(lnk.getUri()).build();
    }
    
    /**
     * Modify EXISTING configuration resource by it's "id" at path "/configurations/{id}"
     * */
    @PUT
    @Path("/{id}")
    @Consumes("application/xml")
    public Response updateConfiguration(@PathParam("id") Integer id, Configuration config){
    	
    	Configuration origConfig = ConfigurationDB.getConfiguration(id);
    	if(origConfig == null) {
    		return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND).build();
    	}
    	
    	if(config.getContent() == null)  {
    		return Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST)
    						.entity(new Message("Config content not found"))
    						.build();
    	}

    	ConfigurationDB.updateConfiguration(id, config);
    	return Response.status(javax.ws.rs.core.Response.Status.OK).entity(new Message("Config Updated Successfully")).build();
    }
    
    /**
     * Delete configuration resource by it's "id" at path "/configurations/{id}"
     * */
    @DELETE
    @Path("/{id}")
    public Response deleteConfiguration(@PathParam("id") Integer id){
    	
    	Configuration origConfig = ConfigurationDB.getConfiguration(id);
    	if(origConfig == null) {
    		return Response.status(javax.ws.rs.core.Response.Status.NOT_FOUND).build();
    	}
    	
    	ConfigurationDB.removeConfiguration(id);
    	return Response.status(javax.ws.rs.core.Response.Status.OK).build();
    }
     
    /**
     * Initialize the application with these two default configurations
     * */
    static {
        ConfigurationDB.createConfiguration("Some Content", Status.ACTIVE);
        ConfigurationDB.createConfiguration("Some More Content", Status.INACTIVE);
    }
}

Register Resource in Runtime

To register JAX-RS REST resource with server’s runtime, you will need to extend javax.ws.rs.core.Application class and put it in application’s classpath.

package net.restfulapi.app.rest;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import net.restfulapi.app.rest.service.ConfigurationResource;

@ApplicationPath("/network-management")
public class NetworkApplication extends Application {

   private Set<Object> singletons = new HashSet<Object>();
   private Set<Class<?>> empty = new HashSet<Class<?>>();

   public NetworkApplication() {
      singletons.add(new ConfigurationResource());
   }

   @Override
   public Set<Class<?>> getClasses() {
      return empty;
   }

   @Override
   public Set<Object> getSingletons() {
      return singletons;
   }
}

Here @ApplicationPath annotation identifies this class as REST application to automatic scanning process in servlet 3.0 containers. It helps in making web.xml file almost empty – with no REST specific configuration at all.

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
	<display-name>Archetype Created Web Application</display-name>
</web-app>

Demo

Build and deploy this project to any web server and start the server. Now test the REST APIs by invoking above URIs on any browser client.

HTTP GET http://localhost:8080/NetworkManagement/network-management/configurations

Fetch collection of configurations.

HTTP GET - Configuration Collection Resource
HTTP GET – Configuration Collection Resource
HTTP GET http://localhost:8080/NetworkManagement/network-management/configurations/1

Fetch individual configuration.

HTTP GET - Individual Configuration Resource
HTTP GET – Individual Configuration Resource
HTTP POST http://localhost:8080/NetworkManagement/network-management/configurations

Create a new configuration resource.

HTTP POST - Create New Resource
HTTP POST – Create New Resource
HTTP PUT http://localhost:8080/NetworkManagement/network-management/configurations/1

Update configuration resource.

HTTP PUT - Update Individual Configuration Resource
HTTP PUT – Update Individual Configuration Resource
HTTP DELETE http://localhost:8080/NetworkManagement/network-management/configurations/1

Remove configuration resource.

HTTP DELETE - Individual Configuration Resource
HTTP DELETE – Individual Configuration Resource

Click on the given download link to download source code for this application.

Download Sourcecode

Was this article helpful?

TwitterFacebookLinkedInReddit
Previous Tutorial:
How to design a REST API
Next Tutorial:

Reader Interactions

Comments

  1. Ketlen says

    April 8, 2020 at 7:24 pm

    Hi! Congrats for the example. But, what about the class “Status”? I’m sorry, Idk the implementation.

    Reply
    • ahmad says

      May 25, 2020 at 6:04 am

      Hey Kerlen, did you know what “Status” class is ??

      Reply
  2. Ricardo says

    June 25, 2019 at 9:37 pm

    Thanks!

    Very useful!

    Reply
  3. Pranav says

    June 14, 2019 at 5:42 am

    Why setLink() method is not used while implementing @POST HTTP method??
    How will it directly reflect while running on a server, as link is not set?

    Reply
  4. dn.perl says

    May 31, 2019 at 3:25 am

    I wish you had chosen a different noun rather than ‘configuration’ in this tutorial. There is a library named Configuration, and if I want to edit this tutorial for a noun named ‘node’, I do not know where to replace the noun ‘configuration’ with ‘node’ and where to let it be because it refers to the library.

    Reply
  5. nkundwa says

    April 18, 2019 at 2:55 pm

     
    
    	@POST
    	@Consumes("application/xml")
    	public Response createConfiguration(Configuration config) {
    		
    		if (config.getContent() == null) {
    			return Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST)
    					       .entity(new Message("Config content not found")).build();
    		}
    		Integer id = ConfigurationDB.createConfiguration(config.getContent(), config.getStatus());
    		Link lnk = Link.fromUri(uriInfo.getPath() + "/" + id).rel("self").build();
    		
    		return Response.status(javax.ws.rs.core.Response.Status.CREATED).location(lnk.getUri()).build();
    	}
    
    

    This method POST doesn’t work properly when I test it with Postman. How can I add xml text when creating new configuraion?

    Reply
    • Admin says

      April 18, 2019 at 8:17 pm

      What error or problem you are facing. Please write in detail.

      Reply
  6. Rajkumar says

    February 15, 2019 at 12:41 pm

    Is their any way to configure the path via configurable xml. I mean instead of specifying annotation for specifying the path for each methods, is their any options to redirect to a particular method based on the xml configuration. XML means I dont need to re-compile the code again and again, whereas the path I specify in code differs from customer to customer. If it is via xml I can ask them to change the xml file alone.

    Reply
  7. Meziano says

    September 29, 2017 at 7:36 am

    Spring REST is NOT a JAX-RS implementaion!

    Reply
    • Admin says

      October 3, 2017 at 10:23 am

      Thanks for observing this. Yes, it is not JAX-RS reference implementation.

      Reply
  8. sabr sheikkh says

    June 21, 2017 at 2:49 pm

    Good conceptual wise expanation.

    Reply
  9. Santhosh Krishnan says

    June 15, 2017 at 5:42 am

    Thanks for the Awesome tutorial….
    worked perfectly!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

Search Tutorials

Learn REST

  • What is REST?
  • REST Constraints
  • REST Resource Naming Guide

Guides

  • Caching
  • Compression
  • Content Negotiation
  • HATEOAS
  • Idempotence
  • Security Essentials
  • Versioning
  • Statelessness in REST APIs

Tech – How To

  • REST API Design Tutorial
  • Create REST APIs with JAX-RS

FAQs

  • PUT vs POST
  • N+1 Problem
  • ‘q’ Parameter

Resources

  • What is an API?
  • Comparing SOAP vs REST APIs
  • HTTP Methods
  • Richardson Maturity Model
  • HTTP Response Codes
    • 200 (OK)
    • 201 (Created)
    • 202 (Accepted)
    • 204 (No Content)
    • 301 (Moved Permanently)

Footer

References

  • The dissertation by Roy Thomas Fielding
  • Uniform Resource Identifier (URI, URL, URN) [RFC 3986]
  • Internet MediaTypes
  • Web Application Description Language (WADL)

Meta Links

  • About
  • Contact Us
  • Privacy Policy

Blogs

  • How To Do In Java

Copyright © 2020 · restfulapi.net · All Rights Reserved. | Sitemap