Professional Documents
Culture Documents
© luv2code LLC
You will learn how to …
• Create REST APIs / Web Services with Spring
• Not an A to Z reference … for that you can see Spring Reference Manual
https://projects.spring.io/spring-framework/
City
My Weather
Weather Service
App (external)
Weather Report
Java JavaScript
C# Go
Swift
PHP Ruby
Python
etc…
api.openweathermap.org/data/2.5/weather?q={city name}
OR
{
...
"temp": 14,
"temp_min": 11,
"temp_max": 17,
"humidity": 81,
"name": "London",
... Condensed
} version
Spring MVC
My Weather
Weather Service
C# App
(external)
My
Weather
iPhone App
Of course this
fluctuates based
on the market
Get customers
CRM
CRM App Service
(spring-rest)
Customer list
We will create
this code using
Spring REST
(SERVER)
REST
REST API REST Services
Web Services
RESTful
RESTful API RESTful Services
Web Services
REST
REST API REST Services
Web Services
RESTful
RESTful API RESTful Services
Web Services
© luv2code LLC
What is JSON?
• JavaScript Object Notation
• Lightweight data format for storing and exchanging data … plain text
JSON is just
• Language independent … not just for JavaScript plain text
data
• Can use with any programming language: Java, C#, Python etc …
• null
{
"id": 14,
Nested
"firstName": "Mario",
"lastName": "Rossi",
"active": true,
"address" : {
"street" : "100 Main St",
"city" : "Philadelphia",
"state" : "Pennsylvania",
"zip" : "19103",
"country" : "USA"
}
}
{ Array
"id": 14,
"firstName": "Mario",
"lastName": "Rossi",
"active": true,
"languages" : ["Java", "C#", "Python", "Javascript"]
}
© luv2code LLC
REST over HTTP
• Most common use of REST is over HTTP
HTTP Request
Client Message Server
My CRM
CRM REST
App Service
HTTP Response
Message
Message body
Header variables
Message body
• Examples
• text/html, text/plain
• application/json, application/xml, …
Free
developer
plan
www.getpostman.com
www.getpostman.com
© luv2code LLC
Spring REST Controller
© luv2code LLC
Spring REST Hello World We will write
this code
/test/hello
REST REST
Client Service
Hello World!
Web Browser
Or
Postman
www.luv2code.com © luv2code LLC
Spring REST Controller
Adds REST support
@RestController
@RequestMapping("/test")
public class DemoRestController {
Access the REST endpoint at
@GetMapping("/hello") /test/hello
public String sayHello() {
return "Hello World!";
}
} Returns content to
client
The response
The response
© luv2code LLC
Development Process Step-
By-S
tep
@RestController
@RequestMapping("/test")
public class DemoRestController {
© luv2code LLC
Java JSON Data Binding
• Data binding is the process of converting JSON data to a Java POJO
Java
JSON
POJO Also known as
Mapping
Marshalling / Unmarshalling
https://github.com/FasterXML/jackson-databind
{
"id": 14,
Java
"firstName": "Mario",
POJO
"lastName": "Rossi",
}
"active": true
Student
{ Call
"id": 14,
setXXX Java
methods
"firstName": "Mario",
POJO
"lastName": "Rossi",
}
"active": true
Jackson will do
Student
this work
// getter methods
}
{
"id": 14,
Java
"firstName": "Mario",
POJO
"lastName": "Rossi",
Call
getXXX
}
"active": true methods Student
Jackson will do
this work
© luv2code LLC
Create a New Service
/api/students
REST REST
Client Service
Web Browser
Or
Postman
Java
POJO
Student
{
"id": 14,
Java
"firstName": "Mario",
POJO
"lastName": "Rossi",
}
"active": true
Student
Jackson will do
this work
/api/students
REST REST
Client Service
…
List<Student>
Jackson will
convert to
JSON array
www.luv2code.com © luv2code LLC
Behind the scenes We will write
this code
REST /api/students
REST
Spring
Client REST
Jackson
Service
…
We will return
Jackson will convert List<Student>
List<Student> to
JSON array
@RestController
@RequestMapping("/api")
public class StudentRestController {
© luv2code LLC
Path Variables
• Retrieve a single student by id
/api/students/0 Known as a
/api/students/1 "path variable"
/api/students/2
/api/students/{studentId}
REST REST
Client Service
{
"firstName": "Mario",
"lastName": "Rossi"
} Student
Jackson will
convert to
JSON
www.luv2code.com © luv2code LLC
Behind the scenes We will write
this code
REST /api/students/{studentId}
REST
Spring
Client REST
Jackson
Service
{
"firstName": "Mario",
"lastName": "Rossi"
}
We will return
Jackson will convert Student
Student to
JSON
@RestController
@RequestMapping("/api")
public class StudentRestController {
@GetMapping("/students/{studentId}")
public Student getStudent(@PathVariable int studentId) {
© luv2code LLC
Remember our problem?
• Bad student id of 9999 …
Bad data
REST REST
Client Service
Exception
Handler
// constructors
// getters / setters
}
Call super class
constructor
@RestController
@RequestMapping("/api")
public class StudentRestController { Could also
@GetMapping("/students/{studentId}") check results
public Student getStudent(@PathVariable int studentId) {
from DB
// check the studentId against list size
return theStudents.get(studentId);
}
Throw exception
…
}
Happy path
Bad data
Throw exception
/api/students/9999
REST REST
Client Service
Exception
Handler
@ExceptionHandler
public ResponseEntity<StudentErrorResponse> handleException(StudentNotFoundException exc) {
error.setStatus(HttpStatus.NOT_FOUND.value());
error.setMessage(exc.getMessage());
error.setTimeStamp(System.currentTimeMillis());
Bad data
Throw exception
/api/students/9999
REST REST
Client Service
Exception
Handler
© luv2code LLC
Spring REST Exception Handling
Bad data
Throw exception
/api/students/9999
REST REST
Client Service
Exception
Handler
Large projects
• Can't be reused by other controllers :-( will have
multiple controllers
• Promotes reuse
Throw exception
/api/students/9999
...
...
@ControllerAdvice
public class StudentRestExceptionHandler {
@RestController
Remove
@RequestMapping("/api")
public class StudentRestController {
this code
…
@ExceptionHandler
public ResponseEntity<StudentErrorResponse> handleException(StudentNotFoundException exc) {
error.setStatus(HttpStatus.NOT_FOUND.value());
error.setMessage(exc.getMessage());
error.setTimeStamp(System.currentTimeMillis());
@ExceptionHandler
public ResponseEntity<StudentErrorResponse> handleException(StudentNotFoundException exc) {
error.setStatus(HttpStatus.NOT_FOUND.value());
error.setMessage(exc.getMessage());
error.setTimeStamp(System.currentTimeMillis());
Throw exception
/api/students/9999
...
...
© luv2code LLC
REST API Design
• For real-time projects, who will use your API?
/api/employees
Full
CRUD
Employee
Service
(spring-rest)
/api/employeesList
/api/deleteEmployee
/api/addEmployee
/api/updateEmployee Instead, use
HTTP methods
to assign actions
Don't include actions in the endpoint
Employee
Service
(spring-rest)
• PayPal
• GitHub
• SalesForce
Create an individual
POST /services/apexrest/clinic01/v1/individual/
Update an individual
PUT /services/apexrest/clinic01/v1/individual/
© luv2code LLC
Real-Time Project
REST API
with
Spring Boot
Employee
Employee Employee
REST
Service DAO
Controller
© luv2code LLC
employee.sql
1. File: employee.sql
© luv2code LLC
Development Process Step-
By-S
tep
© luv2code LLC
Application Architecture
Employee
Employee Employee
REST
Service DAO
Controller
Current task
List<Employee> findAll();
@Repository
public class EmployeeDAOJpaImpl implements EmployeeDAO {
@Autowired
public EmployeeDAOJpaImpl(EntityManager theEntityManager) {
entityManager = theEntityManager;
}
…
}
Automatically created Constructor
by Spring Boot injection
@Override
public List<Employee> findAll() {
// create a query
TypedQuery<Employee> theQuery =
entityManager.createQuery("from Employee", Employee.class);
© luv2code LLC
Refactor: Add a Service Layer
Employee
Employee Employee
Rest
Service DAO
Controller
Employee
Employee Employee
Rest
Service DAO
Controller
Employee
DAO
Employee
Employee
Rest
Service
Controller Skills
DAO
Payroll
DAO
Employee
Employee Employee
Rest
Service DAO
Controller
@Component
Employee
Employee Employee
Rest
Service DAO
Controller
List<Employee> findAll();
// inject EmployeeDAO …
@Override
public List<Employee> findAll() {
return employeeDAO.findAll();
}
}
© luv2code LLC
Service Layer - Best Practice
✤ Best practice is to apply transactional boundaries at the service layer
✤ It is the service layer’s responsibility to manage transaction boundaries
✤ For implementation code
✤ Apply @Transactional on service methods
✤ Remove @Transactional on DAO methods if they already exist
@Override
public Employee findById(int theId) {
// get employee
Employee theEmployee = entityManager.find(Employee.class, theId);
// return employee
return theEmployee;
}
// return dbEmployee
return dbEmployee;
}
Return dbEmployee
It has updated id from the database
(in the case of insert)
@Override
public void deleteById(int theId) {
© luv2code LLC
Development Process Step-
By-S
tep
© luv2code LLC
Development Process Step-
By-S
tep
© luv2code LLC
Development Process Step-
By-S
tep
GET /api/employees/{employeeId}
Employee
REST
REST
Client
Controller
Employee
REST
REST
Client
Controller
Response contains
new id / primary key
• For controller to process JSON data, need to set a HTTP request header
• Content-type: application/json
• Need to configure REST client to send the correct HTTP request header
© luv2code LLC
Development Process Step-
By-S
tep
Employee
REST
REST
Client
Controller
Response contains
updated info (echoed)
DELETE /api/employees/{employeeId}
Employee
REST
REST
Client
Controller
Deleted employee id - {employeeId}
© luv2code LLC
Application Architecture
Employee
Employee Employee
REST
Service DAO
Controller
Spring Data
JPAJPA
// get data
Employee theData = entityManager.find(Employee.class, theId);
// return data
return theData;
}
Primary key
Only difference is the Entity type
entity type and primary key
Entity:
Entity: Employee
Customer
Product Primary key: Integer
• Create a DAO and just plug in your entity type and primary key
• Spring will give you a CRUD implementation for FREE …. like MAGIC!!
findAll()
findById(…)
save(…)
deleteById(…)
… others …
No need for
implementation class
www.luv2code.com/jpa-repository-javadoc
@Autowired
public EmployeeServiceImpl(EmployeeRepository theEmployeeRepository) {
employeeRepository = theEmployeeRepository;
}
@Override
public List<Employee> findAll() {
return employeeRepository.findAll();
}
…
Magic method that is
} available via repository
1 File
3 lines of code!
2 Files
30+ lines of code
No need for
implementation class
www.luv2code.com/spring-data-jpa-defining-custom-queries
© luv2code LLC
Spring Data JPA
• Earlier, we saw the magic of Spring Data JPA
Give me all of the basic REST API CRUD features for free
• Spring will give you a REST CRUD implementation for FREE …. like
MAGIC!!
• Expose REST APIs for each entity type for your JpaRepository
}
/employees
That's it!!!
That's it!!!
After
3 files
100+ lines of code
https://spring.io/understanding/HATEOAS
Response
{
"firstName": "Avani", Employee data
"lastName": "Gupta",
"email": "avani@luv2code.com",
"_links": {
"self": {
"href": "http://localhost:8080/employees/3"
}, Response meta-data
"employee": {
"href": "http://localhost:8080/employees/3" Links to data
}
}
}
https://spring.io/understanding/HATEOAS
https://en.wikipedia.org/wiki/Hypertext_Application_Language
https://spring.io/projects/spring-data-rest
© luv2code LLC
REST Endpoints
• By default, Spring Data REST will create endpoints based on entity type
}
/employees
@RepositoryRestResource(path="members")
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
http://localhost:8080/members
• Page size = 20
• You can navigate to the different pages of data using query param
http://localhost:8080/employees?page=0
Pages are
http://localhost:8080/employees?page=1 zero-based
Name Description
spring.data.rest.base-path Base path used to expose repository resources
spring.data.rest.default-page-size Default size of pages
spring.data.rest.max-page-size Maximum size of pages
… …
http://localhost:8080/magic-api/employees
File: application.properties
spring.data.rest.base-path=/magic-api
spring.data.rest.default-page-size=50
Returns 50
elements per page