Documentation ¶
Index ¶
- Constants
- Variables
- func ClearStartupHooks()
- func DisableMaintenance()
- func EnableMaintenance()
- func IsMaintenanceEnabled() bool
- func IsReady() bool
- func RegisterStartupHook(hook func())
- func RunTest(t *testing.T, suite ITestSuite) bool
- func Start(routeRegistrer func(*Router)) error
- func Stop()
- type Error
- type Handler
- type ITestSuite
- type Middleware
- type NativeMiddlewareFunc
- type Request
- func (r *Request) BasicAuth() (username, password string, ok bool)
- func (r *Request) BearerToken() (string, bool)
- func (r *Request) Bool(field string) bool
- func (r *Request) CORSOptions() *cors.Options
- func (r *Request) ContentLength() int64
- func (r *Request) Cookies(name string) []*http.Cookie
- func (r *Request) Date(field string) time.Time
- func (r *Request) File(field string) []filesystem.File
- func (r *Request) Has(field string) bool
- func (r *Request) Header() http.Header
- func (r *Request) IP(field string) net.IP
- func (r *Request) Integer(field string) int
- func (r *Request) Method() string
- func (r *Request) Numeric(field string) float64
- func (r *Request) Protocol() string
- func (r *Request) Referrer() string
- func (r *Request) RemoteAddress() string
- func (r *Request) Request() *http.Request
- func (r *Request) Route() *Route
- func (r *Request) String(field string) string
- func (r *Request) Timezone(field string) *time.Location
- func (r *Request) URI() *url.URL
- func (r *Request) URL(field string) *url.URL
- func (r *Request) UUID(field string) uuid.UUID
- func (r *Request) UserAgent() string
- type Response
- func (r *Response) Cookie(cookie *http.Cookie)
- func (r *Response) Download(file string, fileName string) error
- func (r *Response) Error(err interface{}) error
- func (r *Response) File(file string) error
- func (r *Response) GetError() interface{}
- func (r *Response) GetStatus() int
- func (r *Response) HandleDatabaseError(db *gorm.DB) bool
- func (r *Response) Header() http.Header
- func (r *Response) JSON(responseCode int, data interface{}) error
- func (r *Response) Redirect(url string)
- func (r *Response) Render(responseCode int, templatePath string, data interface{}) error
- func (r *Response) RenderHTML(responseCode int, templatePath string, data interface{}) error
- func (r *Response) SetWriter(writer io.Writer)
- func (r *Response) Status(status int)
- func (r *Response) String(responseCode int, message string) error
- func (r *Response) TemporaryRedirect(url string)
- func (r *Response) Write(data []byte) (int, error)
- func (r *Response) WriteHeader(status int)
- func (r *Response) Writer() io.Writer
- type Route
- type Router
- func (r *Router) CORS(options *cors.Options)
- func (r *Router) Delete(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) Get(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) GetRoute(name string) *Route
- func (r *Router) Middleware(middleware ...Middleware)
- func (r *Router) Options(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) Patch(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) Post(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) Put(uri string, handler Handler, validationRules validation.RuleSet, ...) *Route
- func (r *Router) Route(methods string, uri string, handler Handler, ...) *Route
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
- func (r *Router) Static(uri string, directory string, download bool, middleware ...Middleware)
- func (r *Router) StatusHandler(handler Handler, status int, additionalStatuses ...int)
- func (r *Router) Subrouter(prefix string) *Router
- type TestSuite
- func (s *TestSuite) ClearDatabase()
- func (s *TestSuite) ClearDatabaseTables()
- func (s *TestSuite) CreateTestFiles(paths ...string) []filesystem.File
- func (s *TestSuite) CreateTestRequest(rawRequest *http.Request) *Request
- func (s *TestSuite) CreateTestResponse(recorder http.ResponseWriter) *Response
- func (s *TestSuite) CreateTestResponseWithRequest(recorder http.ResponseWriter, rawRequest *http.Request) *Response
- func (s *TestSuite) Delete(route string, headers map[string]string, body io.Reader) (*http.Response, error)
- func (s *TestSuite) Get(route string, headers map[string]string) (*http.Response, error)
- func (s *TestSuite) GetBody(response *http.Response) []byte
- func (s *TestSuite) GetJSONBody(response *http.Response, data interface{}) error
- func (s *TestSuite) Middleware(middleware Middleware, request *Request, procedure Handler) *http.Response
- func (s *TestSuite) Patch(route string, headers map[string]string, body io.Reader) (*http.Response, error)
- func (s *TestSuite) Post(route string, headers map[string]string, body io.Reader) (*http.Response, error)
- func (s *TestSuite) Put(route string, headers map[string]string, body io.Reader) (*http.Response, error)
- func (s *TestSuite) Request(method, route string, headers map[string]string, body io.Reader) (*http.Response, error)
- func (s *TestSuite) RunServer(routeRegistrer func(*Router), procedure func())
- func (s *TestSuite) SetTimeout(timeout time.Duration)
- func (s *TestSuite) Timeout() time.Duration
- func (s *TestSuite) WriteField(writer *multipart.Writer, fieldName, value string)
- func (s *TestSuite) WriteFile(writer *multipart.Writer, path, fieldName, fileName string)
Constants ¶
const ( // ExitInvalidConfig the exit code returned when the config // validation doesn't pass. ExitInvalidConfig = 3 // ExitNetworkError the exit code returned when an error // occurs when opening the network listener ExitNetworkError = 4 // ExitHTTPError the exit code returned when an error // occurs in the HTTP server (port already in use for example) ExitHTTPError = 5 )
Variables ¶
var ( // Logger the logger for default output // Writes to stdout by default. Logger *log.Logger = log.New(os.Stdout, "", log.LstdFlags) // AccessLogger the logger for access. This logger // is used by the logging middleware. // Writes to stdout by default. AccessLogger *log.Logger = log.New(os.Stdout, "", 0) // ErrLogger the logger in which errors and stacktraces are written. // Writes to stderr by default. ErrLogger *log.Logger = log.New(os.Stderr, "", log.LstdFlags) )
Functions ¶
func DisableMaintenance ¶ added in v2.1.0
func DisableMaintenance()
DisableMaintenance replace the main server handler with the original router.
func EnableMaintenance ¶ added in v2.1.0
func EnableMaintenance()
EnableMaintenance replace the main server handler with the "Service Unavailable" handler.
func IsMaintenanceEnabled ¶ added in v2.1.0
func IsMaintenanceEnabled() bool
IsMaintenanceEnabled return true if the server is currently in maintenance mode.
func IsReady ¶
func IsReady() bool
IsReady returns true if the server has finished initializing and is ready to serve incoming requests.
func RegisterStartupHook ¶
func RegisterStartupHook(hook func())
RegisterStartupHook to execute some code once the server is ready and running.
func RunTest ¶ added in v2.2.0
func RunTest(t *testing.T, suite ITestSuite) bool
RunTest run a test suite with prior initialization of a test environment. The GOYAVE_ENV environment variable is automatically set to "test" and restored to its original value at the end of the test run. All tests are run using your project's root as working directory. This directory is determined by the presence of a "go.mod" file.
func Start ¶
Start starts the web server. The routeRegistrer parameter is a function aimed at registering all your routes and middleware.
import ( "github.com/System-Glitch/goyave/v2" "my-project/route" ) func main() { if err := goyave.Start(route.Register); err != nil { os.Exit(err.(*goyave.Error).ExitCode) } }
Errors returned can be safely type-asserted to "*goyave.Error". Panics if the server is already running.
func Stop ¶
func Stop()
Stop gracefully shuts down the server without interrupting any active connections.
Make sure the program doesn't exit and waits instead for Stop to return.
Stop does not attempt to close nor wait for hijacked connections such as WebSockets. The caller of Stop should separately notify such long-lived connections of shutdown and wait for them to close, if desired.
Types ¶
type Error ¶ added in v2.10.1
Error wrapper for errors directely related to the server itself. Contains an exit code and the original error.
type Handler ¶
Handler is a controller or middleware function
func NativeHandler ¶
NativeHandler is an adapter function for "http.Handler". With this adapter, you can plug non-Goyave handlers to your application.
Just remember that the body contains the raw data, which haven't been validated nor converted. This means that native handlers are not guaranteed to work and cannot modify the request data. Request properties, such as headers, can still be modified. Prefer implementing a Goyave handler.
This feature is a compatibility layer with the rest of the Golang web ecosystem. Prefer using Goyave handlers if possible.
type ITestSuite ¶ added in v2.2.0
type ITestSuite interface { RunServer(func(*Router), func()) Timeout() time.Duration SetTimeout(time.Duration) Middleware(Middleware, *Request, Handler) *http.Response Get(string, map[string]string) (*http.Response, error) Post(string, map[string]string, io.Reader) (*http.Response, error) Put(string, map[string]string, io.Reader) (*http.Response, error) Patch(string, map[string]string, io.Reader) (*http.Response, error) Delete(string, map[string]string, io.Reader) (*http.Response, error) Request(string, string, map[string]string, io.Reader) (*http.Response, error) T() *testing.T SetT(*testing.T) GetBody(*http.Response) []byte GetJSONBody(*http.Response, interface{}) error CreateTestFiles(paths ...string) []filesystem.File WriteFile(*multipart.Writer, string, string, string) WriteField(*multipart.Writer, string, string) CreateTestRequest(*http.Request) *Request CreateTestResponse(http.ResponseWriter) *Response // contains filtered or unexported methods }
ITestSuite is an extension of testify's Suite for Goyave-specific testing.
type Middleware ¶
Middleware function generating middleware handler function.
Request data is available to middleware, but bear in mind that it had not been validated yet. That means that you can modify or filter data. (Trim strings for example)
func NativeMiddleware ¶
func NativeMiddleware(middleware NativeMiddlewareFunc) Middleware
NativeMiddleware is an adapter function for standard library middleware.
Native middleware work like native handlers. See "NativeHandler" for more details.
type NativeMiddlewareFunc ¶ added in v2.9.0
NativeMiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
type Request ¶
type Request struct { User interface{} Rules validation.RuleSet Data map[string]interface{} Params map[string]string Lang string // contains filtered or unexported fields }
Request struct represents an http request. Contains the validated body in the Data attribute if the route was defined with a request generator function
func (*Request) BasicAuth ¶ added in v2.5.0
BasicAuth returns the username and password provided in the request's Authorization header, if the request uses HTTP Basic Authentication.
func (*Request) BearerToken ¶ added in v2.5.0
BearerToken extract the auth token from the "Authorization" header. Only takes tokens of type "Bearer". Returns empty string if no token found or the header is invalid.
func (*Request) Bool ¶
Bool get a bool field from the request data. Panics if the field is not a bool.
func (*Request) CORSOptions ¶ added in v2.3.0
CORSOptions returns the CORS options applied to this request, or nil. The returned object is a copy of the options applied to the router. Therefore, altering the returned object will not alter the router's options.
func (*Request) ContentLength ¶
ContentLength records the length of the associated content. The value -1 indicates that the length is unknown.
func (*Request) Date ¶
Date get a date field from the request data. Panics if the field is not a date.
func (*Request) File ¶
func (r *Request) File(field string) []filesystem.File
File get a file field from the request data. Panics if the field is not numeric.
func (*Request) Header ¶
Header contains the request header fields either received by the server or to be sent by the client. Header names are case-insensitive.
If the raw request has the following header lines,
Host: example.com accept-encoding: gzip, deflate Accept-Language: en-us fOO: Bar foo: two
then the header map will look like this:
Header = map[string][]string{ "Accept-Encoding": {"gzip, deflate"}, "Accept-Language": {"en-us"}, "Foo": {"Bar", "two"}, }
func (*Request) Integer ¶
Integer get an integer field from the request data. Panics if the field is not an integer.
func (*Request) Numeric ¶
Numeric get a numeric field from the request data. Panics if the field is not numeric.
func (*Request) RemoteAddress ¶
RemoteAddress allows to record the network address that sent the request, usually for logging.
func (*Request) Request ¶ added in v2.7.0
Request return the raw http request. Prefer using the "goyave.Request" accessors.
func (*Request) String ¶
String get a string field from the request data. Panics if the field is not a string.
func (*Request) Timezone ¶
Timezone get a timezone field from the request data. Panics if the field is not a timezone.
func (*Request) URI ¶
URI specifies the URI being requested. Use this if you absolutely need the raw query params, url, etc. Otherwise use the provided methods and fields of the "goyave.Request".
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response represents a controller response.
func CreateTestResponse
deprecated
func CreateTestResponse(recorder http.ResponseWriter) *Response
CreateTestResponse create an empty response with the given response writer. This function is aimed at making it easier to unit test Responses.
Deprecated: Use goyave.TestSuite.CreateTestResponse instead.
writer := httptest.NewRecorder() response := goyave.CreateTestResponse(writer) response.Status(http.StatusNoContent) result := writer.Result() fmt.Println(result.StatusCode) // 204
func (*Response) Cookie ¶
Cookie add a Set-Cookie header to the response. The provided cookie must have a valid Name. Invalid cookies may be silently dropped.
func (*Response) Download ¶
Download write a file as an attachment element. Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status 404 Not Found. The given path can be relative or absolute.
The "fileName" parameter defines the name the client will see. In other words, it sets the header "Content-Disposition" to "attachment; filename="${fileName}""
If you want the file to be sent as an inline element ("Content-Disposition: inline"), use the "File" function instead.
func (*Response) Error ¶
Error print the error in the console and return it with an error code 500. If debugging is enabled in the config, the error is also written in the response and the stacktrace is printed in the console. If debugging is not enabled, only the stauts code is set, which means you can still write to the response, or use your error status handler.
func (*Response) File ¶
File write a file as an inline element. Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status 404 Not Found. The given path can be relative or absolute.
If you want the file to be sent as a download ("Content-Disposition: attachment"), use the "Download" function instead.
func (*Response) GetError ¶ added in v2.4.0
func (r *Response) GetError() interface{}
GetError return the value which caused a panic in the request's handling, or nil.
func (*Response) GetStatus ¶ added in v2.4.0
GetStatus return the response code for this request or 0 if not yet set.
func (*Response) HandleDatabaseError ¶ added in v2.5.0
HandleDatabaseError takes a database query result and checks if any error has occurred.
Automatically writes HTTP status code 404 Not Found if the error is a "Not found" error. Calls "Response.Error()" if there is another type of error.
Returns true if there is no error.
func (*Response) JSON ¶
JSON write json data as a response. Also sets the "Content-Type" header automatically.
If a model is passed as parameter, its hidden fields will be removed.
func (*Response) Render ¶ added in v2.4.0
Render a text template with the given data. The template path is relative to the "resources/template" directory.
func (*Response) RenderHTML ¶ added in v2.4.0
RenderHTML an HTML template with the given data. The template path is relative to the "resources/template" directory.
func (*Response) SetWriter ¶ added in v2.7.0
SetWriter set the writer used to write the response. This can be used to chain writers, for example to enable gzip compression, or for logging.
The original http.ResponseWriter is always kept.
func (*Response) Status ¶
Status set the response status code. Calling this method a second time will have no effect.
func (*Response) TemporaryRedirect ¶
TemporaryRedirect send a temporary redirect response
func (*Response) WriteHeader ¶
WriteHeader sends an HTTP response header with the provided status code. Prefer using "Status()" method instead. Calling this method a second time will have no effect.
type Route ¶ added in v2.6.0
type Route struct {
// contains filtered or unexported fields
}
Route stores information for matching and serving.
func (*Route) BuildURL ¶ added in v2.6.0
BuildURL build a full URL pointing to this route. Panics if the amount of parameters doesn't match the amount of actual parameters for this route.
func (*Route) GetFullURI ¶ added in v2.6.0
GetFullURI get the full URI of this route.
Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client.
func (*Route) GetMethods ¶ added in v2.6.0
GetMethods returns the methods the route matches against.
func (*Route) GetURI ¶ added in v2.6.0
GetURI get the URI of this route. The returned URI is relative to the parent router of this route, it is NOT the full path to this route.
Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router registers routes to be matched and executes a handler.
func (*Router) CORS ¶ added in v2.3.0
CORS set the CORS options for this route group. If the options are not nil, the CORS middleware is automatically added.
func (*Router) Delete ¶ added in v2.10.0
func (r *Router) Delete(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Delete registers a new route wit the DELETE method.
func (*Router) Get ¶ added in v2.10.0
func (r *Router) Get(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Get registers a new route wit the GET method.
func (*Router) GetRoute ¶ added in v2.6.0
GetRoute get a named route. Returns nil if the route doesn't exist.
func (*Router) Middleware ¶
func (r *Router) Middleware(middleware ...Middleware)
Middleware apply one or more middleware to the route group.
func (*Router) Options ¶ added in v2.10.0
func (r *Router) Options(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Options registers a new route wit the OPTIONS method.
func (*Router) Patch ¶ added in v2.10.0
func (r *Router) Patch(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Patch registers a new route wit the PATCH method.
func (*Router) Post ¶ added in v2.10.0
func (r *Router) Post(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Post registers a new route wit the POST method.
func (*Router) Put ¶ added in v2.10.0
func (r *Router) Put(uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Put registers a new route wit the PUT method.
func (*Router) Route ¶
func (r *Router) Route(methods string, uri string, handler Handler, validationRules validation.RuleSet, middleware ...Middleware) *Route
Route register a new route.
Multiple methods can be passed using a pipe-separated string.
"PUT|PATCH"
The validation rules set is optional. If you don't want your route to be validated, pass "nil".
If the router has CORS options set, the "OPTIONS" method is automatically added to the matcher if it's missing, so it allows preflight requests.
Returns the generated route.
func (*Router) ServeHTTP ¶ added in v2.6.0
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
ServeHTTP dispatches the handler registered in the matched route.
func (*Router) Static ¶
func (r *Router) Static(uri string, directory string, download bool, middleware ...Middleware)
Static serve a directory and its subdirectories of static resources. Set the "download" parameter to true if you want the files to be sent as an attachment instead of an inline element.
If no file is given in the url, or if the given file is a directory, the handler will send the "index.html" file if it exists.
func (*Router) StatusHandler ¶ added in v2.4.0
StatusHandler set a handler for responses with an empty body. The handler will be automatically executed if the request's life-cycle reaches its end and nothing has been written in the response body.
Multiple status codes can be given. The handler will be executed if one of them matches.
This method can be used to define custom error handlers for example.
Status handlers are inherited as a copy in sub-routers. Modifying a child's status handler will not modify its parent's.
Codes in the 400 and 500 ranges have a default status handler.
type TestSuite ¶ added in v2.2.0
TestSuite is an extension of testify's Suite for Goyave-specific testing.
func (*TestSuite) ClearDatabase ¶ added in v2.2.0
func (s *TestSuite) ClearDatabase()
ClearDatabase delete all records in all tables. This function only clears the tables of registered models.
func (*TestSuite) ClearDatabaseTables ¶ added in v2.5.0
func (s *TestSuite) ClearDatabaseTables()
ClearDatabaseTables drop all tables. This function only clears the tables of registered models.
func (*TestSuite) CreateTestFiles ¶ added in v2.2.0
func (s *TestSuite) CreateTestFiles(paths ...string) []filesystem.File
CreateTestFiles create a slice of "filesystem.File" from the given paths. Files are passed to a temporary http request and parsed as Multipart form, to reproduce the way files are obtained in real scenarios.
func (*TestSuite) CreateTestRequest ¶ added in v2.2.0
CreateTestRequest create a "goyave.Request" from the given raw request. This function is aimed at making it easier to unit test Requests.
If passed request is "nil", a default GET request to "/" is used.
rawRequest := httptest.NewRequest("GET", "/test-route", nil) rawRequest.Header.Set("Content-Type", "application/json") request := goyave.CreateTestRequest(rawRequest) request.Lang = "en-US" request.Data = map[string]interface{}{"field": "value"}
func (*TestSuite) CreateTestResponse ¶ added in v2.2.0
func (s *TestSuite) CreateTestResponse(recorder http.ResponseWriter) *Response
CreateTestResponse create an empty response with the given response writer. This function is aimed at making it easier to unit test Responses.
writer := httptest.NewRecorder() response := suite.CreateTestResponse(writer) response.Status(http.StatusNoContent) result := writer.Result() fmt.Println(result.StatusCode) // 204
func (*TestSuite) CreateTestResponseWithRequest ¶ added in v2.7.0
func (s *TestSuite) CreateTestResponseWithRequest(recorder http.ResponseWriter, rawRequest *http.Request) *Response
CreateTestResponseWithRequest create an empty response with the given response writer HTTP request. This function is aimed at making it easier to unit test Responses needing the raw request's information, such as redirects.
writer := httptest.NewRecorder() rawRequest := httptest.NewRequest("POST", "/test-route", strings.NewReader("body")) response := suite.CreateTestResponseWithRequest(writer, rawRequest) response.Status(http.StatusNoContent) result := writer.Result() fmt.Println(result.StatusCode) // 204
func (*TestSuite) Delete ¶ added in v2.2.0
func (s *TestSuite) Delete(route string, headers map[string]string, body io.Reader) (*http.Response, error)
Delete execute a DELETE request on the given route. Headers and body are optional.
func (*TestSuite) Get ¶ added in v2.2.0
Get execute a GET request on the given route. Headers are optional.
func (*TestSuite) GetBody ¶ added in v2.2.0
GetBody read the whole body of a response. If read failed, test fails and return empty byte slice.
func (*TestSuite) GetJSONBody ¶ added in v2.2.0
GetJSONBody read the whole body of a response and decode it as JSON. If read or decode failed, test fails.
func (*TestSuite) Middleware ¶ added in v2.2.0
func (s *TestSuite) Middleware(middleware Middleware, request *Request, procedure Handler) *http.Response
Middleware executes the given middleware and returns the HTTP response. Core middleware (recovery, parsing and language) is not executed.
func (*TestSuite) Patch ¶ added in v2.2.0
func (s *TestSuite) Patch(route string, headers map[string]string, body io.Reader) (*http.Response, error)
Patch execute a PATCH request on the given route. Headers and body are optional.
func (*TestSuite) Post ¶ added in v2.2.0
func (s *TestSuite) Post(route string, headers map[string]string, body io.Reader) (*http.Response, error)
Post execute a POST request on the given route. Headers and body are optional.
func (*TestSuite) Put ¶ added in v2.2.0
func (s *TestSuite) Put(route string, headers map[string]string, body io.Reader) (*http.Response, error)
Put execute a PUT request on the given route. Headers and body are optional.
func (*TestSuite) Request ¶ added in v2.2.0
func (s *TestSuite) Request(method, route string, headers map[string]string, body io.Reader) (*http.Response, error)
Request execute a request on the given route. Headers and body are optional.
func (*TestSuite) RunServer ¶ added in v2.2.0
RunServer start the application and run the given functional test procedure.
This function is the equivalent of "goyave.Start()". The test fails if the suite's timeout is exceeded. The server automatically shuts down when the function ends. This function is synchronized, that means that the server is properly stopped when the function returns.
func (*TestSuite) SetTimeout ¶ added in v2.2.0
SetTimeout set the timeout for test failure when using RunServer or requests.
func (*TestSuite) Timeout ¶ added in v2.2.0
Timeout get the timeout for test failure when using RunServer or requests.
func (*TestSuite) WriteField ¶ added in v2.2.0
WriteField create and write a new multipart form field. The test fails if the field couldn't be written.