Top Banner
Building a Killer REST Client for Your REST+JSON API Les Hazlewood @lhazlewood Apache Shiro Project Chair CTO, Stormpath stormpath.com
59

Build A Killer Client For Your REST+JSON API

Aug 27, 2014

Download

Software

Stormpath

REST+JSON APIs are great - but you still need to communicate with them from your code. Wouldn't you prefer to interact with clean and intuitive Java objects instead of messing with HTTP requests, HTTP status codes and JSON parsing? Wouldn't you prefer to work with type-safe objects specific to your API?

In this presentation, Les Hazlewood - Stormpath CTO and Apache Shiro PMC Chair - will share all of the golden nuggets learned while designing, implementing and supporting multiple clients purpose-built for a real-world REST+JSON API.

Further reading: http://www.stormpath.com/blog

Stormpath is a user management and authentication service for developers. By offloading user management and authentication to Stormpath, developers can bring applications to market faster, reduce development costs, and protect their users. Easy and secure, the flexible cloud service can manage millions of users with a scalable pricing model.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Build A Killer Client For Your REST+JSON API

Building a Killer REST Clientfor Your REST+JSON API

Les Hazlewood @lhazlewoodApache Shiro Project Chair

CTO, Stormpath stormpath.com

Page 2: Build A Killer Client For Your REST+JSON API

.com• User Management and Authentication

API• Security for your applications• User security workflows• Security best practices• Developer tools, SDKs, libraries

Page 3: Build A Killer Client For Your REST+JSON API

Overview• Resources• Public / Private API• Proxy Design• Active Record• Fluent API• Configuration• Caching• Authentication• Pluggability• Lessons Learned

Page 4: Build A Killer Client For Your REST+JSON API

HATEOAS

• Hypermedia

• As

• The

• Engine

• Of

• Application

• State

Learn more at Stormpath.com

Page 5: Build A Killer Client For Your REST+JSON API

Resources

Learn more at Stormpath.com

Page 6: Build A Killer Client For Your REST+JSON API

Resources

• Nouns, not verbs• Coarse-grained, not fine-grained• Support many use cases• Globally unique HREF

Learn more at Stormpath.com

Page 7: Build A Killer Client For Your REST+JSON API

Collection Resource

• Example: /applications

• First class resource w/ own properties:• offset• limit• items• first, next, previous, last• etc

• items contains instance resources

Learn more at Stormpath.com

Page 8: Build A Killer Client For Your REST+JSON API

Instance Resource

• Example:/applications/8sZxUoExA30mP74

• Child of a collection• RUD (no Create - done via parent collection)

Learn more at Stormpath.com

Page 9: Build A Killer Client For Your REST+JSON API

Translating to Code

Learn more at Stormpath.com

Page 10: Build A Killer Client For Your REST+JSON API

Resource

public interface Resource { String getHref();}

Learn more at Stormpath.com

Page 11: Build A Killer Client For Your REST+JSON API

Instance Resourcepublic interface Application extends Resource, Saveable, Deleteable { ...}

public interface Saveable { void save();}

public interface Deletable { void delete();}

Learn more at Stormpath.com

Page 12: Build A Killer Client For Your REST+JSON API

Collection Resourcepublic interface CollectionResource<T extends Resource> extends Resource, Iterable<T> {

int getOffset();

int getLimit();

}

Learn more at Stormpath.com

Page 13: Build A Killer Client For Your REST+JSON API

Example: ApplicationListpublic interface ApplicationList extends CollectionResource<Application> { }

Learn more at Stormpath.com

Page 14: Build A Killer Client For Your REST+JSON API

Design!

Learn more at Stormpath.com

Page 15: Build A Killer Client For Your REST+JSON API

Encapsulation

• Public API• Internal/Private Implementations• Extensions

• Allows for change w/ minimal impacthttp://semver.org

Learn more at Stormpath.com

Page 16: Build A Killer Client For Your REST+JSON API

Encapsulation in practiceproject-root/|- api/| |- src/main/java||- impl/| |- src/main/java||- extendsions/| |- src/main/java||- pom.xml

Learn more at Stormpath.com

Page 17: Build A Killer Client For Your REST+JSON API

Public API

Learn more at Stormpath.com

Page 18: Build A Killer Client For Your REST+JSON API

Public API

• All interfaces• Helper classes with static methods• Builder interfaces for configuration

• NO IMPLEMENTATIONS EXPOSED

Learn more at Stormpath.com

Page 19: Build A Killer Client For Your REST+JSON API

Example interfaces

• Client• ClientBuilder• Application• Directory• Account• Group• etc

Learn more at Stormpath.com

Page 20: Build A Killer Client For Your REST+JSON API

Classes with static helper methodsClient client = Clients.builder() ... .build();

• Create multiple helper classesseparation of concerns

Learn more at Stormpath.com

Page 21: Build A Killer Client For Your REST+JSON API

Builder interfaces for configuration

Client client = Clients.builder().setApiKey( ApiKeys.builder().setFileLocation( “$HOME/.stormpath/apiKey.properties”) .build()) .build();

Clients.builder() ClientBuilderApiKeys.builder() ApiKeyBuilder

Single Responsibility Principle!

Learn more at Stormpath.com

Page 22: Build A Killer Client For Your REST+JSON API

Private API

• Implementations + SPI interfaces• Builder implementations• Implementation Plugins

Learn more at Stormpath.com

Page 23: Build A Killer Client For Your REST+JSON API

Resource Implementations• Create a base AbstractResource class:• Map manipulation methods• Dirty checking• Reference to DataStore• Lazy Loading• Locks for concurrent access

• Create abstract InstanceResource and CollectionResource implementations

• Extend from InstanceResource or CollectionResource

Learn more at Stormpath.com

Page 24: Build A Killer Client For Your REST+JSON API

Resource Implementationspublic class DefaultAccount extends InstanceResource implements Account {

@Override public String getName() { return (String)getProperty(“name”); }

@Override public Account setName(String name) { setProperty(“name”, name); return this; }}

Learn more at Stormpath.com

Page 25: Build A Killer Client For Your REST+JSON API

Usage Paradigm

Learn more at Stormpath.com

Page 26: Build A Killer Client For Your REST+JSON API

Account JSON Resource{ “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “href”: “https://api.stormpath.com/v1/directories/g4h5i6” }}

Learn more at Stormpath.com

Page 27: Build A Killer Client For Your REST+JSON API

Naïve Design (typesafe language)//get accountString href = “https://api.stormpath.com/v1/....”;Map<String,Object> account = client.getResource(href);

//get account’s parent directory via link:Map<String,Object> dirLink = account.getDirectory();String dirHref = (String)dirLink.get(“href”);

Map<String,Object> directory = client.getResource(dirHref);System.out.println(directory.get(“name”));

Learn more at Stormpath.com

Page 28: Build A Killer Client For Your REST+JSON API

Naïve Design (typesafe language)

• Results in *huge* amount of Boilerplate code• Not good• Find another way

Learn more at Stormpath.com

Page 29: Build A Killer Client For Your REST+JSON API

Proxy PatternString href = “https://api.stormpath.com/v1/....”;Account account = client.getAccount(href);

Directory directory = account.getDirectory();

System.out.println(directory.getName());

Learn more at Stormpath.com

Page 30: Build A Killer Client For Your REST+JSON API

Proxy Pattern

Learn more at Stormpath.com

Page 31: Build A Killer Client For Your REST+JSON API

Component Design

Learn more at Stormpath.com

Page 32: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

Learn more at Stormpath.com

Page 33: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

DataStore

Learn more at Stormpath.com

Page 34: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

MapMarshaller JSON <--> Map

DataStore

Learn more at Stormpath.com

Page 35: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

ResourceFactory Map Resource

MapMarshaller JSON <--> Map

DataStore

Learn more at Stormpath.com

Page 36: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

ResourceFactory Map Resource

MapMarshaller JSON <--> Map

CacheManager

DataStore

Learn more at Stormpath.com

Page 37: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

RequestExecutor

ResourceFactory Map Resource

MapMarshaller JSON <--> Map

CacheManager

DataStore

Learn more at Stormpath.com

Page 38: Build A Killer Client For Your REST+JSON API

Component Architectureaccount .save()

RequestExecutor

ResourceFactory Map Resource

AuthenticationStrategy

MapMarshaller JSON <--> Map

CacheManager

DataStore

RequestAuthenticator

Learn more at Stormpath.com

Page 39: Build A Killer Client For Your REST+JSON API

Component Architectureaccount

API Server

.save()

RequestExecutor

ResourceFactory Map Resource

AuthenticationStrategy

MapMarshaller JSON <--> Map

CacheManager

DataStore

RequestAuthenticator

Learn more at Stormpath.com

Page 40: Build A Killer Client For Your REST+JSON API

Caching

Learn more at Stormpath.com

Page 41: Build A Killer Client For Your REST+JSON API

Cachingpublic interface CacheManager { Cache getCache(String regionName);}

public interface Cache { long getTtl(); long getTti(); ... Map<String,Object> get(String href); ... other map methods ... }

Learn more at Stormpath.com

Page 42: Build A Killer Client For Your REST+JSON API

CachingAccount account = client.getAccount(href);

//DataStore:

Cache cache = cacheManager.getCache(“accounts”);Map<String,Object> accountProperties = cache.get(href);if (accountProps != null) { return resourceFactory.create(Account.class, props);}

//otherwise, query the server:requestExeuctor.get(href) ...

Learn more at Stormpath.com

Page 43: Build A Killer Client For Your REST+JSON API

Queries

Learn more at Stormpath.com

Page 44: Build A Killer Client For Your REST+JSON API

QueriesGroupList groups = account.getGroups();//results in a request to://https://api.stormpath.com/v1/accounts/a1b2c3/groups

• What about query parameters?• How do we make this type safe?

Learn more at Stormpath.com

Page 45: Build A Killer Client For Your REST+JSON API

Queries

Use a Fluent API!

Learn more at Stormpath.com

Page 46: Build A Killer Client For Your REST+JSON API

QueriesGroupList groups = account.getGroups(Groups.where() .name().startsWith(“foo”) .description().contains(“test”) .orderBy(“name”).desc() .limitTo(100));//results in a request to:

https://api.stormpath.com/v1/accounts/a1b2c3/groups? name=foo*&description=*test*&orderBy=name%20desc&limit=100

Learn more at Stormpath.com

Page 47: Build A Killer Client For Your REST+JSON API

QueriesAlso support simple map for dynamic languages, for example, groovy:

def groups = account.getGroups([name: ‘foo*’, description:’*test*’, orderBy:’name desc’, limit: 100]);

//results in a request to:https://api.stormpath.com/v1/accounts/a1b2c3/groups? name=foo*&description=*test*&orderBy=name%20desc&limit=100

Learn more at Stormpath.com

Page 48: Build A Killer Client For Your REST+JSON API

Authentication

Learn more at Stormpath.com

Page 49: Build A Killer Client For Your REST+JSON API

Authentication• Favor a digest algorithm over HTTP Basic• Prevents Man-in-the-Middle attacks (SSL won’t guarantee

this!)

• Also support Basic for environments that require it (Dammit Google!)• ONLY use Basic over SSL

• Represent this as an AuthenticationScheme to your ClientBuilder

Learn more at Stormpath.com

Page 50: Build A Killer Client For Your REST+JSON API

Authentication• AuthenticationScheme.SAUTHC1• AuthenticationScheme.BASIC• AuthenticationScheme.OAUTH10a• ... etc ...

Client client = Clients.builder() ... //defaults to SAUTHC1 .setAuthenticationScheme(BASIC) .build();

Client uses a Sauthc1RequestAuthenticator or BasicRequestAuthenticator or OAuth10aRequestAuthenticator, etc.

Learn more at Stormpath.com

Page 51: Build A Killer Client For Your REST+JSON API

Plugins

Learn more at Stormpath.com

Page 52: Build A Killer Client For Your REST+JSON API

Plugins

• Plugins or Extensions module• One sub-module per plugin• Keep dependencies to a minimum

extensions/|- httpclient |- src/main/java

Learn more at Stormpath.com

Page 53: Build A Killer Client For Your REST+JSON API

Lessons Learned

Learn more at Stormpath.com

Page 54: Build A Killer Client For Your REST+JSON API

Lessons Learned

• Recursive caching if you support resource expansion

• Dirty checking logic is not too hard, but it does add complexity. Start off without it.

Learn more at Stormpath.com

Page 55: Build A Killer Client For Your REST+JSON API

Lessons Learned: Async, Async!

• Async clients can be used synchronously easily, but not the other way around

• Vert.x, Netty, Scala, Clojure, etc. all require async – hard to use your SDK otherwise

• Netty has a *great* Async HTTP Client that can be the base of your client SDK

Learn more at Stormpath.com

Page 56: Build A Killer Client For Your REST+JSON API

Lessons Learned: Async!account.req().groups().where()....execute(new ResultListener<GroupList>() { onSuccess(GroupList groups){...} onFailure(ResourceException ex) {...}}

account.req() -> RequestBuilderexecute -> async call w/ promise callback

Learn more at Stormpath.com

Page 57: Build A Killer Client For Your REST+JSON API

Lessons Learned: SyncSync is still easy:

account.getGroups() just delegates to:

account.req().groups()... .get();

Learn more at Stormpath.com

Page 58: Build A Killer Client For Your REST+JSON API

$ git clone https://github.com/stormpath/stormpath-sdk-java.git

$ cd stormpath-sdk-java

$ mvn install

Code

Learn more at Stormpath.com

Page 59: Build A Killer Client For Your REST+JSON API

Thank You!

[email protected]• Twitter: @lhazlewood• http://www.stormpath.com

Learn more at Stormpath.com