+ All Categories
Home > Documents > RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation...

RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation...

Date post: 12-May-2020
Category:
Upload: others
View: 7 times
Download: 0 times
Share this document with a friend
59
1 RESTEasy Distributed peace of mind
Transcript
Page 1: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

1

RESTEasyDistributed peace of mind

Page 2: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

2

Agenda

Why REST? Writing RESTFul Web Services in Java

JAX-RS RESTEasy features RESTEasy Roadmap

Page 3: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

3

Speaker’s Qualifications

RESTEasy project lead

Fully certified JAX-RS implementation

JAX-RS JSR member

Also served on EE 5 and EJB 3.0 committees

JBoss contributor since 2001

Clustering, EJB, AOP

Published author

Books, articles

Page 4: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

4

What are the goals of SOA?

Page 5: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

5

SOA Goals

Reusable

Interoperable

Evolvable Versioning

Governable Standards Architectural Guidelines and Constraints Predictable

Scalable

Manageable

Page 6: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

6

What system has these properties?

Page 7: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

7

The Web!

Page 8: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

8

What is REST?

REpresentational State Transfer

PhD by Roy Fielding REST answers the questions of

Why is the Web so prevalent and ubiquitous? What makes the Web scale? How can I apply the architecture of the web to

my applications?

Page 9: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

9

What is REST?

It can mean a simple, “lightweight”, distributed interfaceover HTTP

REST is really a set of architectural principles Principles that make the Web unique

REST isn’t protocol specific But, usually REST == REST + HTTP

A different way to look at writing Web Services Many say it’s the anti-WS-*

Rediscovery of HTTP

Page 10: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

10

REST Architectural Principles

Addressable Resources Representation Oriented Constrained interface Hypermedia and Link Driven Communicate statelessly

Page 11: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

11

Why REST?

HTTP is everywhere “Lightweight” interoperability “Lightweight” stack Evolvability

Link driven systems allow you to redirect easily Content negotiation allows you to support old and new

formats

Page 12: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

12

JAX-RS

RESTFul Web Services in Java

Page 13: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

13

JAX-RS

JCP Specification

Required part of Java EE 6

Annotation Framework

Allows you to map HTTP requests to Java methodinvocations

Page 14: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

14

JAX-RS: GET /orders/3323

@Path(“/orders”)public class OrderResource {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Page 15: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

15

JAX-RS Annotations

@Path Defines URI mappings and templates

@Produces, @Consumes What MIME types does the resource produce and

consume @GET, @POST, @DELETE, @PUT, @HEAD

Identifies which HTTP method the Java method isinterested in

Page 16: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

16

JAX-RS Parameter Annotations @PathParam

Allows you to extract URI parameters/named URI templatesegments

@QueryParam

Access to specific parameter URI query string @HeaderParam

Access to a specific HTTP Header @CookieParam

Access to a specific cookie value

Page 17: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

17

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Base URI path to resource

JAX-RS: GET /orders/3323

Page 18: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

18

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @ProduceMime(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Additional URI patternthat getOrder() method maps to

JAX-RS: GET /orders/3323

Page 19: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

19

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Defines a URI path segment pattern

JAX-RS: GET /orders/3323

Page 20: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

20

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

HTTP method Java getOrder()maps to

JAX-RS: GET /orders/3323

Page 21: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

21

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Orer getOrder(@PathParam(“order-id”) int id) { … }}

What’s the CONTENT-TYPEreturned?

JAX-RS: GET /orders/3323

Page 22: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

22

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Inject value of URI segment intothe id Java parameter

JAX-RS: GET /orders/3323

Page 23: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

23

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Automatically convert URI stringsegment into an integer

JAX-RS: GET /orders/3323

Page 24: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

24

@Path(“/orders”)public class OrderService {

@Path(“/{order-id}”) @GET @Produces(“application/xml”) Order getOrder(@PathParam(“order-id”) int id) { … }}

Content handlers can convertfrom Java to Data Format

JAX-RS: GET /orders/3323

Page 25: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

25

JAX-RS: POST /orders

@Path(“/orders”)public class OrderService {

@POST @Consumes(“application/xml”) void submitOrder(Order orderXml) { … }}

What CONTENT-TYPE is thismethod expecting from client?

Page 26: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

26

@Path(“/orders”)public class OrderService {

@POST @Consumes(“application/xml”) void submitOrder(Order orderXml) { … }}

Un-annotated parametersassumed to be incoming message

body. There can be only one!

JAX-RS: POST /orders

Page 27: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

27

@Path(“/orders”)public class OrderService {

@POST @Consumes(“application/xml”) void submitOrder(Order orderXml) { … }}

Content handlers can convertfrom data format into Java object

JAX-RS: POST /orders

Page 28: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

28

More on Content Handlers

Media type, annotations, object type are all used to finda handler

@XmlElementpublic class Order {…}

@Path(“/orders”)public class OrderService {

@POST @Consumes(“application/xml”) void submitOrder(Order orderXml) { … }}

Page 29: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

29

More on Content Handlers

JAXB and other simple types required by specification JSON? Jackson project is a great provider Jettison can output/input JSON from JAXB annotations

A little buggy on JSON output Jackson is implementing JAXB support (try that)

Atom, multipart, XOP and other formats available You can write your own custom ones

Page 30: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

30

Response Object

JAX-RS has a Response and ResponseBuilder class Customize response code Specify specific response headers Specify redirect URLs Work with variants

@GETResponse getOrder() { ResponseBuilder builder = Response.status(200, order); builder.type(“text/xml”) .header(“custom-header”, “33333”); return builder.build();}

Page 31: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

31

JAX-RS Content Negotiation

Matched up and chosen based on request ACCEPT header

Accept: application/json;q=1.0,application/xml;q=0.5

@GET@Produces(“application/xml”)String getXmlOrder() {…}

@GET@Produces(“application/json”)String getJsonOrder() {…}

Page 32: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

32

ExceptionMappers

Map application thrown exceptions to a Response object

Implementations annotated by @Provider

public interface ExceptionMapper<E>{ Response toResponse(E exception);}

Page 33: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

33

JAX-RS Conclusions

Mapping HTTP requests using annotations A la carte HTTP information Nice content handlers Nice routing

Page 34: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

34

RESTEasy Features

Page 35: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

35

RESTEasy

Embeddable CDI, Spring, EJB, Guice, and Seam integration Client Framework Asynchronous HTTP (COMET) Asynchronous Jobs Client and Server Side Caching Interceptor model Automatic GZIP encoding support Data format support

Atom, JAXB, JSON, Multipart, XOP

Page 36: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

36

Embeddable

Very fast unit testing Web embed a fork of TJWS

Can run within IDE No special plugins

Page 37: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

37

Embeddable

public class SimpleTest extends BaseResourceTest {

@BeforeClass public static void setUp() throws Exception { addPerRequestResource(Resource.class); }

@Test public void testEcho() { String url = TestPortProvider.generateURL(“/my/resource”); … call the client }

}

Page 38: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

38

Client Framework

JAX-RS aware Layer over

Apache HttpClient 3.1 (very stable) Apache HttpClient 4.x (latest and greatest) java.net.URL (for use within GAE)

Proxy framework for ease of use Use JAX-RS annotations on the client side

Page 39: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

39

Client Framework

ClientRequest request = new ClientRequest(“http://…”);request.accept(“application/xml”);

ClientResponse<Customer> response = request.get(Customer.class);

Assert.assertEquals(200, response.getStatus());

Customer cust = response.getEntity();

Page 40: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

40

Client Proxy Framework

@Path(“/customers”)public interface CustomerService {

@GET @Path(“{id}) @Produces(“application/xml”) public Customer getCustomer( @PathParam(“id”) String id);}

CustomerService service = ProxyFactory(CustomerService.class, “http://example.com”);

Customer cust = service.getCustomer(“3322”);

Page 41: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

41

Client Javascript Framework

Special Javascript Servlet Scans a RESTEasy deployment Builds downloadable Javascript proxies

Page 42: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

42

Client Javascript Framework

@Path(“/customers”)public class Customers {

@GET @Path(“{id}) @Produces(“application/json”) public Customer getCustomer( @PathParam(“id”) String id) {…}}

var customer = Customers.getCustomer({id : “42”})

Page 43: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

43

Asynchronous HTTP (COMET)

“Pushing” events to the browser Really just blocking AJAX HTTP clients

Servlets generally thread/request 1000 blocking connections, 1000 threads

Async HTTP Detaching request thread from response Different thread can service response

1 thread can service multiple responses

Page 44: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

44

Asynchronous HTTP (COMET)

Different Async HTTP implementations Tomcat 6 JBossWeb Servlet 3.0

RESTEasy Async HTTP JAX-RS integration Synchronous façade (for use in non-async-http

platforms) Abstraction for different async implementations

Page 45: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

45

Async HTTP

@Path("/")public class MyResource { @GET public void get( final @Suspend(1000) AsynchronousResponse async) { Thread thread = new Thread() { public void run() { Response jaxrs = Response.ok("hello") .type(MediaType.TEXT_PLAIN) .build(); async.setResponse(jaxrs); } }; thread.start(); }}

Page 46: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

46

Job Framework

Page 47: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

47

HTTP and ACCEPTED

Server is allowed to send a 202, “Accepted” response Request was received but not processed yet

A design pattern Server sends 202 response code Server sends a Location header

Location header is an HTTP redirect Location header has a URI that will hold our response

Page 48: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

48

Job Framework

Any invocation can be made asynchronous uri?asynch=true - creates a job uri?oneway=true - fire and forget

Returns a Location that can be viewed and deleted GET and DELETE /jobs/{job-id}?wait={time}&nowait=true Returns 410, “Gone” if job doesn’t exist anymore Returns 202, Accepted if job exists but isn’t complete

Page 49: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

49

RESTEasy Caching

Page 50: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

50

Client Cache

Acts like a browser minus persistence In memory only

Does validation and conditional gets Sharable “Browser” cache instances Works with raw request or proxy framework

Page 51: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

51

Client Cache@Path(“/orders”)public interface OrderServiceProxy {

@GET @Produces(“application/xml”) @Path(“{id”} Order getOrder(@PathParam(“id”) int id);}

OrderServiceProxy proxy = ProxyFactory.create( “http://example.com”);BrowserCache cache =CacheFactory.makeCacheable(proxy);

// proxy instance now will cache responses and do// conditional GETs

Page 52: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

52

Server Cache

Local in-memory cache

Sits in front of JAX-RS service

Caches marshalled data

Auto generates Cache-Control headers

Generates ETag headers

Automatically handles conditional gets

Page 53: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

53

RESTEasy Roadmap

Page 54: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

54

RESTEasy Roadmap

Java EE 6 integration Automatic scanning Zero web.xml configuration Complete CDI and EJB integration JBoss AS6 Milestone 4

Page 55: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

55

RESTEasy Roadmap

Client Response mapping@ResponseMapping@ExpectedCodepublic class MyResponse {

@Body Customer getCustomer() {…}

@Header public String getEtag() {…}}

@Pathpublic interface MyProxy { @GET MyResponse getCustomer(@PathParameter(“id”) intid);}

Page 56: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

56

RESTEasy Roadmap

Client Response Exception mapping@ResponseMapping@ExpectedCode(400)public class ErrorException { …}

@Pathpublic interface MyProxy { @GET MyResponse getCustomer(@PathParameter(“id”) int id)throws ErrorException}

Page 57: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

57

RESTEasy Roadmap

REST + SOA + Security Oauth integration for running “on behalf of” Integration with Picketlink and Secure Token Service

Page 58: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

58

RESTEasy Roadmap

RESTEasy Middleware Interfaces REST-*.org HornetQ (close to release) Transactions (close to iteration) Workflow (prototype only) (See my jboss world talk)

Page 59: RESTEasy - JBoss · 2018-04-16 · RESTEasy project lead Fully certified JAX-RS implementation JAX-RS JSR member Also served on EE 5 and EJB 3.0 committees JBoss contributor since

59

References

Links

http://jsr311.dev.java.net/

http://jboss.org/resteasy

http://rest-star.org

O’Reilly Books

“RESTFul Java with JAX-RS” by me

“RESTful Web Services”

“RESTful Web Services Cookbook”


Recommended