-
Retrieve all Users - GET /users
-
Create a User - POST /users
-
Retrieve one User - GET /users/{id} -> /users/1
-
Delete a User - DELETE /users/{id} -> /users/1
-
Retrieve all posts for a User - GET /users/{id}/posts
-
Create a posts for a User - POST /users/{id}/posts
-
Retrieve details of a post - GET /users/{id}/posts/{post_id}
Resolved exception caused by Handler execution:
org.springframework.http.converter.HttpMessageNotWritableException:
No converter found for return value of type:
class com.in28minutes.rest.webservices.restfulwebservices.HelloWorldBean
- This happened because there were no getters in HelloWorldBean class
-
What is dispatcher servlet?
-
Who is configuring dispatcher servlet?
-
What does dispatcher servlet do?
-
How does the HelloWorldBean object get converted to JSON?
-
Who is configuring the error mapping?
-
Mapping servlet: 'dispatcherServlet' to [/]
-
Mapped "{[/hello-world],methods=[GET]}" onto public java.lang.String com.in28minutes.rest.webservices.restfulwebservices.HelloWorldController.helloWorld()
-
Mapped "{[/hello-world-bean],methods=[GET]}" onto public com.in28minutes.rest.webservices.restfulwebservices.HelloWorldBean com.in28minutes.rest.webservices.restfulwebservices.HelloWorldController.helloWorldBean()
-
Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
-
Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[
{
"id": 1,
"name": "Adam",
"birthDate": "2017-07-19T04:40:20.796+0000"
},
{
"id": 2,
"name": "Eve",
"birthDate": "2017-07-19T04:40:20.796+0000"
},
{
"id": 3,
"name": "Jack",
"birthDate": "2017-07-19T04:40:20.796+0000"
}
]
{
"id": 1,
"name": "Adam",
"birthDate": "2017-07-19T04:40:20.796+0000"
}
{
"name": "Ranga",
"birthDate": "2000-07-19T04:29:24.054+0000"
}
- Get request to a non existing resource.
- The response shows default error message structure auto configured by Spring Boot.
{
"timestamp": "2017-07-19T05:28:37.534+0000",
"status": 404,
"error": "Not Found",
"message": "id-500",
"path": "/users/500"
}
- Get request to a non existing resource.
- The response shows a Customized Message Structure
{
"timestamp": "2017-07-19T05:31:01.961+0000",
"message": "id-500",
"details": "Any details you would want to add"
}
POST http://localhost:8080/users with Validation Errors
{
"name": "R",
"birthDate": "2000-07-19T04:29:24.054+0000"
}
{
"timestamp": "2017-07-19T09:00:27.912+0000",
"message": "Validation Failed",
"details": "org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'user' on field 'name': rejected value [R]; codes [Size.user.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name],2147483647,2]; default message [Name should have atleast 2 characters]"
}
GET http://localhost:8080/users/1 with HATEOAS
{
"id": 1,
"name": "Adam",
"birthDate": "2017-07-19T09:26:18.337+0000",
"_links": {
"all-users": {
"href": "http://localhost:8080/users"
}
}
}
- LocaleResolver
- Default Locale - Locale.US
- ResourceBundleMessageSource
- Autowire MessageSource
- @RequestHeader(value = "Accept-Language", required = false) Locale locale
- messageSource.getMessage("helloWorld.message", null, locale)
- Accept application/xml
<List>
<item>
<id>2</id>
<name>Eve</name>
<birthDate>2017-07-19T10:25:20.450+0000</birthDate>
</item>
<item>
<id>3</id>
<name>Jack</name>
<birthDate>2017-07-19T10:25:20.450+0000</birthDate>
</item>
<item>
<id>4</id>
<name>Ranga</name>
<birthDate>2017-07-19T10:25:20.450+0000</birthDate>
</item>
</List>
- Accept : application/xml
- Content-Type : application/xml
Request
<item>
<name>Ranga</name>
<birthDate>2017-07-19T10:25:20.450+0000</birthDate>
</item>
Response
- Status - 201 Created
public static final Contact DEFAULT_CONTACT = new Contact(
"Ranga Karanam", "http://www.in28minutes.com", "[email protected]");
public static final ApiInfo DEFAULT_API_INFO = new ApiInfo(
"Awesome API Title", "Awesome API Description", "1.0",
"urn:tos", DEFAULT_CONTACT,
"Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0");
private static final Set<String> DEFAULT_PRODUCES_AND_CONSUMES =
new HashSet<String>(Arrays.asList("application/json",
"application/xml"));
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(DEFAULT_API_INFO)
.produces(DEFAULT_PRODUCES_AND_CONSUMES)
.consumes(DEFAULT_PRODUCES_AND_CONSUMES);
}
@GetMapping("/users/{id}")
@ApiOperation(value = "Finds Users by id",
notes = "Also returns a link to retrieve all users with rel - all-users")
public Resource<User> retrieveUser(@PathVariable int id) {
@ApiModel(value="User Details", description="Contains all details of a user")
public class User {
@Size(min=2, message="Name should have atleast 2 characters")
@ApiModelProperty(notes = "Name should have atleast 2 characters")
private String name;
@Past
@ApiModelProperty(notes = "Birth Date should be in the Past")
private Date birthDate;
@JsonIgnoreProperties(value={"field1"})
public class SomeBean {
private String field1;
@JsonIgnore
private String field2;
private String field3;
{
"field3": "value3"
}
- Media type versioning (a.k.a “content negotiation” or “accept header”)
- GitHub
- (Custom) headers versioning
- Microsoft
- URI Versioning
- Request Parameter versioning
- Amazon
- Factors
- URI Pollution
- Misuse of HTTP Headers
- Caching
- Can we execute the request on the browser?
- API Documentation
- No Perfect Solution
- https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown
- http://urthen.github.io/2013/05/09/ways-to-version-your-api/
- http://stackoverflow.com/questions/389169/best-practices-for-api-versioning
- http://www.lexicalscope.com/blog/2012/03/12/how-are-rest-apis-versioned/
- https://www.3scale.net/2016/06/api-versioning-methods-a-brief-reference/
create table user (
id integer not null,
birth_date timestamp,
name varchar(255),
primary key (id)
);
create table post (
id integer not null,
description varchar(255),
user_id integer,
primary key (id)
);
alter table post
add constraint post_to_user_foreign_key
foreign key (user_id) references user;