Build REST web service using Spring
This tutorial provides a step-by-step guide on how to build REST web service using Spring framework.
Prerequisites:
- Eclipse IDE (Mars release)
- Java 1.8
- Apache tomcat 8
1. Create Maven web project
Create a maven web project using this tutorial and name your project as SpringRestService.
The structure of the generated project looks like the following:
2. Add Spring dependencies
After creating the web project, the first step is to add Spring dependencies into pom.xml, here we go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <properties> <springframework.version>4.3.0.RELEASE</springframework.version> <jackson.library>2.7.5</jackson.library> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.library}</version> </dependency> </dependencies> |
In this tutorial, we use Spring 4.3.0 and we’re interested in the following modules:
- spring-core: this is the core module of the Spring framework, it should be used in any spring-based application.
- spring-web, spring-webmvc: these are the web modules which allow you to create either REST resources or standard controllers.
- jackson-databind: this library provides implicit conversion between JSON and POJO classes, when this library is imported in pom.xml, you don’t have to worry about converting JSON requests into POJO or POJO responses into JSON, this is fully handled implicitly by this library. In case you’re interested in XML data type, then use jackson-xml-databind.
To learn more about Spring modules, check this out.
After adding the above dependencies, the following jars are automatically imported to your project under Maven Dependencies:
3. Implement REST resources
Now that we’re able to create our first REST application using Spring.
We’re going to implement a very basic payment API which charges customers for buying items.
Our API would only accept JSON requests and respond back with JSON responses, thanks to jackson library which allows us to deal with requests and responses as POJO classes without worrying about JSON/POJO conversions.
Following is the payment request class which should be submitted by clients on each payment request:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public class PaymentRequest { private int userId; private String itemId; private double discount; public String getItemId() { return itemId; } public void setItemId(String itemId) { this.itemId = itemId; } public double getDiscount() { return discount; } public void setDiscount(double discount) { this.discount = discount; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } } |
And this is the base response returned back from our service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.programmer.gate; public class BaseResponse { private String status; private Integer code; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } } |
The most important class in our API is the controller which acts as the interface for client/server communication, each controller acts as a resource which exposes some services and is accessed via specific url.
In our example, we define one resource called PaymentController which exposes the payment service to the customers.
Our controller looks like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package com.programmer.gate; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/payment") public class PaymentController { private final String sharedKey = "SHARED_KEY"; private static final String SUCCESS_STATUS = "success"; private static final String ERROR_STATUS = "error"; private static final int CODE_SUCCESS = 100; private static final int AUTH_FAILURE = 102; @RequestMapping(value = "/pay", method = RequestMethod.POST) public BaseResponse pay(@RequestParam(value = "key") String key, @RequestBody PaymentRequest request) { BaseResponse response = new BaseResponse(); if(sharedKey.equalsIgnoreCase(key)) { int userId = request.getUserId(); String itemId = request.getItemId(); double discount = request.getDiscount(); // Process the request // .... // Return success response to the client. response.setStatus(SUCCESS_STATUS); response.setCode(CODE_SUCCESS); } else { response.setStatus(ERROR_STATUS); response.setCode(AUTH_FAILURE); } return response; } } |
The only service exposed by our controller is the pay() method which looks very straightforward, it validates the client request using a predefined shared key, processes the request and respond back with the operation status.
Following are the common annotations used by our controller:
- @RestController: this annotation marks the class as a Resource, it defines implicitly both @Controller and @ResponseBody mvc annotations, when annotating a class with @RestController, it’s not necessary to write @ResponseBody beside the POJO classes returned from your methods.
- @RequestMapping: this annotation defines the url of the resource in addition to the method type: GET/POST, in our example we expose the payment service as POST which is accessed through /payment/pay.
- @RequestParam: this annotation represents a specific request parameter, in our example, we map a request parameter called key to an argument key of type String.
- @RequestBody: this annotation represents the body of the request, in our example, we map the body of the request to a POJO class of type PaymentRequest (jackson handles the JSON/POJO conversion)
As noticed the response is represented as BaseResponse and there is no need to annotate it, jackson converts it implicitly to JSON.
4. Configure REST API
After implementing our resource and defining the requests and responses of our API, now we need to configure the context url of our API and instruct our servlet container to load the resource on startup. Without this configuration section, your resources wouldn’t be exposed to clients.
Spring 4.3.0 supports several configuration annotations, there is no more need to define configurations in web.xml.
Basically we need to create 2 classes:
- ApplicationInitializer: this is an initializer class which is loaded at the startup of the application, it defines the configuration class of the application along with the context url.
- ApplicationConfiguration: this is the configuration class of the application, it is basically used to instruct the servlet container to load REST resources from specific package.
Here we go:
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.programmer.gate; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.programmer.gate") public class ApplicationConfiguration { } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.programmer.gate; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { ApplicationConfiguration.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/rest/*" }; } } |
In our example, we’re instructing the servlet container to load the resources from com.programmer.gate package, and we’re exposing our API through /rest url.
5. Deploy REST API
Now that our API is ready for deployment, so we deploy it on Tomcat 1.8/JRE8 (if you haven’t setup tomcat on eclipse then follow this guide).
In order to test our API, we use Advanced REST client plugin from chrome and we initiate 2 different requests:
Successful request: in this request we pass a valid shared key as a request parameter along with item details in the request body. This is how it looks like:
And this is our response:
1 2 3 4 | { "status": "success", "code": 100 } |
Failure request: this request looks similar to the above but with invalid shared key, this is what we get from our API:
1 2 3 4 | { "status": "error", "code": 102 } |
That’s it, hope you find it useful.
Thanks, and is a usefull piece of code.
Thank you, glad you like it
where is put, delete and other request type? please give me example of others
is very simple! thanks.
Thank you enrique
Hello
Thank you for this article …. but i have an HTTP 404 when I invoke the url http://localhost:8085/SpringRestService/rest/payment/pay?key=SHARED_KEY.
Could you please share the code source of this example (web.xml and pom.xml)
Best Regards
Hi Salah, In order to investigate the 404 issue: 1- Make sure that you define ApplicationConfiguration.java and ApplicationInitializer.java exactly as i defined them in the tutorial, double check the @ComponentScan(basePackages = “com.programmer.gate”) and make sure that you have implemented your resources under this package. (most probably is that your application is not able to scan your resources). Also double check getServletMappings() method inside ApplicationInitializer.java and make sure that you’ve set /rest/* prefix. 2- Make sure that you’re using the correct port of tomcat: 8085. i.e. you setup your tomcat at 8085. 2- The third thing to notice is that this… Read more »
Still 404. I did exactly as given, expect, i added all the classes and edited POM in the Simple Web project (given in the tutorial). I have corrected the url to SimpleWebProject/ . HelloWorld is working in the jsp but not the rest service.
port is correct as well. i use 8080
can you tell me jar name for this import org.springframework.web.bind.annotation.RestController
If you’re not using Maven, then search for spring-web jar
anyway .. i found it
can you share your web.xml
This tutorial doesn’t use web.xml, all the configuration is done via annotations as per the steps above.
hi, this no work, when i use the app google rest, the servre print this mensaje.
Mar 19, 2018 10:55:17 PM org.springframework.web.servlet.PageNotFound noHandlerFound
WARNING: No mapping found for HTTP request with URI [/SpringRestService/rest/payment/pay] in DispatcherServlet with name ‘dispatcher’
where is mapping of servlet
Eclipse oxygen, java 8, tomcat 8
Make sure that ApplicationConfiguration.java is scanning the correct package as per the example above. Regarding the servlet mapping it’s defined in getServletMappings() method of ApplicationInitializer.java.
If you still face the problem, please post your ApplicationConfiguration.java, ApplicationInitializer.java and PaymentController.java
hi,
Please post other topics also for rest web serice using spring. such as using other http methods and using log4j .
Hello husseinterek,
How can i configure timeout in service?
Thank you
Following the tutorial to setup the maven project and then this tutorial exactly, I am getting an unresolved type for the import org.springframework.context.annotation.Configuration and ComponentScan in the ApplicationConfiguration class. I see that the spring-context module is loaded from Maven and that it is added as a dependency just like the image you showed but still nothing. I am using Eclipse Photon so not sure if that could be problem but all others are resolved fine. Any ideas? Thanks!
Very useful. Thanks
Hi admin thank you so much for your valuable post its really a helpful post for all
web services i would like to share some opinion may be its also helpfull.
waiting and look forward to seeing your next post
hi…
could you share the structure of the project…thanks
how to do same thing in soap ui tool rather than rest client.please tell me that way i am using that only.thank you
This does not seem to work. I have followed and verified and only get 404. The index.jsp page loads so that verifies the port and context name used. One question I have is where in the process is ApplicationInitializer loaded. When starting in debug mode that class is never loaded as the code does not stop on any debug break
I had same problem. I noticed eclipse placed the java sources in src/main/resources instead of src/main/java. I manually created src/main/java and moved my sources there, clean and rebuild, and it resolved the issue.
not working, just 404 error, already check all, please share the project
Thanks!
Running of the Server in Eclipse is very hard and fragile process 🙂
For me help rightclick(on progect)->Maven->Update Progect
rightclick(on progect)->Run As->Maven clean
and the end reinstall Tomcat
Windows->Preferens->Server->RunTime Environments
Sir can you please share the complete folder structure of this project
it is a bit confusing to me
Help will be appreciated