Skip to content

Instantly share code, notes, and snippets.

@renatoathaydes
Last active June 16, 2021 12:18
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save renatoathaydes/2860486594cfe39e43d36bae22cf5aff to your computer and use it in GitHub Desktop.
Save renatoathaydes/2860486594cfe39e43d36bae22cf5aff to your computer and use it in GitHub Desktop.
HTTP Server / Client in Groovy
/*
* This is a runnable groovy script.
* Run with "groovy client.groovy".
*
* Don't forget to start the server.groovy script first (shown in this gist).
*/
import groovy.transform.CompileStatic
import groovy.transform.Immutable
import groovy.transform.ToString
import groovy.transform.TypeChecked
@Grab( group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.7.2' )
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseDecorator
import groovyx.net.http.Method
import org.apache.http.util.EntityUtils
/**
* Simple trait that adds HTTP client capabilities to any class.
*/
trait CanTalkHttp {
SimpleHttpResponse withClient( HTTPBuilder httpClient,
HttpOperation operation ) {
def handler = { HttpResponseDecorator resp ->
Map<String, Collection<String>> headersMap = [ : ]
resp.headers.each { headersMap.get( it.name, [ ] ) << it.value }
new SimpleHttpResponse( resp.status, EntityUtils.toString( resp.entity ), headersMap )
}
httpClient.handler.success = handler
httpClient.handler.failure = handler
println "Running ${operation.method} to ${operation.path}"
httpClient.request( operation.method, operation.accept ) {
HTTPBuilder.RequestConfigDelegate d = getDelegate()
d.uri.path = operation.path
d.setHeaders( operation.headers )
if ( operation instanceof Post ) {
d.send operation.contentType, operation.body
}
} as SimpleHttpResponse
}
}
/**
* Representation of a HTTP response that is easy to check type-safely.
*/
@Immutable
@CompileStatic
@ToString( includeFields = true, includeNames = true, includePackage = false )
class SimpleHttpResponse {
int statusCode
String body
Map<String, ? extends Collection<String>> headers
}
/**
* Parent class of all HTTP method types.
*/
abstract class HttpOperation {
abstract Method method
String path = '/'
String accept = 'application/json'
Map<String, ?> headers = [ : ]
}
/*
* GET HTTP Request configuration
*/
class Get extends HttpOperation {
final Method method = Method.GET
}
/*
* POST HTTP Request configuration
*/
class Post extends HttpOperation {
final Method method = Method.POST
String contentType = 'application/json'
String body = ''
}
/*
* Simple example class showing how to make use of the CanTalkHttp trait.
*/
@TypeChecked
class Example implements CanTalkHttp, Runnable {
final HTTPBuilder client = new HTTPBuilder( 'http://localhost:4567' )
void show( SimpleHttpResponse resp ) {
println "Server responded with ${resp.statusCode}"
println "Headers: ${resp.headers}"
println "Body: ${resp.body}"
}
void run() {
// run a GET Request with our client
def resp = withClient( client, new Get( path: '/hello' ) )
// Show the response
show resp
// run a POST Request
resp = withClient( client, new Post(
path: 'data',
body: '{"hello": true, "name": "Renato"}' ) )
show resp
}
}
new Example().run()
/*
* Very simple HTTP server using http://sparkjava.com/
*
* Start the server with "groovy server.groovy".
*/
@Grab( group = 'com.sparkjava', module = 'spark-core', version = '2.1' )
import static spark.Spark.*
staticFileLocation '.'
get '/hello', { req, res -> log req; '{"hi": true, "ho": 3}' }
post '/data', { req, res -> log req; "Thank you for sending me data: ${req.body()}" }
def log( req ) {
println "Handling ${req.requestMethod()} ${req.pathInfo()}"
println "Headers: ${req.headers().collect { it + ': ' + req.headers( it ) }}"
def b
if ( ( b = req.body() ) ) {
println "Body: $b"
} else {
println "No body"
}
}
println 'Enter to exit'
System.in.newReader().readLine()
println "Done"
stop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment