Skip to content

Http

Purpose

Enables the sending of http requests.

Methods

Binding name: p6.http


TLDR

  1. Specify method

    def response = p6.http.post()
    
  2. Specify URL

    def response = p6.http.post() to 'https://myurl.com'
    
  3. Add request body (optional)

    def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5
    
  4. Configure request

    def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5 socketTimeout 3 sniServerName 'myurl2.com'
    
  5. Send

    def response = p6.http.post() to 'https://myurl.com' json id: 'xyz', amount: 5 socketTimeout 3 sniServerName 'myurl2.com' send()
    
  6. 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'
Accepts multiple, comma-seperated paths
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.

Example

res.status.code
res.status.reason

headers

Returns: Map<String, String>

Fetch all headers.

Example

res.headers

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'));