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

  • View
    906

  • Download
    8

Embed Size (px)

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

  • 1. Groovy Vampires: REST, NoSQL, and MoreKenneth Kousen@kenkousenken.kousen@kousenit.com 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

2. Groovy VampiresGroovy, REST, NoSQL, and Bad Marketing 3. Only one 4. Two (or more) 5. NYT #1 Best Seller 6. NYT #1 Best Seller2008 #1 selling book(over 22 million) 7. NYT #1 Best Seller2008 #1 selling book(over 22 million)Made into a very boringMajor Motion Feature 8. http://manning.com/kousen 9. http://manning.com/kousenNYT ignored (so far) 10. http://manning.com/kousenNYT ignored (so far)Great Amazon reviews(that's actually true) 11. http://manning.com/kousenNYT ignored (so far)Great Amazon reviewsNominated for Jolt award 12. http://manning.com/kousenNYT ignored (so far)Great Amazon reviewsNominated for Jolt award(I did that, but still) 13. Clearly what my book needs ... 14. Groovy vampires! 15. Rotten Tomatoeshttp://www.rottentomatoes.com/Movie review site 16. Rotten Tomatoeshttp://www.rottentomatoes.com/Movie review siteAPI provides REST access (with key)GET requests only 17. REST- Addressable resources- Uniform interface- Content negotiation- HATEOAS 18. REST- Addressable resourceshttp://api.rottentomatoes.com/api/public/v1.0/movies.json?q=vampire&page_limit=10&page=1&apikey=... 19. REST- Addressable resources- Uniform interfaceRotten Tomatoes: GET requests only 20. REST- Addressable resources- Uniform interface- Content negotiationRotten Tomatoes: JSON onlyContent type in URL 21. REST- Addressable resources- Uniform interface- Content negotiation- HATEOASEmbedded links for each movieTop level self and next links 22. Sample: Blazing Saddles- GET requests in Groovy are trivial'...url...'.toURL().text 23. Sample: Blazing Saddles- URL needs query string 24. Sample: Blazing Saddles- URL needs query string- assemble from map:qs = [k1:v1, k2:v2].collect { k,v "$k=$v" }.join('&') 25. Sample: Blazing Saddles// API key in fileString apiKey = new File('rotten_tomatoes_apiKey.txt').text 26. Sample: Blazing Saddles// API key in fileString apiKey = new File('rotten_tomatoes_apiKey.txt').text// Base URLString base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?" 27. Sample: Blazing Saddles// API key in fileString apiKey = new File('rotten_tomatoes_apiKey.txt').text// Base URLString base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?"// Assemble query stringString qs = [apiKey:apiKey, q: URLEncoder.encode('Blazing Saddles','UTF-8')].collect { it }.join('&')toString of Map.Entry 28. Sample: Blazing Saddles// API key in fileString apiKey = new File('rotten_tomatoes_apiKey.txt').text// Base URLString base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?"// Assemble query stringString qs = [apiKey:apiKey, q: URLEncoder.encode('Blazing Saddles','UTF-8')].collect { it }.join('&')// Full URLString url = "$base$qs" 29. Sample: Blazing SaddlesJsonOutput.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"},... 30. 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"} 31. Sample: Blazing Saddles- Pagination"links": {"self": "http://api.rottentomatoes.com/.../movies.json?...&page=1","next": "http://api.rottentomatoes.com/.../movies.json?...&page=2"} 32. Sample: Blazing SaddlesAnd, of course, Mongo{"cast": [{ }, {"id": "415791170","name": "Alex Karras","characters": ["Mongo"]}, { }]} 33. Which inevitably leads us to: 34. MongoDBhttp://www.mongodb.org/ 35. MongoDB home page, www.mongodb.org 36. MongoDB- Document based 37. MongoDB- Document based- BSON Binary JSON 38. MongoDB- Document based- BSON Binary JSON- Open source 39. MongoDB- Document based- BSON Binary JSON- Open source- Full indexing 40. MongoDB- Document based- BSON Binary JSON- Open source- Full indexing- JavaScript queries 41. MongoDBStart server> mongodruns on port 27017 by default 42. MongoDBClient program is mongo:$ mongo 43. MongoDBClient program is mongo:$ mongo> show databases 44. MongoDBClient program is mongo:$ mongo> show databases> use movies 45. MongoDBClient program is mongo:$ mongo> show databases> use movies> show collections 46. MongoDBClient program is mongo:$ mongo> show databases> use movies> show collections> db.vampireMovies.find() 47. Java DriverJava driver availablehttp://docs.mongodb.org/ecosystem/drivers/java/JavaDocshttp://api.mongodb.org/java/current/ 48. BasicDBObjectcom.mongodb.BasicDBObjectextendsjava.util.LinkedHashMapwrapper for domain classes 49. GroovyGMongo Projecthttps://github.com/poiati/gmongo/Maintained by Paolo Poiati(not active, but still works) 50. @DelegateTypical Groovy idiom:Groovy class wraps Java class 51. @Delegateclass GMongo {@DelegateMongo mongo // from Java driver} 52. Doesn't exactlydraw your eye,does it? 53. Populate MongoDB- Perform GET request at RT- Parse results into JSON objects- Append to DB collection- Handle pagination through links 54. 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 55. Populate MongoDB- Perform GET request at RT- Parse results into JSON objectsdef vampMovies =new JsonSlurper().parseText(url.toURL().text) 56. Populate MongoDB- Perform GET request at RT- Parse results into JSON objects- Append to DB collectiondb.vampireMovies url-mappings-report 77. 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 | 78. GrailsMongoDB pluginhttp://grails.org/plugin/mongodbAdd to BuildConfig.groovy:compile ":mongodb:3.0.1" 79. GrailsAdd to domain classes:ObjectId id 80. GrailsAdd to domain classes:ObjectId idstatic mapWith = "mongo" 81. GrailsAdd to domain classes:ObjectId idstatic mapWith = "mongo"static embedded = [..., , ] 82. GrailsAdd to DataSource.groovy:grails {mongo {host = 'localhost'port = 27017databaseName = 'movies'}} 83. GrailsNow can use GORM methodsMovie.withCriteria {ratings {gte 'critics_score', 50}order('ratings.critics_score', 'desc')maxResults(10)} 84. Maybe vampire fans don't buy Groovy, somaybe try a different approach... 85. Or perhaps... 86. Or maybe better ... 87. ConclusionsREST API at Rotten TomatoesGET only (like most public services)MongoDB stores JSON natively 88. ConclusionsGroovy JDK makes GET requests easyHypermedia links for individual moviesself, cast, clips, reviews, Hypermedia links for pagination 89. ConclusionsGMongo project wraps Java APIGreat use of @Delegate 90. ConclusionsRatpack is fast and easy(but not -- yet -- well documented)Natural for RESTShows lots of promise 91. ConclusionsGrails 2.3+ adds RESTUses annotations or RestControllerURL mappingsMongoDB plugin