# form-data2

A Streams2-compatible drop-in replacement for the `form-data` module. Through the wrapping done by the underlying `combined-stream2` module, old-style streams are also supported.

Takes a number of streams or Buffers, and turns them into a valid `multipart/form-data` stream.

## License

[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer. A donation and/or attribution are appreciated, but not required.

## Donate

My income consists entirely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)!

You can donate using Bitcoin, PayPal, Gratipay, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else.

## Contributing

Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the `.coffee` files, not the `.js` files.

Build tool of choice is `gulp`; simply run `gulp` while developing, and it will watch for changes.

Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.

## Migrating from `form-data`

While `form-data2` was designed to be roughly API-compatible with the `form-data` module, there are a few notable differences:

* `form-data2` does __not__ do HTTP requests. It is purely a multipart/form-data encoder. This means you should use a different module for your HTTP requests, such as [`bhttp`](https://www.npmjs.com/package/bhttp), [`request`](https://www.npmjs.com/package/request), or the core `http` module. `bhttp` uses `form-data2` internally - that means you won't have to manually use `form-data2`.
* The `header` option for the `form.append()` options object is not (yet) implemented. This means that you cannot currently set custom field headers.
* There is no `form.getLengthSync()` method. Length retrieval is always asynchronous.
* The `form.getHeaders` method is __always asynchronous__ (whereas in the original `form-data`, it is synchronous). Due to the requirements for obtaining the stream length reliably, there is no synchronous equivalent.
* A `form-data2` stream is not a real stream. Only the `form.pipe()` method is implemented, other stream methods are unavailable. This may change in the future.

## Usage

```javascript
var FormData = require('form-data2');
var fs = require('fs');

var form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
```

### Getting the HTTP headers

```javascript
Promise = require("bluebird");
util = require("util");

Promise.try(function(){
	form.getHeaders();
}).then(function(headers){
	console.log("Stream headers:", util.inspect(headers));
}).catch(function(err){
	console.log("Something went wrong!");
});
```

... or using nodebacks:

```javascript
form.getHeaders(function(err, headers){
	if(err) {
		console.log("Something went wrong!");
	} else {
		console.log("Stream headers:", util.inspect(headers));
	}
});
```

## API

Note that this is __not__ a real stream, and does therefore not expose the regular `stream.Readable` properties. The `pipe` method will simply pipe the underlying `combined-stream2` stream into the specified target. If you want to access the stream directly for some reason, use `form._stream`.

### append(name, source, [options])

Adds a new data source to the multipart/form-data stream.

This module will *not* automatically handle arrays for you - if you need to send an array, you will need to call this method for each element individually, using the same `[]`-suffixed field name for each element.

* __name__: The name of the form field.
* __source__: The data source to add. This can be a stream, a Buffer, or a UTF-8 string.
* __options__: *Optional.* Additional options for the stream.
	* __contentLength__: The total length of the stream. Useful if your stream is of a type that [`stream-length`](https://www.npmjs.com/package/stream-length) can't automatically determine the length of. Also available under the alias `knownLength`, for backwards compatibility reasons.
	* __contentType__: The MIME type of the source. It's recommended to *always* specify this manually; however, if it's not supplied, `form-data2` will attempt to determine it for you where possible.
	* __filename__: The filename of the source, if it is a file or should be represented as such. It's recommended to *always* specify this manually (if the source is a file of some sort); however, if it's not supplied, `form-data2` will attempt to determine it for you where possible.

### getHeaders([callback])

Asynchronously returns the HTTP request headers that you will need to successfully transmit this stream, as an object.

All object keys are lower-case. To use the headers, simply merge them into the headers object for your request.

If you specify a `callback`, it will be treated as a nodeback. If you do *not* specify a `callback`, a Promise will be returned.

### pipe(target)

Pipes the `multipart/form-data` stream into the `target` stream.

### done()

__You probably don't need to call this.__

Calling this method will append the multipart/form-data footer to the stream. It is called automatically when you `pipe` the stream into something else.

### getBoundary()

__You probably don't need to call this.__

Returns the form boundary used in the `multipart/form-data` stream.

### getLength([callback])

__You probably don't need to call this.__

Asynchronously returns the total length of the stream in bytes.

If you specify a `callback`, it will be treated as a nodeback. If you do *not* specify a `callback`, a Promise will be returned.

## Changelog

### v1.0.4 (February 18, 2020)

- Added this changelog to the README
- Removed Lodash, resolving the audit warnings
- Removed CoffeeScript
- Removed Gulp

### v1.0.3 (March 17, 2015)

- Added documentation about asynchronicity of `form.getHeaders`

### v1.0.2 (January 23, 2015)

- Fixed packaging mistake (again)

### v1.0.1 (January 23, 2015)

- Fixed packaging mistake

### v1.0.0 (January 22, 2015)

Initial release.
