Http
Purpose¶
Enables the sending of http requests.
Methods¶
Binding name: p6.http
TLDR
-
Specify method
def response = p6.http.post()
-
Specify URL
def response = p6.http.post() to 'https://myurl.com'
-
Add request body (optional)
def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5
-
Configure request
def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5 socketTimeout 3 sniServerName 'myurl2.com'
-
Send
def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5 socketTimeout 3 sniServerName 'myurl2.com' send()
-
Use response
def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5 send() if (response.ok) { p6.log.info response.body }
Specify Method¶
To send a HTTP request one must first specify which method to use.
- ToMethodBuilder
p6.http.post()
,p6.http.patch()
,p6.http.put()
- FromMethodBuilder
p6.http.get()
,p6.http.delete()
,p6.http.options()
Specify URL¶
Note the methods return 2 different MethodBuilders, which perform different operations: sending to
OR receiving from
.
This enables us to do p6.http.post() to ...
and p6.http.get() from ...
.
Add request body (optional)¶
If you’re using a method that returns a ToMethodBuilder, you can add data to the method body. These methods add the appropriate content type headers automatically.
json¶
Accepts: Map<String, Map/String/Int>
- the json structure: containing recursive maps of the same types
Set the body of the request as json, and necessary headers.
Syntax
<T extends Serializable> ToRequestClient json(final Map<String, T> jsonObject) throws Exception
Example
final def invoice = [name: 'invoice', data: [price: 10, shop: 'lidl', breakdown: [cheese: 8, milk: 2]]]
p6.http.{method}() to 'https...' json invoice send()
xml¶
Accepts: Map<String, Map/String/Int>
- the xml structure: containing recursive maps of the same types
Warning
The XML object must have one root node.
If not, it will be wrapped by <root></root>
Syntax
<T extends Serializable> ToRequestClient xml(final Map<String, T> xmlObject) throws P6Exception
Example
final def invoice = [name: 'testing', data: [price: 10, amount: 1]]
p6.http.{method}() to 'https...' xml invoice send()
formUrlEncoded¶
Accepts: Map<String, Map/String/Int>
- the form structure: containing recursive maps of the same types
Syntax
groovy
<T extends Serializable> ToRequestClient formUrlEncoded(final Map<String, T> form)
Example
final def details = [name: 'max', address: [number: 10, road: 'fake street', region: 'Birmingham']]
p6.http.{method}() to 'https...' formUrlEncoded details send()
text¶
Accepts: String
- the text body
Syntax
groovy
ToRequestClient text(final String body)
Example
p6.http.{method}() to 'https...' text 'abcdefghijk' send()
bytes¶
Accepts: byte[]
- the byte body
Syntax
groovy
ToRequestClient bytes(final byte[] body)
Example
final def arrayOfBytes = {1, 2, 3, 4, 5};
p6.http.{method}() to 'https...' bytes arrayOfBytes send()
mime¶
The mime method accepts a closure.
This closure will configure a multi-part request with 6 different
types: file
, bytes
, text
, stream
, json
, xml
.
These methods all accept similar parameters, aside from text, which doesn’t accept filename.
Tip
Need to add a header/field to an individual part?
Each mime method accepts an additional parameter at the end, of Map<String, String>
final def myJson = [name: 'max', address: [number: 10, road: 'fake street', region: 'Birmingham']]
final def res = p6.http.post() to 'https://max2.requestcatcher.com/test' mime {
json 'jsonPartName', myJson, [Content-Disposition: 'xyz']
} send()
json¶
Accepts: String
- the part name, Map<String, Map/String/Int>
- the xml structure: containing recursive
maps of the same types
Default: content type = application/json
Syntax
<T extends Serializable> MimeBuilder json(final String partName, final Map<String, T> json) throws P6Exception
Example
final def myJson = [name: 'max', address: [number: 10, road: 'fake street', region: 'Birmingham']]
p6.http.post() to 'https...' mime {
json 'jsonPartName', myJson
} send()
xml¶
Accepts: String
- the part name, Map<String, Map/String/Int>
- the xml structure: containing recursive
maps of the same types
Default: content type = application/xml
Syntax
<T extends Serializable> MimeBuilder xml(final String partName, final Map<String, T> xml) throws P6Exception
Warning
The XML object must have one root node.
If not, it will be wrapped by <root></root>
Example
final def myXml = [invoice: [amount: 10, unitCost: 5, name: 'Cheese']]
p6.http.post() to 'https...' mime {
xml 'xmlPartName', myXml
} send()
file¶
Accepts: String
- the part name, File
- the file
Default: content type = application/octet-stream
Syntax
MimeBuilder file(final String partName, final File file)
MimeBuilder file(final String partName, final File file, final String contentType, final String fileName) throws P6Exception
Example
final def myFile = p6.uri.fileFromUrl 'p6file://${P6_DATA}/resources/xyz.abc'
p6.http.post() to 'https...' mime {
file 'file1', myFile
} send()
with content type
Accepts: String
- the part name, File
- the file, String
- content type, String
- file name
final def myFile = p6.uri.fileFromUrl 'p6file://${P6_DATA}/resources/xyz.abc'
p6.http.post() to 'https...' mime {
file 'file1', myFile, 'application/pdf', 'xyz.abc'
} send()
text¶
Accepts: String
- the part name, String
- the text
Default: content type = text/plain
Syntax
MimeBuilder text(final String partName, final String text)
MimeBuilder text(final String partName, final String text, final String contentType) throws P6Exception
Example
p6.http.post() to 'https...' mime {
text 'textPartName', 'someTextToSend'
} send()
with content type
Accepts: String
- the part name, String
- the text, String
- content type
p6.http.post() to 'https...' mime {
text 'textPartName', 'sometextToSend', 'text/plain'
} send()
bytes¶
Accepts: String
- the part name, byte[]
- the bytes
Default: content type = application/octet-stream
Syntax
groovy
MimeBuilder bytes(final String partName, final byte[] bytes)
MimeBuilder bytes(final String partName, final byte[] bytes, final String contentType, final String fileName) throws P6Exception
Example
final def arrayOfBytes = {1, 2, 3, 4, 5};
p6.http.post() to 'https...' mime {
bytes 'bytePartName', arrayOfBytes
} send()
with content type
Accepts: String
- the part name, byte[]
- the bytes, String
- content type, String
- file name
final def arrayOfBytes = {1, 2, 3, 4, 5};
p6.http.post() to 'https...' mime {
bytes 'bytePartName', arrayOfBytes, 'text/plain', 'fileName'
} send()
stream¶
Accepts: String
- the part name, InputStream
- the stream
Default: content type = application/octet-stream
Syntax
MimeBuilder stream(final String partName, final InputStream stream)
MimeBuilder stream(final String partName, final InputStream stream, final String contentType, final String fileName) throws P6Exception
Example
final def myStream = new ByteArrayInputStream {1, 2, 3, 4, 5};
p6.http.post() to 'https...' mime {
stream 'streamPartName', myStream
} send()
with content type
Accepts: String
- the part name, InputStream
- the stream, String
_- content type, String
- file name
final def myStream = new ByteArrayInputStream {1, 2, 3, 4, 5};
p6.http.post() to 'https...' mime {
stream 'streamPartName', myStream, 'text/plain', 'fileName'
} send()
Configure request¶
A method builder enables the configuring of a request client, which is received by specifying the URL using to
or from
.
Then we can configure.
headers¶
Accepts: Map<String, String>
- map of the headers
Set the headers of the request.
Syntax
RequestClient headers(final Map<String, String> headers)
Example
p6.http.{method}() {to/from} 'https...' headers Accept-Encoding: 'gzip, deflate, br'
socketTimeout¶
Accepts: Integer
- amount of seconds until timing out
Set the timeout of the socket until it receives data.
Syntax
RequestClient socketTimeout(final int timeout)
Example
p6.http.{method}() {to/from} 'https...' socketTimeout 2
connectTimeout¶
Accepts: Integer
- amount of seconds until timing out
Set the timeout until a connection with the end server is established.
Syntax
RequestClient connectTimeout(final int timeout)
Example
p6.http.{method}() {to/from} 'https...' connectTimeout 2
connectRequestTimeout¶
Accepts: Integer
- amount of seconds until timing out
Set the timeout when requesting a connection from the connection manager.
Syntax
RequestClient connectRequestTimeout(final int timeout)
Example
p6.http.{method}() {to/from} 'https...' connectRequestTimeout 2
retry¶
Accepts: Integer
- amount of retry attempts
Default: 1
Set the number of retries for the request.
Syntax
RequestClient retry(final int retry)
Example
p6.http.{method}() {to/from} 'https...' retry 1
identityPrivateKeyPath¶
Accepts: String
- the certificate path
Configure the private key, stored on disk, to use in the secure context.
Syntax
RequestClient identityPrivateKeyPath(final String path) throws P6Exception
Example
p6.http.{method}() {to/from} 'https...' identityPrivateKeyPath 'p6file://${P6_DATA}/resources/certificates/privatekey.pem'
identityCertPaths¶
Accepts: String...
- comma-seperated list of certificate paths
Configure the certificates, stored on disk, to use in the secure context.
Syntax
RequestClient identityCertPaths(final String... paths)
Example
p6.http.{method}() {to/from} 'https...' identityCertPaths 'p6file://${P6_DATA}/resources/certificates/privatekey.pem'
p6.http.{method}() {to/from} 'https...' identityCertPaths 'p6file://${P6_DATA}/resources/certificates/privatekey.pem', 'p6file://${P6_DATA}/privatekey2.pem'
sniServerName¶
Accepts: String
- the alternate server name
Configure the accepted server name when identifying the destination server.
Syntax
RequestClient sniServerName(final String sniServerName)
Example
p6.http.{method}() {to/from} 'https...' sniServerName 'xyz.com'
trustType¶
Accepts: String
Default: 'ONE_WAY_TRUST_ANY'
Sets the trust type used in the secure context.
Valid values: ONE_WAY
, TWO_WAY
, ONE_WAY_TRUST_ANY
, TWO_WAY_TRUST_ANY
, NONE
Syntax
RequestClient trustType(final String trustType) throws P6Exception
Example
p6.http.{method}() {to/from} 'https...' trustType 'two_way'
authCaching¶
Accepts: Boolean
Default: true
Sets whether authentication is cached.
Syntax
RequestClient authCaching(final boolean authCaching)
Example
p6.http.{method}() {to/from} 'https...' authCaching true
autoRetry¶
Accepts: Boolean
Default: true
Sets whether to automatically retry sending the request.
Syntax
RequestClient autoRetry(final boolean autoRetry)
Example
p6.http.{method}() {to/from} 'https...' autoRetry true
cookieManagement¶
Accepts: Boolean
Default: true
Sets whether cookie management is enabled.
Syntax
RequestClient cookieManagement(final boolean cookieManagement)
Example
p6.http.{method}() {to/from} 'https...' cookieManagement true
Add auth - optional¶
Add some authentication to the request.
basic¶
Example
p6.http.{method}() {to/from} 'https...' auth.basic {
id 'myID'
secret 'mySecret'
}
bearer¶
Adds a Authorization header to the final request containing the extracted access token.
To customise the request to get the access token, use the customAuthRequest
closure.
To customise where to extract the access token from the response use the extractor
closure - it receives the same object described in the Use Response
section.
Example
p6.http.{method}() {to/from} 'https...' auth.bearer {
id 'myID'
secret 'mySecret'
url 'https://p6-auth.requestcatcher.com/test'
customAuthRequest {
headers 'Content-Type': 'application/x-www-form-urlencoded'
}
extractor {
return 'yesThisIsABearerToken'
}
}
jwt¶
Adds a Authorization header to the final request containing the JWT.
Warning
Only private keys encoded in PKCS8 are supported
Supported algorithms: RSA256, RSA384, RSA512, ECDSA256, ECDSA384, ECDSA512.
Example
p6.http.{method}() {to/from} 'https...' auth.jwt {
privateKeyPath 'p6file://${P6_DATA}/certs/key.ecdsa'
algorithm 'ECDSA512'
claims name: 'John Doe', admin: true
}
Send¶
Send the request.
Example
def res = p6.http.{method}() {to/from} 'https...' send()
Use response¶
The above send method returns an object with helpful accessors.
Warning
You can only consume the body as String, bytes or Stream once per request.
ok¶
Returns: boolean
Checks if the response status code is > 199 AND < 300.
Example
res.ok
status¶
Returns: StatusCode
An object containing the code and the reason.
Returns: Map<String, String>
Fetch all headers.
Example
res.headers
header¶
Returns: String
A single headers value.
Example
res.header 'Content-Type'
body¶
Returns: String
Default: Encoding = UTF-8
The body as a String.
Example
res.body
body - custom charset¶
Returns: String
The body as a String, parsed using provided charset.
Example
res.body 'utf-8'
body - as bytes¶
Returns: byte[]
The body as an array of bytes.
Example
res.body true
body - stream¶
Returns: void
Enables direct streaming of the response body, using a closure.
Example
res.body { stream ->
stream.readAllBytes()
}
Examples¶
Post request
final def invoice = [name: 'testing', data: [price: 10, amount: 1]]
final def res = p6.http.post() to 'https://fake.com' json invoice send()
final boolean isOk = res.ok
final int statusCode = res.status.code
final String statusReason = res.status.reason
final String contentTypeHeader = (res.header 'Content-Type')
final String body = res.body
final def invoice = [name: 'testing', data: [price: 10, amount: 1]]
final def res = p6.http.post().to('https://fake.com').json(invoice).send()
final boolean isOk = res.ok
final int statusCode = res.status.code
final String statusReason = res.status.reason
final String contentTypeHeader = (res.header 'Content-Type')
final String body = res.body
Post with fully configure client
final Map<String, String> headerMap = [Accepts: 'application/json']
final def res = p6.http.get() from 'https://fake.com' with {
headers headerMap
identityCertPaths 'path1', 'path2'
identityPrivateKeyPath 'privateKeyPath'
sniServerName 'xyz.com'
retry 3
socketTimeout 2
connectTimeout 3
connectRequestTimeout 4
trustType 'two_way'
authCaching false
autoRetry false
cookieManagement false
} send()
final int statusCode = res.status.code
final Map<String, String> headers = res.headers
final String body = res.body
final Map<String, String> headerMap = [Accepts: 'application/json']
final def res = p6.http.get().from('https://fake.com')
.headers(headerMap)
.identityCertPaths('path1', 'path2')
.identityPrivateKeyPath('privateKeyPath')
.sniServerName('xyz.com')
.retry(3)
.socketTimeout(2)
.connectTimeout(3)
.connectRequestTimeout(4)
.trustType('two_way')
.authCaching(false)
.autoRetry(false)
.cookieManagement(false)
.send()
final int statusCode = res.status.code
final Map<String, String> headers = res.headers
final String body = res.body
Mime with configured client
final def myFile = p6.uri.fileFromUrl 'p6file://${P6_DATA}/resources/xyz.abc'
final Map<String, String> headerMap = [Accepts: 'application/json']
final def res = p6.http.post() to 'https://fake.com' with {
headers headerMap
identityPrivateKeyPath 'privateKeyPath'
sniServerName 'xyz.com'
retry 3
} mime {
file 'file1', myFile
text 'textPart', 'someTextToSend'
} send()
final int statusCode = res.status.code
final Map<String, String> headers = res.headers
final String body = res.body
final def myFile = p6.uri.fileFromUrl('p6file://${P6_DATA}/resources/xyz.abc')
final Map<String, String> headerMap = [Accepts: 'application/json']
final def res = p6.http.post().to('https://fake.com')
.headers(headerMap)
.identityPrivateKeyPath('privateKeyPath')
.sniServerName('xyz.com')
.retry(3)
.mime {
file('file1', myFile)
text('textPart', 'someTextToSend')
}.send()
final int statusCode = res.status.code
final Map<String, String> headers = res.headers
final byte[] body = res.body
Every MIME part
final def myJson = [name: 'max', address: [number: 10, road: 'fake street', region: 'Birmingham']]
final def myXml = [invoice: [amount: 10, unitCost: 5, name: 'Cheese']]
final def myFile = p6.uri.fileFromUrl 'p6file://${P6_DATA}/resources/xyz.abc'
final byte[] aByteArray = 'abcdef'.bytes
final def myStream = myFile.newDataInputStream()
final def res = p6.http.post() to 'https://fake.com' mime {
json 'jsonPart', myJson
xml 'xmlPart', myXml
file 'file1', myFile
text 'textPart', 'someTextToSend'
bytes 'bytePart', aByteArray
stream 'streamPart', myStream
} send()
final int statusCode = res.statusCode
final Map<String, String> headers = res.headers
final byte[] body = res.body
final def myJson = [name: 'max', address: [number: 10, road: 'fake street', region: 'Birmingham']]
final def myXml = [invoice: [amount: 10, unitCost: 5, name: 'Cheese']]
final def myFile = p6.uri.fileFromUrl 'p6file://${P6_DATA}/resources/xyz.abc'
final byte[] aByteArray = 'abcdef'.bytes
final def myStream = myFile.newDataInputStream()
final def res = p6.http.post().to('https://fake.com').mime {
json('jsonPart', myJson)
xml('xmlPart', myXml)
file('file1', myFile)
text('textPart', 'someTextToSend')
bytes('bytePart', aByteArray)
stream('streamPart', myStream)
}.send()
final int statusCode = res.statusCode
final Map<String, String> headers = res.headers
final String body = res.body
Get to file
final def res = p6.http.get() from 'https://picsum.photos/200' with {
headers Accepts: 'application/json'
} send()
final def bytes = res.body true
p6.file.write bytes to 'p6file://${P6_DATA}/input/file.txt'
final Map<String, String> headerMap = [Accepts: 'application/json']
def res = p6.http.get().from('https://picsum.photos/200').headers(headerMap).send()
final byte[] bytes = res.body true
FileUtils.writeByteArrayToFile(bytes, new File('p6file://${P6_DATA}/input/file.txt'));