REST



REST

0 1


ninja-rest

Cours REST pour IUT

On Github Ninja-Squad / ninja-rest

REST

Cyril Lacôte

Ninja Squad

@clacote

REST

REpresentational State Transfer

2000 - Roy Fielding

REST c'est quoi?

  • C’est un style d’architecture
  • Ce n’est pas un standard
  • C’est une alternative à SOAP

REST utilise les standards existants

  • HTTP
  • URIs/URLs
  • XML, HTML, PNG, JSON...
  • application/xml, text/html, image/png, ... (types MIME)

Stateless

horizontal scalability

JSON or XML

But JSON is obviously THE FUTURE!
{
  "name": "Cyril Lacôte",
  "company": "Ninja Squad",
  "email": "cyril@ninja-squad.com",
  "twitter": "@clacote",
  "associations" : ["LyonJUG", "Mix-IT"]
}
					

Everybody familiar

with Json?

Respect du web

URI

http://server.com/users/clacote

HTTP verb

GETPOSTPUTDELETE
getAllUsersGET /users
getUserById(id)GET /users/{id}
createUserPOST /users
deleteUser(id)DELETE /users/{id}
updateUserPUT /users/{id}
searchUser(criteria)GET /users/search?name=Lac*&age=34

Code http

3 cas courants

OK, erreur client, erreur serveur

OK

Bad request

Internal Server Error

Created

Not Found

Reponse

HTTP status 403

{
	"code": "14",
	"developerMessage": "this user has not enough credentials to access admin repository",
	"more": "http://mywebsite.com/api/errors/14",
	"userMessage": "You can't access this repository",
}
					

Content type negociation

application/JSON

application/xml

HATEOAS

Hypermedia as the Engine

of Application State

Demo

github

Pragmatist

vs

RESTafarian

Api sub domain

http://api.github.com

Verbs are bad

Nouns are good

concrete nouns

lower case

plural (as in collections)

Attributs names

"created_at": Twitter, Github

"createdAt": Foursquare

Versioning

/v1/users

Pagination

/users?limit=120

/users?page=2&count=30

/users?fields=name,email

How to

with Spring MVC

A controller


@Controller
@RequestMapping("/spectacle")
public class SpectacleController {

  @Autowired
  private SpectacleService spectacleService;

  @RequestMapping(value="/{id}", method=RequestMethod.GET)
  public ModelAndView view(@PathVariable("id") Long id) {
    Spectacle spectacle = spectacleService.findById(id);
    ModelAndView result = new ModelAndView("spectacle");
    result.addObject("spectacle", spectacle);
    return result;
  }
}
					

Been there,

Done that.

So what about

JSON handling?

JSON needs

  • Check ACCEPT_TYPE header (if we're nice)
  • Read JSON input (if we need to)
  • Write JSON ouput.
You're lucky to use Spring MVC :

Add Jackson to your CLASSPATH

and... that's it!

<dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.12</version> </dependency>

Jackson?

A JSON marshaller. THE JSON marshaller.(other famous one: Gson)

Write Json?

Jackson API

ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(writer, javaObject);
					

Through Spring MVC:

@ResponseBody on return type If request accept "application/json"
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public @ResponseBody Spectacle view(@PathVariable("id") Long id) {
    Spectacle spectacle = spectacleService.findById(id);
    return spectacle;
}
					

One gotcha

Default Json mapping: all fields serialized.

Avoid cyclic references!

How to customize Json serialization?

Lot of ways (check documentation). Easiest: annotate your model classes.

  • @JsonIgnore to ignore attribute
  • @JsonProperty("otherName") to customize name
  • ... and many more.

Read Json?

Jackson API

ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class);
					

Through Spring MVC:

@RequestBody on action method parameter If request content-type "application/json"
@RequestMapping(value = "/", method = RequestMethod.POST)
public void Spectacle create(@RequestBody Spectacle spectacle) {
    spectacleService.createSpectacle(spectacle);
}
					

Handling errors?

and return dedicated HTTP error status?

  • Define your own exception class
  • @ExceptionHandler (in same controller class)
@ExceptionHandler(InvalidRequestException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody String whenInvalidRequest() {
    return "invalid data";
}
					

And now, for your coding pleasure

GET /api/spectacles/ : liste des spectacles
GET /api/spectacles/{id} : détail du spectacle d'identifiant {id}
POST /api/spectacles/ : créer un nouveau spectacle
  avec gestion d'erreurs (paramètre manquant -> erreur HTTP 400)