Rest API
Pages 92
12/01/2014 The 3.0.1 release is out !
Using AndroidAnnotations
- Get started!
- Download
- Cookbook, full of recipes
- Customize annotation processing
- List of all available annotations
- Release Notes
- Examples
Questions?
- Read the FAQ
- Join the Mailing list
- Create an issue
- Tag on Stack Overflow
Enjoying AndroidAnnotations
Improving AndroidAnnotations
Since AndroidAnnotations 2.2
Introduction
The REST API allows you to quickly write REST clients using clean interfaces.
It is a wrapper around the great Spring Android RestTemplate Module. As such, if you want to use the REST API, you should make sure that your application has the right Jars or Maven dependencies set.
You should also read the Spring Android RestTemplate Module Documentation, to know more about entity serialization / deserialization and how the RestTemplate works.
Create your REST API interface
The Rest API works with a @Rest
annotated interface. It's the entry point.
Converters
You MUST define converters
field on this @Rest
annotation, which corresponds to the SpringHttpMessageConverter
s that will be provided to the RestTemplate
.
@Rest(converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events")
EventList getEvents();
}
Important note: Keep in mind that HttpMessageConverter
s are provided by Spring Android RestTemplate, but it DOESN'T contains the implementation of the converter. For example :MappingJacksonHttpMessageConverter
is using Jackson as converter but you still have to add this library in the classpath of you project.
Root url
You will usually define a ROOT_URL in a @Rest
annotation,
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events")
EventList getEvents();
}
but you can omit the ROOT_URL and define a complete URL on each method.
@Rest(converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("http://company.com/ajax/services/events")
EventList getEvents();
}
Interceptors
Since AndroidAnnotations 3.0
It may be useful to add an interceptor to your Rest client. You can do that with the interceptors
field in @Rest
annotation.
@Rest(converters = { MappingJacksonHttpMessageConverter.class }, interceptors = { HttpBasicAuthenticatorInterceptor.class })
public interface MyRestClient {
@Get("/events")
EventList getEvents();
}
public class HttpBasicAuthenticatorInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] data, ClientHttpRequestExecution execution) throws IOException {
// do something
//在此添加header,例如编码,以解决中文乱码
return execution.execute(request, data);
}
}
For example, this can be used to log each request or to handle custom authentication.
Before AndroidAnnotations 3.0
Before this version you can manualy add interceptors into RestTemplate instance by adding agetRestTemplate
method in your interface. More information about this on this page.
Error handler
Since AndroidAnnotations 3.0
By default, if an api call fails for any reason, an exception is thrown. Managing general exceptions like service unavailable
or bad request
for every call can be really tedious. Not doing it would make your app crash for all unexpected error. It's a good practice to override the default behavior, and this is done using a RestErrorHandler
.
Implement your RestErrorHandler (it doesn't have to be an @EBean
).
import org.androidannotations.api.rest.RestErrorHandler;
@EBean
public class MyErrorHandler implements RestErrorHandler {
@Override
public void onRestClientExceptionThrown(RestClientException e) {
// Do whatever you want here.
}
}
Make sure your rest client interface extends RestClientErrorHandling
.
@Rest
public interface MyRestClient extends RestClientErrorHandling {
...
}
Then set the error handler where you use your rest client.
@RestService
MyRestClient myRestClient;
@Bean
MyErrorHandler myErrorHandler;
@AfterInject
void afterInject() {
myRestClient.setRestErrorHandler(myErrorHandler);
}
Add REST API methods
Notes
Let's clarify some points before starting with REST API methods.
Placeholders
For each type of REST call you can add URL parameters by writing the parameter names in brackets and you MUST define them all as parameters of your method.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
// OK
@Get("/events/{year}/{location}")
EventList getEventsByYearAndLocation(int year, String location);
// OK
@Get("/events/{year}/{location}")
EventList getEventsByLocationAndYear(String location, int year);
// WRONG
@Get("/events/{year}/{location}")
EventList getEventsByLocation(String location); // Wrong, "year" must be defined.
}
Parameterized class
Since AndroidAnnotations 3.0
You can now return parameterized class (such as List<Event>
) in your REST API methods.
Before AndroidAnnotations 3.0
Before this version you can't directly return a parameterized class but you can use a class extending of it.
@Get("/events/{year}/{location}")
EventList getEvents(String location, int year);
With
public class EventList extends List<Event> {
}
ResponseEntity
You can also return a ResponseEntity
parameterized by the expected result type, which gives you access to to the response context. For instance, it could be useful to check the HTTP headers of the response.
@Get("/events/{year}/{location}")
ResponseEntity<Event> getEvents(String location, int year);
@Get
Send a request with GET HTTP Method. The example shows the different possible return types.
Your method can return nothing,
@Get("/events/{id}")
void getEvent(long id);
or a class representing the object contained in the HTTP response. The binding from JSON/XML to Object is automatically done by the RestTemplate according the defined converters, please check the related documentation.
@Get("/events/{id}")
Event getEvent(long id);
@Post
Send a request with POST HTTP method.
The POST HTTP method is used to add objects to a REST resource. You only need to add a parameter representing the object to your annotated method. The allowed return types are the same as @Get
.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Post("/events")
void addEvent(Event event);
@Post("/events/{id}")
void addEventById(Event event, long id);
@Post("/events")
Event addAndReturnEvent(Event event);
@Post("/events")
ResponseEntity<Event> addAndReturnResponseEntity(Event event);
}
Of course, you can send a POST request without sending any entity.
@Post("/events")
void addEvent();
@Put
Send a PUT HTTP Method request. The allowed return types are the same as @Get
.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Put("/events")
void updateEvent(Event event);
@Put("/events/{id}")
Event updateEventById(Event event, long id);
@Put("/events")
void updateEventNoEntity();
@Put("/events/{id}")
void updateEventNoEntityById(long id);
}
@Delete
Send a DELETE HTTP Method request. Quite similar to the @Put annotation. The allowed return types are the same as @Get
.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Delete("/events")
void deleteEvents();
@Delete("/events/{id}")
Event deleteEventById(long id);
@Delete("/events/{id}")
void deleteEventWithEntityById(Event event, long id);
}
@Options
Send a OPTIONS HTTP Method request. @Options
annotated methods must return a set ofHttpMethod
.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Options("/events")
Set<HttpMethod> getEventOptions();
@Options("/events/{year}/{location}")
Set<HttpMethod> getEventOptions(String location, int year);
}
@Head
Send a HEAD HTTP Method request. @Head
annotated methods must return HttpHeaders
.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Head("/events")
HttpHeaders getEventHeader();
@Head("/events/{year}/{location}")
HttpHeaders getEventHeader2(String location, int year);
}
Configure your REST API methods
On each method you're able to add some interfaces to customize HTTP calls.
@Accept
You can negotiate the response format expected by your REST client (JSON, XML, TEXT, HTML...).
@Accept
can only be used on @Get
and @Post
methods.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events/{id}")
@Accept(MediaType.APPLICATION_JSON)
Event getEvent(long id);
@Post("/entity")
@Accept(MediaType.APPLICATION_XML)
Event addEvent(Event event);
}
You can directly annotate the @Rest
interface but only @Get
and @Post
will use it.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
@Accept(MediaType.APPLICATION_XML)
public interface MyService {
}
Since AndroidAnnotations 2.7
@Accept
accepts any String, so you can use custom formats e.g. @Accept("foo/bar")
.
@RequiresHeader / setHeader / getHeader
Since AndroidAnnotations 3.0
Inject a header in the request based on the given key.
To set the header's value you have to create a void setHeader(String name, String value)
method in your REST API interface. It will be automaticaly handle and implemented by AA.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events/{id}")
@RequiresHeader("myHeader")
Event getEvent(long id);
void setHeader(String name, String value);
String getHeader(String name);
}
In this example your code should call setHeader("myHeader", "My Value")
before callinggetEvent(…)
. AA will is also handle String getHeader(String name)
method to let you retrieve a specific header's value.
@RequiresCookie / setCookie / getCookie
Since AndroidAnnotations 3.0
Inject a cookie in the request based on the given key.
To set the cookie's value you have to create a void setCookie(String name, String value)
method in your REST API interface. It will be automaticaly handle and implemented by AA.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events/{id}")
@RequiresCookie("session")
Event getEvent(long id);
void setCookie(String name, String value);
String getCookie(String name);
}
In this example your code should call setCookie("session", "MyUID")
before calling getEvent(…)
. AA will is also handle String getCookie(String name)
method to let you retrieve a specific cookie's value.
@RequiresCookieInUrl
Since AndroidAnnotations 3.0
Works exactly as @RequiresCookie
but it will inject the cookie in the url instead of in headers. It could be helpful in some cases.
@RequiresAuthentication / setAuthentication / setHttpBasicAuth
Since AndroidAnnotations 3.0
Use the previously configured org.springframework.http.HttpAuthentication
to inject authentication value in the Authorization
request header.
To set the authentication object you have to create void setAuthentication(HttpAuthentication auth)
and/or setHttpBasicAuth(String username, String password)
methods in your REST API interface. The former is a generic method and the latter is just a shortcut forsetAuthentication(new HttpBasicAuthentication(username, password))
. It will be automaticaly handle and implemented by AA.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events/{id}")
@RequiresAuthentication
Event getEvent(long id);
setHttpBasicAuth(String username, String password);
}
In this example your code should call setHttpBasicAuth("username", "pass")
before callinggetEvent(...)
@SetsCookie
Since AndroidAnnotations 3.0
This annotation is used to retrieve and store cookies from the HTTP response. After being set, the can be retrieve by @RequiresCookie
and @RequiresCookieInUrl
annotation and getCookie
method.
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events/{id}")
@SetsCookie({"xt"})
Event getEvent(long id);
}
Customize your REST API interface
AndroidAnnotation @Rest
will automaticaly detect and handle some methods in your @Rest
annotated interface. Some of them has already been described earlier and works with an annotation. Here are some other methods.
RootUrl
Since AndroidAnnotations 2.6
If you need to dynamicaly set ROOT_URL values, you can add a void setRootUrl(String rootUrl)
method to the interface.
@Rest(converters = { MappingJacksonHttpMessageConverter.class })
public interface MyRestClient {
@Get("/events")
EventList getEvents();
void setRootUrl(String rootUrl);
}
This can be useful if you need to create builds for different environments.
Since AndroidAnnotations 3.0
You can also retrieve the current ROOT_URL value by adding a String getRootUrl()
method to the interface.
RestTemplate
The generated implementation of your annotated interface uses Spring Android RestTemplate. If you want to configure the RestTemplate to some specific needs, you can addgetRestTemplate()
and setRestTemplate()
methods:
@Rest("http://company.com/ajax/services")
public interface MyService {
RestTemplate getRestTemplate();
void setRestTemplate(RestTemplate restTemplate);
}
Uses "bundle" interfaces
Since AndroidAnnotations 3.0
AndroidAnnotation provide some interfaces your REST API interface can extends of. Each of them provide handled methods and let you clean your code by using extends composition instead of writing methods.
@Rest("http://company.com/ajax/services")
public interface MyService extends RestClientRootUrl, RestClientSupport {
…
}
RestClientRootUrl
Provide getRootUrl
and setRootUrl
methods. See above for more information.
RestClientSupport
Provide getRestTemplate
and setRestTemplate
methods. See above for more information.
RestClientHeaders
Provide setHeader
, getHeader
, getHeader
, setHeader
, setAuthentication
and setHttpBasicAuth
methods. See above for more information.
Using your REST client
Once your REST interface has been created you can inject it in any @Exxx
annotated class with@RestService
annotation.
@EActivity
public class MyActivity extends Activity {
@RestService
MyRestClient myRestClient; //Inject it
@AfterViews
void afterViews() {
myRestClient.getEvents("fr", 2011); //Play with it
}
}
Handling errors
Spring Rest Template throws runtime exceptions when there's an error. Checked exceptions would add unwanted boilerplate code to every interface/implementation of REST clients.
If you want to handle HTTP errors from outside of your interface (to show error dialogs or to retry, for example), you can catch the RestClientException
. (See documentation)
try {
myRestClient.getEvents("fr", 2011);
} catch (RestClientException e) {
// handle error for Rest client exceptions
}
If you just want to log the error for every calls you can just add an interceptor to @Rest
(See above).
A Full REST API example
@Rest(rootUrl = "http://company.com/ajax/services", converters = { MappingJacksonHttpMessageConverter.class })
// if defined, the url will be added as a prefix to every request
public interface MyService extends RestClientHeaders {
// url variables are mapped to method parameter names.
@Get("/events/{year}/{location}")
@Accept(MediaType.APPLICATION_JSON)
EventList getEvents(String location, int year);
// The response can be a ResponseEntity<T>
@Get("/events/{year}/{location}")
/*
* You may (or may not) declare throwing RestClientException (as a reminder,
* since it's a RuntimeException), but nothing else.
*/
ResponseEntity<EventList> getEvents2(String location, int year) throws RestClientException;
// There should be max 1 parameter that is not mapped to an attribute. This
// parameter will be used as the post entity.
@Post("/events/")
@Accept(MediaType.APPLICATION_JSON)
Event addEvent(Event event);
@Post("/events/{year}/")
Event addEvent(Event event, int year);
@Post("/events/")
ResponseEntity<Event> addEvent2(Event event);
@Post("/events/{year}/")
@Accept(MediaType.APPLICATION_JSON)
ResponseEntity<Event> addEvent2(Event event, int year);
@Put("/events/{id}")
void updateEvent(Event event, int id);
// url variables are mapped to method parameter names.
@Delete("/events/{id}")
@RequiresAuthentication
void removeEvent(long id);
@Head("/events/{year}/{location}")
HttpHeaders getEventHeaders(String location, int year);
@Options("/events/{year}/{location}")
Set<HttpMethod> getEventOptions(String location, int year);
// if you need to add some configuration to the Spring RestTemplate.
RestTemplate getRestTemplate();
void setRestTemplate(RestTemplate restTemplate);
}
AndroidAnnotations was created by Pierre-Yves Ricau and is sponsored by eBusinessInformations.