operating microservices with groovy

39
Operating Microservices with Andrés Viedma @andres_viedma

Upload: andres-viedma-pelaez

Post on 14-Jan-2017

371 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Operating Microservices with Groovy

OperatingMicroservices

with

Andrés Viedma@andres_viedma

Page 2: Operating Microservices with Groovy

Andrés ViedmaAndrés Viedma@andres_viedma@andres_viedma

Page 3: Operating Microservices with Groovy

Andrés ViedmaAndrés Viedma@andres_viedma@andres_viedma

Page 4: Operating Microservices with Groovy
Page 5: Operating Microservices with Groovy

curl \

-u "jsonrpc:19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" \

-d '{"jsonrpc": "2.0", "id": 1, \

"method": "getAllTasks", "params": , {"project_id": 1, "status_id": 1} }' \

http://demo.kanboard.net/jsonrpc.php

Page 6: Operating Microservices with Groovy

01 LET'S PLAY!(IN THE MUD)

Page 7: Operating Microservices with Groovy

Our weapon: the Groovy shell groovysh

Page 8: Operating Microservices with Groovy

Our basic Groovy Client

class JsonRpcClient {

(...)

def makeCall(String method, Map params = [:]) { try { (... json call ...) return json.result

} catch (HttpResponseException e) { (...) } }}

Page 9: Operating Microservices with Groovy

class JsonRpcClient {

def methodMissing(String name, args) { return makeCall(name, args) }

def makeCall(String method, Map params = [:]) { (...) } (...)}

Our dynamic Groovy Client

Page 10: Operating Microservices with Groovy

class JsonRpcClient {

def methodMissing(String name, args) { return makeCall(name, args) }

def makeCall(String method, Map params = [:]) { (...) } (...)}

groovy:000> client = new JsonRpcClient(...)===> jsonrpc.JsonRpcClient@a0a9fa5

groovy:000> client.getAllTasks(project_id: 1, status_id: 2)

Our dynamic Groovy Client

Page 11: Operating Microservices with Groovy

Our dynamic REST Groovy Client

blog.posts.”37”.comments()

blog.posts.”37”.delete()

blog.posts.”37” = [text: 'xxx', ...]

GET

POST

PUT

DELETE

blog.posts.”37”.comments << [text: 'xxx', …]

blog.posts.”37”.comments.add(text: 'xxx', …)

Page 12: Operating Microservices with Groovy

class RestGroovyClient extends RestGroovyClientPath { String base (...) private doGet(String path, params = [:]) { … } private doPut(String path, params = [:]) { … } private doPost(String path, params = [:]) { … } private doDelete(String path, params = [:]) { … }}

class RestGroovyClientPath { RestGroovyClient client = null String path = '' (...)}

Our dynamic REST Groovy Client

Page 13: Operating Microservices with Groovy

class RestGroovyClientPath {

def propertyMissing(String name) { newPath(name)

} def getAt(name) { newPath(name.toString()) }

private RestGroovyClientPath newPath(String name) { return new RestGroovyClientPath( client: client, path: nextpath(name)) } (...)}

Our dynamic REST Groovy Client

blog.posts.”37”.comments()

blog['posts'][37].comments()

Page 14: Operating Microservices with Groovy

class RestGroovyClientPath {

def methodMissing(String name, args) { return client.doGet(nextpath(name), args) }

def propertyMissing(String name, value) { return client.doPut(nextpath(name), args) }

def leftShift(value) { return client.doPost(path, value) }

def delete() { return client.doDelete(path) }}

Our dynamic REST Groovy Client

blog.posts.”37”.comments()

blog.posts.”37” = [...]

blog.posts << [...]

blog.posts.”37”.delete()

Page 15: Operating Microservices with Groovy

02 YOUR LITTLEBLACK BOOK

Page 16: Operating Microservices with Groovy
Page 17: Operating Microservices with Groovy

What if we create a directory of our services?

Organized as a tree

Grouped by features, by environment...

Register as shell variables

Page 18: Operating Microservices with Groovy

The ConfigSlurper

import dynapiclient.rest.*

jsonrpc { kanboard = new JsonRpcClient( base: 'http://demo.kanboard.net/jsonrpc.php', clientHandler: { it.auth.basic 'demo', 'demo123' } )}rest { (...) marvel = new RestDynClient( base: 'http://gateway.marvel.com/', path: '/v1/public', paramsHandler: this.&marvelAuthenticate)}

void marvelAuthenticate(Map callParams, String method) { (...)}

jsonrpc.kanboard.getMyProjects()

Page 19: Operating Microservices with Groovy

The ConfigSlurper

import dynapiclient.rest.*

jsonrpc { kanboard = new JsonRpcClient( base: 'http://demo.kanboard.net/jsonrpc.php', clientHandler: { it.auth.basic 'demo', 'demo123' } )}rest { (...) marvel = new RestDynClient( base: 'http://gateway.marvel.com/', path: '/v1/public', paramsHandler: this.&marvelAuthenticate)}

void marvelAuthenticate(Map callParams, String method) { (...)}

Page 20: Operating Microservices with Groovy

Available on startup: ~/.groovy/groovysh.profile

groovyUserHome = new File(System.getProperty('user.home'), '.groovy')file = new File(groovyUserHome, 'assets.groovy')

binding.variables << new ConfigSlurper().parse(file.toURI().toURL())

Page 21: Operating Microservices with Groovy

Teamwork: share the directory

@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')

Page 22: Operating Microservices with Groovy

Teamwork: share the directory

Fast release cycle

@Grab(group='org.springframework', module='spring-orm', version='3.2.5.RELEASE')

@SourceGrab( 'https://github.com/andresviedma/ groovy-assets-directory-example.git')

Page 23: Operating Microservices with Groovy

AST transformation

Source Grapes Available in

Classpath

@SourceGrab('<url>')public class myscript extends Script { static { SourceGrape.grab("<url>"); } (...)}

TRICK Add the sources directory to the classpath in runtime and... it just works!

Page 24: Operating Microservices with Groovy

Merge directory parts (ConfigSlurper)

1. Passwords (local)

2. The main directory (git)

3. Personal / dev assets (local)

TRICK Merge config files: append all the files and then parse them

Page 25: Operating Microservices with Groovy

03 I NEVER FORGET A FACE(BUT IN YOUR CASE, I'LL MAKE AN EXCEPTION)

Page 26: Operating Microservices with Groovy
Page 27: Operating Microservices with Groovy
Page 28: Operating Microservices with Groovy

Asking for help

marvel.characters(doc)

groovy:000> rest.marvel.characters===> **** /v1/public/characters ** GET: Fetches lists of characters.Params: name, nameStartsWith, modifiedSince, comics, series, events, stories, orderBy, limit, offsetNext: {characterId}

groovy:000>

marvel.characters()GET

marvel.characters.help()(doc)

Page 29: Operating Microservices with Groovy

Asking for help

groovy:000> rest.marvel.characters."1010354"===> **** /v1/public/characters/{characterId} ** GET: Fetches a single character by id.[characterId(*)]Next: comics, events, series, stories

groovy:000>

Replaceable URL path sections

Page 30: Operating Microservices with Groovy

What about Autocomplete?

We have the ExpandoMetaClass!

groovy:000> x = 2===> 2groovy:000> x.metaClass.sayHello = { args -> println 'hello' }===> groovysh_evaluate$_run_closure1@57adfab0groovy:000> x.sayHello()hello===> nullgroovy:000> x.abs() byteValue() compareTo( doubleValue() downto( floatValue() intValue() longValue() power( shortValue() times( upto( groovy:000>

Page 31: Operating Microservices with Groovy

What about Autocomplete?

We have the ExpandoMetaClass!

groovy:000> x = 2===> 2groovy:000> x.metaClass.sayHello = { args -> println 'hello' }===> groovysh_evaluate$_run_closure1@57adfab0groovy:000> x.sayHello()hello===> nullgroovy:000> x.abs() byteValue() compareTo( doubleValue() downto( floatValue() intValue() longValue() power( shortValue() times( upto( groovy:000>

Page 32: Operating Microservices with Groovy

What about Autocomplete?

The shell wraps the Expando In a HandleMetaClass

groovy:000> x.metaClass===> HandleMetaClass[MetaClassImpl[class java.lang.String]]groovy:000> x.metaClass."hello" = { name -> "Hello ${name}" }===> groovysh_evaluate$_run_closure1@feba70egroovy:000> x.metaClass===> HandleMetaClass[ExpandoMetaClass[class java.lang.String]]

groovy:000> x.metaClass.getMetaMethods()*.name.findAll { it.startsWith('h') }===> [hasProperty]

TRICK Use InvokerHelper.getMetaClass(x) instead of x.metaClass

Page 33: Operating Microservices with Groovy

class AutocompleteMetaClass extends DelegatingMetaClass {

static void addFakeMethodsToObject(Object object, methods, properties) { def autocomplete = configureMetaClass(object) def innerMeta = autocomplete.originalMetaClass addFakeMethodsToExpando(innerMeta, object, methods, properties) }

private static MetaClass configureMetaClass(Object object) { def metaOld = InvokerHelper.getMetaClass(object) if (metaOld.getClass().name != AutocompleteMetaClass.class.name) { object.metaClass = new AutocompleteMetaClass(metaOld) } return InvokerHelper.getMetaClass(object) }

(...)}

Create your own brand AutocompleteMetaClass

Page 34: Operating Microservices with Groovy

class AutocompleteMetaClass extends DelegatingMetaClass {(...)

final MetaClass expando

AutocompleteMetaClass(MetaClass originalMetaClass) { super(originalMetaClass) this.expando = originalMetaClass }

List<MetaMethod> getMetaMethods() { return expando.getExpandoMethods() } List<MetaBeanProperty> getProperties() { return expando.getExpandoProperties() }}

Create your own brand AutocompleteMetaClass

Page 35: Operating Microservices with Groovy

Let's demo!!!

Page 36: Operating Microservices with Groovy

04 So...?(JUST ENDING, I PROMISE...)

Page 37: Operating Microservices with Groovy

Give me the code!!!

https://github.com/andresviedma/sourcegrape

https://github.com/andresviedma/dynapiclient-groovy

https://github.com/andresviedma/groovy-assets-directory-example

Page 38: Operating Microservices with Groovy

Where did all this led us?

Shared microservices directory

Dynamic service calls

Autocomplete

Integrated help

A powerful shell

Page 39: Operating Microservices with Groovy

But, in the way there, mostly...

Learning about Groovy scripting black magic

Having fun!

Andrés ViedmaAndrés Viedma@andres_viedma@andres_viedma

Questions?