groovy vampires: combining groovy, rest, nosql, and more

99
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Groovy Vampires: REST, NoSQL, and More Kenneth Kousen @kenkousen [email protected]

Upload: spring-io

Post on 02-Jul-2015

948 views

Category:

Software


8 download

DESCRIPTION

Speaker: Kenneth Kousen If a book as horrible as Twilight can sell millions of copies and be made into an even worse movie, how many copies can a book with Groovy vampires sell? (Spoiler: Not as many.) Yes, this topic may be silly, but the technologies used (Groovy, Ratpack, MongoDB, Grails, REST) are (un)deadly serious.

TRANSCRIPT

Page 1: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Groovy Vampires: REST, NoSQL, and More

Kenneth Kousen@kenkousen

[email protected]

Page 2: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Groovy VampiresGroovy, REST, NoSQL, and Bad Marketing

Page 3: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Only one

Page 4: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Two (or more)

Page 5: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

NYT #1 Best Seller

Page 6: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

NYT #1 Best Seller2008 #1 selling book

(over 22 million)

Page 7: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

NYT #1 Best Seller2008 #1 selling book

(over 22 million)

Made into a very boringMajor Motion Feature

Page 8: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://manning.com/kousen

Page 9: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://manning.com/kousen NYT ignored (so far)

Page 10: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://manning.com/kousen NYT ignored (so far)Great Amazon reviews

(that's actually true)

Page 11: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://manning.com/kousen NYT ignored (so far)Great Amazon reviews

Nominated for Jolt award

Page 12: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://manning.com/kousen NYT ignored (so far)Great Amazon reviews

Nominated for Jolt award(I did that, but still)

Page 13: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Clearly what my book needs ...

Page 14: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Groovy vampires!

Page 15: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://www.rottentomatoes.com/ Movie review site

Rotten Tomatoes

Page 16: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

http://www.rottentomatoes.com/ Movie review site

API provides REST access (with key)GET requests only

Rotten Tomatoes

Page 17: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 18: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

REST

- Addressable resources- Uniform interface- Content negotiation- HATEOAS

Page 20: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

REST

- Addressable resources- Uniform interface

Rotten Tomatoes: GET requests only

Page 21: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

REST

- Addressable resources- Uniform interface- Content negotiation

Rotten Tomatoes: JSON onlyContent type in URL

Page 22: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

REST

- Addressable resources- Uniform interface- Content negotiation- HATEOAS

Embedded links for each movieTop level self and next links

Page 23: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

- GET requests in Groovy are trivial

'...url...'.toURL().text

Page 24: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

- URL needs query string

Page 25: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

- URL needs query string- assemble from map:

qs = [k1:v1, k2:v2].collect { k,v → "$k=$v" }

.join('&')

Page 26: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles// API key in file

String apiKey = new File('rotten_tomatoes_apiKey.txt').text

Page 27: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles// API key in file

String apiKey = new File('rotten_tomatoes_apiKey.txt').text

// Base URL

String base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?"

Page 28: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles// API key in file

String apiKey = new File('rotten_tomatoes_apiKey.txt').text

// Base URL

String base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?"

// Assemble query string

String qs = [apiKey:apiKey, q: URLEncoder.encode(

'Blazing Saddles','UTF-8')].collect { it }.join('&')

toString of Map.Entry

Page 29: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles// API key in file

String apiKey = new File('rotten_tomatoes_apiKey.txt').text

// Base URL

String base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?"

// Assemble query string

String qs = [apiKey:apiKey, q: URLEncoder.encode(

'Blazing Saddles','UTF-8')].collect { it }.join('&')

// Full URL

String url = "$base$qs"

Page 30: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles JsonOutput.prettyPrint(url.toURL().text)

→ "movies": [

{

"id": "13581",

"title": "Blazing Saddles",

"year": 1974,

"mpaa_rating": "R",

"runtime": 93,

"release_dates": {

"theater": "1974-02-07",

"dvd": "1997-08-27"

},

...

Page 31: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

- Inside each movie is a links collection: "links": {

"self": "http://api.rottentomatoes.com/.../13581.json",

"alternate": "http://www.rottentomatoes.com/m/blazing_saddles/",

"cast": "http://api.rottentomatoes.com/.../cast.json",

"clips": "http://api.rottentomatoes.com/.../clips.json",

"reviews": "http://api.rottentomatoes.com/.../reviews.json",

"similar": "http://api.rottentomatoes.com/.../similar.json"

}

Page 32: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

- Pagination "links": {

"self": "http://api.rottentomatoes.com/.../movies.json?...&page=1",

"next": "http://api.rottentomatoes.com/.../movies.json?...&page=2"

}

Page 33: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Sample: Blazing Saddles

And, of course, Mongo{

"cast": [{ … }, {

"id": "415791170",

"name": "Alex Karras",

"characters": ["Mongo"]

}, { … }]

}

Page 34: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Which inevitably leads us to:

Page 35: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDBhttp://www.mongodb.org/

Page 36: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB home page, www.mongodb.org

Page 37: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

- Document based

Page 38: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

- Document based- BSON → Binary JSON

Page 39: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

- Document based- BSON → Binary JSON- Open source

Page 40: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

- Document based- BSON → Binary JSON- Open source- Full indexing

Page 41: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

- Document based- BSON → Binary JSON- Open source- Full indexing- JavaScript queries

Page 42: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Start server> mongod

runs on port 27017 by default

Page 43: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Client program is mongo:$ mongo

Page 44: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Client program is mongo:$ mongo

> show databases

Page 45: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Client program is mongo:$ mongo

> show databases

> use movies

Page 46: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Client program is mongo:$ mongo

> show databases

> use movies

> show collections

Page 47: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

MongoDB

Client program is mongo:$ mongo

> show databases

> use movies

> show collections

> db.vampireMovies.find()

Page 48: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Java Driver

Java driver availablehttp://docs.mongodb.org/ecosystem/drivers/java/

JavaDocshttp://api.mongodb.org/java/current/

Page 49: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

BasicDBObjectcom.mongodb.BasicDBObject

extends java.util.LinkedHashMap<String,Object>

wrapper for domain classes

Page 50: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Groovy

GMongo Projecthttps://github.com/poiati/gmongo/

Maintained by Paolo Poiati(not active, but still works)

Page 51: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

@Delegate

Typical Groovy idiom:Groovy class wraps Java class

Page 52: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

@Delegate

class GMongo {

@Delegate

Mongo mongo // from Java driver

…}

Page 53: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Doesn't exactly draw your eye,

does it?

Page 54: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Populate MongoDB

- Perform GET request at RT- Parse results into JSON objects- Append to DB collection- Handle pagination through links

Page 55: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Populate MongoDB

- Perform GET request at RTSame as before, with q:'vampire'

http://api.rottentomatoes.com/api/public/v1.0/movies.json?apiKey=...

&q=vampire

Page 56: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Populate MongoDB

- Perform GET request at RT- Parse results into JSON objects

def vampMovies =

new JsonSlurper().parseText(url.toURL().text)

Page 57: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Populate MongoDB

- Perform GET request at RT- Parse results into JSON objects- Append to DB collection

db.vampireMovies << vampMovies.movies

Page 58: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Populate MongoDB

- Handle paginationdef next = vampMovies?.links?.next

while (next) {

println next

vampMovies = slurper.parseText("$next&apiKey=$key".toURL().text)

db.vampireMovies << vampMovies.movies

next = vampMovies?.links?.next

}

Page 59: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 60: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Mapping to Classes

Map JSON to Classes- Gson very popular

See 'json_to_gson.groovy' script

Page 61: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Mapping to Classes

Alternative:Manually map classes to JSON

Page 62: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Mapping to Classes

Entity classes:MovieCastMemberMPAARating (enum)Rating (audience, critics)

Page 63: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Mapping to Classes

Add static method to Movie:static Movie fromJSON(data)

extract data from mappopulate objects

Page 64: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Much better

Page 65: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Serve up data locally

Build web app around MongoDB

- Ratpack: http://ratpack.io

Page 66: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Ratpack

- Asynchronous I/O- Optimized for Java 8 and Groovy- Dependency Injection via Guice

Page 67: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Lazybones

Lazybones project from Peter Ledbrook

Generates project templates

Page 68: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Lazybones

> lazybones create ratpack vampires

Page 69: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Vampire Server

Implement class to return vampire movies

Page 70: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Vampire Server

Implement class to return vampire movies

Wraps GMongo instance

Page 71: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Vampire Server

Implement class to return vampire movies

Wraps GMongo instance

Like a MovieDAO classmethods map to HTTP verbs

Page 72: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Ratpack

Use GET handler in Ratpack.groovy

Return Movie instances as required

Page 73: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Ratpack

Testing is easySpock spec for Vampire serverIntegration spec for Ratpack

Page 74: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 75: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Alternative server:Grails

REST capabilitiesMongo plugin

Page 76: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

REST via annotation on domain class@Resource

class Movie { … }

→ no explicit controller needed

Page 77: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

URL Mappings

'movies'(resources: 'movie')

Page 78: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Set preference for JSON data@Resource(formats = ['json'])

class Movie { … }

Page 79: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

URL mappings report

grails> url-mappings-report

Page 80: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

GrailsController: movie

| GET | /movies | Action: index |

| GET | /movies/create | Action: create |

| POST | /movies | Action: save |

| GET | /movies/${id} | Action: show |

| GET | /movies/${id}/edit | Action: edit |

| PUT | /movies/${id} | Action: update |

| PATCH | /movies/${id} | Action: patch |

| DELETE | /movies/${id} | Action: delete |

Page 81: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 82: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

MongoDB pluginhttp://grails.org/plugin/mongodb

Add to BuildConfig.groovy:compile ":mongodb:3.0.1"

Page 83: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Add to domain classes:ObjectId id

Page 84: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Add to domain classes:ObjectId idstatic mapWith = "mongo"

Page 85: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Add to domain classes:ObjectId idstatic mapWith = "mongo"static embedded = [..., …, …]

Page 86: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Add to DataSource.groovy:grails {

mongo {

host = 'localhost'

port = 27017

databaseName = 'movies'

}

}

Page 87: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Grails

Now can use GORM methodsMovie.withCriteria {

ratings {

gte 'critics_score', 50

}

order('ratings.critics_score', 'desc')

maxResults(10)

}

Page 88: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Maybe vampire fans don't buy Groovy, somaybe try a different approach...

Page 89: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 90: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Or perhaps...

Page 91: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 92: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Or maybe better ...

Page 93: Groovy Vampires: Combining Groovy, REST, NoSQL, and more
Page 94: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Conclusions

REST API at Rotten TomatoesGET only (like most public services)

MongoDB stores JSON natively

Page 95: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Conclusions

Groovy JDK makes GET requests easy

Hypermedia links for individual moviesself, cast, clips, reviews, …

Hypermedia links for pagination

Page 96: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Conclusions

GMongo project wraps Java API

Great use of @Delegate

Page 97: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Conclusions

Ratpack is fast and easy(but not -- yet -- well documented)

Natural for REST

Shows lots of promise

Page 98: Groovy Vampires: Combining Groovy, REST, NoSQL, and more

Conclusions

Grails 2.3+ adds RESTUses annotations or RestControllerURL mappings

MongoDB plugin

Page 99: Groovy Vampires: Combining Groovy, REST, NoSQL, and more