** 'Butter' instances route HTTP requests through a stack of middleware.
mixin Butter {
** A const value representing HTTP 1.0
static const Version http10 := Version("1.0")
** A const value representing HTTP 1.1
static const Version http11 := Version("1.1")
** Makes a request and returns the response.
abstract ButterResponse sendRequest(ButterRequest req)
** Returns an instance of the given middleware type as used by the
abstract ButterMiddleware? findMiddleware(Type middlewareType, Bool checked := true)
** Returns a (modifiable) list of middleware instances used by this 'Butter'
abstract ButterMiddleware[] middleware()
** Builds a pack of butter from the given middleware stack.
** The ordering of the stack *is* important.
static Butter churnOut(ButterMiddleware[] middleware := defaultStack) {
return ButterChain(middleware)
}
** The default middleware stack. It currently returns new instances of (in order):
** - `StickyHeadersMiddleware`
** - `GzipMiddleware`
** - `BasicAuthMiddleware`
** - `FollowRedirectsMiddleware`
** - `StickyCookiesMiddleware`
** - `ErrOn4xxMiddleware`
** - `ErrOn5xxMiddleware`
** - `ProxyMiddleware`
** - `HttpTerminator`
static ButterMiddleware[] defaultStack() {
ButterMiddleware[
StickyHeadersMiddleware(),
GzipMiddleware(),
BasicAuthMiddleware(),
FollowRedirectsMiddleware(),
StickyCookiesMiddleware(), // as cookies can come with a re-direct command, Cookie middleware needs to come *before* Redirect middleware
ErrOn4xxMiddleware(),
ErrOn5xxMiddleware(),
ProxyMiddleware(),
HttpTerminator()
]
}
** Makes a simple HTTP get request to the given URL and returns the response.
virtual ButterResponse get(Uri url) {
sendRequest(ButterRequest(url))
}
** Makes a HTTP POST request to the URL with the given form data.
** The 'Content-Type' HTTP header is set to 'application/x-www-form-urlencoded'.
virtual ButterResponse postForm(Uri url, Str:Str form) {
sendRequest(ButterRequest(url) {
it.method = "POST"
it.body.form = form
})
}
** Makes a HTTP POST request to the URL with the given String.
** The 'Content-Type' HTTP header is set to 'text/plain'.
virtual ButterResponse postStr(Uri url, Str content, Charset charset := Charset.utf8) {
sendRequest(ButterRequest(url) {
it.method = "POST"
it.body.str = content
it.body.charset = charset
})
}
** Makes a HTTP POST request to the URL with the given JSON Str.
** The 'Content-Type' HTTP header is set to 'application/json'.
virtual ButterResponse postJson(Uri url, Str? json) {
sendRequest(ButterRequest(url) {
it.method = "POST"
it.body.json = json
})
}
** Makes a HTTP POST request to the URL with the given JSON Obj.
** The 'Content-Type' HTTP header is set to 'application/json'.
virtual ButterResponse postJsonObj(Uri url, Obj? jsonObj) {
sendRequest(ButterRequest(url) {
it.method = "POST"
it.body.jsonObj = jsonObj
})
}
** Makes a HTTP POST request to the URL with the given file.
** The 'Content-Type' HTTP header is set from the file extension's MIME type, or 'application/octet-stream' if unknown.
virtual ButterResponse postFile(Uri url, File file) {
sendRequest(ButterRequest(url) {
it.method = "POST"
it.headers.contentType = file.mimeType ?: MimeType("application/octet-stream")
it.body.buf = file.readAllBuf
})
}
** Makes a HTTP PUT request to the URL with the given String.
** The 'Content-Type' HTTP header is set to 'text/plain'.
virtual ButterResponse putStr(Uri url, Str content, Charset charset := Charset.utf8) {
sendRequest(ButterRequest(url) {
it.method = "PUT"
it.body.str = content
it.body.charset = charset
})
}
** Makes a HTTP PUT request to the URL with the given JSON string.
** The 'Content-Type' HTTP header is set to 'application/json'.
virtual ButterResponse putJson(Uri url, Str? json) {
sendRequest(ButterRequest(url) {
it.method = "PUT"
it.body.json = json
})
}
** Makes a HTTP PUT request to the URL with the given JSON Obj.
** The 'Content-Type' HTTP header is set to 'application/json'.
virtual ButterResponse putJsonObj(Uri url, Obj? jsonObj) {
sendRequest(ButterRequest(url) {
it.method = "PUT"
it.body.jsonObj = jsonObj
})
}
** Makes a simple HTTP DELETE request to the given URL and returns the response.
virtual ButterResponse delete(Uri url) {
sendRequest(ButterRequest(url) {
it.method = "DELETE"
})
}
@NoDoc
override Obj? trap(Str name, Obj?[]? args := null) {
middleware.find |mw->Bool| {
if (mw.typeof.name.equalsIgnoreCase(name))
return true
if (mw.typeof.name.lower.endsWith("middleware"))
if (mw.typeof.name[0..<-"middleware".size].equalsIgnoreCase(name))
return true
return false
} ?: throw ButterErr(ErrMsgs.chainMiddlewareNotFound(name), middleware.map { it.typeof.name })
}
}