- Added
debugUrl
toWebSocketConnectEvent
which is emitted via theGlobalWebSocketMonitor
. When using SockJS, this will be populated with the full URL that the underlying transport is using, which can be useful information for debugging.
- Added
defaultTimeoutThreshold
top level field to add a timeout for all requests by default.
- Made
RequestException.request
nullable and re-add the null check, as we found unsound consumer usages where this could be null. - Bumped
collection
dependency to a non-pre-release version.
- Updated to null safety:
- Made as much of the public API non-nullable as safely possible.
- One notable behavioral change that was required in order to make the request
dispatch methods (like
.get()
and.post()
) return non-nullable: if any response interceptor takes a non-null response but returns a null response, the original non-null response will be used instead. In practice, we don't think this is common, and being able to make request methods return non-nullable was worth it.
- Bug Fix: When using
MockTransports.install(fallThrough: true)
, the optionalbody
param on thesend()
method will now properly be applied when the request "falls through" the mock config to a real request. - Docs: Suggest using
.streamGet()
over.get()
for binary responses that will be read as bytes (viabody.asBytes()
).
- Widen ranges on
fluri
andhttp_parser
- Improvement JSON content will always decode as utf-8. Previously it would fall back to the encoding specified for the body, or to ISO-8859-1, which was the old fallback value. There is no longer any fallback value, per rfc7231, but it uses the media type value, which for JSON is by default UTF-8.
- Improvement:
AutoRetryConfig
gained theincreaseTimeoutOnRetry
flag. This allows timeouts to increase as retry attempts increase.
- Update the changelog
- Tech Debt: Release automation fixes
- Tech Debt: Widen dependency ranges #370
- Tech Debt: Release automation fixes
- Tech Debt: Documentation updates.
- Tech Debt: Update deprecated dart CLI commands.
- Bug Fix: The
body
parameter given toRequest.send()
was being ignored. It should now be used as expected.
- Improvement: Implement equality for
RegExp
to ensure 2 mock request handlers with the same pattern and regex settings are stored in a common map.
This is a major release with breaking changes.
Previously, this project included a sockjs_client
dependency via a git
reference, but in July of 2019 pub.dev began disallowing the publishing
of packages with git dependencies. Additionally, this package included public
APIs that depended on this git dependency. We are unable to get this dependency
moved to pub.dev, so our only option is to release a major version and
remove our usage of this dependency and any relevant APIs.
We also had some pre-existing deprecations that we are removing in this major release.
With only a couple of exceptions, this 4.0.0 version should be backwards- compatible with 3.x.x as long as uses of deprecated APIs have been resolved.
- Breaking: Consumers of the SockJS implementation behind
WebSocket
must now includesockjs.js
on the page: - Breaking: Removed the following deprecated APIs:
- The
WSocket
class. UseWebSocket
instead. WSocketCloseEvent
WSocketException
- The SockJS optional parameters (e.g.
useSockJS
orsockJSProtocolsWhitelist
) for:configureWTransportForBrowser()
WebSocket.connect()
- The
- Improvement: Be robust to empty contentType header on response.
- Improvement: The jitter approach used previously for exponential backoffs still leads to peaks in server load. This is now improved by adopting a more advanced backoff algorithm from Polly.
- Improvement: Added
closeCode
andcloseReason
getters toMockWebSocketServer
. - Improvement: prep for a breaking change in Dart SDK to
HttpRequest
andHttpClientResponse
- Tech-debt: upgrade to
dart_dev
v3 - Tech-debt: use
workiva_analysis_options
to simplify linter/analysis configuration. - Tech-debt: remove Dart 1 support
- Tech-debt: upgrade to
dart_dev
v2
October 10th, 2018
- Improvement: Dart 2 compatible!
July 19th, 2018
-
Bug Fix: When using
MockTransports
withfallThrough: true
, requests that fall through now properly copy overcontentLength
andcontentType
if applicable. -
Dependency: Upgraded minimum
sockjs_client_wrapper
version to 1.0.4 in order to pull in SockJS v1.1.5.
May 17th, 2018
-
Bug Fix: The previous version introduced a new transformer for the w_transport examples, but did not properly scope it to the
examples/
directory. This led to the following error during apub get
for some consumers:Precompiling dependencies... Loading source assets... Error on line 1, column 1 of https://pub.dartlang.org/api/packages/w_transport: Error loading transformer "over_react": package "over_react" is not a dependency.
This has been fixed. If you're still seeing this error, run
pub upgrade w_transport
to make sure you have the latest.
May 16th, 2018
- Bug Fix: The browser implementation of
MultipartRequest
was previously adding every field to theFormData
twice - this has been fixed.
April 25th, 2018
- Improvement: Now compatible with Dart 2 and the Dart Dev Compiler.
April 20th, 2018
- Documentation: Fixed some broken links.
January 29th, 2018
- Bug Fix: The
sockjs.js
detection now usescontext.hasProperty()
instead of actually trying to access theSockJS
object on the window. This fixes an exception that was being thrown silently in certain situations.
January 4th, 2018
-
Improvement: Added support for the
sockjs_client_wrapper
package. This will eventually replace our usage of thesockjs_client
Dart port because the wrapper uses the actual JS library which is fully-featured and community supported.The SockJS wrapper requires that the JS library be included in the HTML page. To avoid a breaking change, it will only be used if the JS library is detected on the window.
If you are using the SockJS configuration for
WebSocket
and wish to leverage this more fully-featured SockJS (which provides all of the SockJS protocols e.g.xhr-polling
), all you need to do is add the JS script to your application page:https://github.com/workiva/sockjs_client_wrapper#usage
If you don't change anything, the SockJS configuration for
WebSocket
will still behave exactly the same and you should see no difference.
March 15th, 2017
- Bug Fix: When a request is canceled, it will now always result in the
done
Future resolving. Previously it was possible for thedone
Future to never resolve if the request was canceled at a certain point during the request lifecycle.
February 3rd, 2017
- Bug Fix: When
MockTransports
is installed with "fall-through" enabled, the optional SockJS params that are available on thenew transport.WebSocket()
constructor are now properly passed through. Previously, a standard WebSocket implementation would have been constructed erroneously ifuseSockJS: true
was set, but it now correctly constructs the SockJS implementation.
January 18th, 2017
- Bug Fix: If a request's
autoRetry.test
function is supplied and returns true when theresponse
is null, a request that was canceled would erroneously be retried. Canceling a request now properly makes it ineligible for retry regardless of other factors.
October 25th, 2016
This major release includes deprecations and an increased minimum Dart SDK version. This release should be backwards compatible with version 2.x.
To upgrade, check out the v3.0.0 upgrade guide.
-
There is a new pattern for configuring
w_transport
for a particular platform. Check out the Transport Platform Configuration guide. -
There is a new way to install the transport mocks (instead of
configureWTransportForTest()
). Check out the Mock Transports Installation guide.
-
Renamed entry points:
w_transport_browser.dart
-->browser.dart
w_transport_mock.dart
-->mock.dart
w_transport_vm.dart
-->vm.dart
-
Other renames:
Client
-->HttpClient
WSocket
-->WebSocket
WSocketException
-->WebSocketException
RetryBackOff.duration
-->RetryBackOff.interval
-
Other deprecations:
WSocketCloseEvent
MockBaseRequest
MockClient
MockFormRequest
MockJsonRequest
MockPlainTextRequest
MockResponse
MockStreamedRequest
MockStreamedResponse
MockWSocket
- The
w_transport
documentation has been revamped with an emphasis on examples and guides. Check them out now!
October 14, 2016
- Bug Fix: The
Future
returned fromWSocket.cancel()
no longer waits for the WebSocket to be closed.
September 8, 2016
- Bug Fix: if a request is canceled right before it would also have exceeded
the timeout threshold, a
StateError
may be thrown due to aCompleter
being completed more than once. This is fixed now.
August 11, 2016
- Widen the version range for the
http_parser
dependency to speed up and/or fix downstream consumers experiencing version conflicts.
August 2, 2016
- Bug Fix: previously, listening to a
WSocket
instance and then canceling the subscription before closing the socket would result in the "done" state never being reached. This is fixed now and theFuture
returned fromWSocket.done
andWSocket.close()
will always resolve once the connection is closed.
July 26, 2016
-
Improvement: All request classes now have a
bool isDone
getter that can be read to determine whether or not a request is complete (i.e. succeeded, failed, or canceled). -
Bug Fix: Calling
request.abort()
more than once will no longer throw aStateError
.
July 21, 2016
-
Improvement: Mock transport handlers can now be canceled. This will allow consumers to remove HTTP or WebSocket mock handlers without having to call
MockTransports.reset()
orMockTransports.uninstall
.var uri = Uri.parse('/example'); var myHttpHandler = MockTransports.http.when(uri, (request) { ... }); myHttpHandler.cancel(); var myWebSocketHandler = MockTransports.webSocket.when(uri, handler: (protocols, headers) { ... }); myWebSocketHandler.cancel(); /// The same works for the `whenPattern()` methods, as well.
July 20, 2016
-
Bug Fix: previously, you could not retry a request that failed with a
null
response. This is now allowed, but still has the same default behavior. To retry a request with anull
response, use theautoRetry.test
method accordingly:var request = new Request(); request.autoRetry ..enabled = true ..test = (request, response, willRetry) { if (response == null) return true; return willRetry; };
June 23, 2016
-
Deprecation:
autoRetry.backOff.duration
has been deprecated in favor of the more aptly namedautoRetry.backOff.interval
. -
Improvement: Automatic request retrying will now add jitter to the backoff intervals by default. To disable jitter, set
autoRetry.backOff.withJitter = false;
. -
Improvement: You can now put a cap on the backoff interval used during automatic request retrying.
request.autoRetry.backOff.maxInterval = new Duration(minutes: 2);
-
Bug Fix: A request's
encoding
property can no longer be set to null. This would have most likely caused an RTE when the request was sent, so now anArgumentError
will be thrown immediately. -
Bug Fix: As of 2.6.0, if you were to set a request's content-type manually without a charset or with an unknown charset, it was possible to hit an RTE due to a null
encoding
. TheHttpBody
class has been updated to be more resilient to a missing encoding or charset. Additionally, all request classes will now pass in the value of itsencoding
property, which should now always be non-null.
June 20, 2016
-
Improvement: The
MockTransport
utilities now support expecting and registering handlers for HTTP requests and WS connections that match aPattern
instead of exactly matching a URI. Handlers will also receive theMatch
instance.var response = new MockResponse.ok(); var webSocket = new MockWSocket(); var uriPattern = new RegExp('(http|ws)s:\/\/example.com\/(.*)'); // Capture any GET request to example.com/ MockTransports.http.expectPattern('GET', uriPattern, respondWith: response); // Register a handler for any GET request to https://example.com/ // The `Match` instance will be given to the handler, where it can be used // to read any of the captured groups. MockTransports.http.whenPattern(uriPattern, (request, match) async { print('path: ${match.group(2)}'); return response; }, method: 'GET'); // Capture any WS connection attempt to example.com/ MockTransports.webSocket.expectPattern(uriPattern, connectTo: webSocket); // Register a handler for an WS connection attempt to example.com/ // The `Match` instance will be given to the handler, where it can be used // to read any of the captured groups. MockTransports.webSocket.whenPattern(uriPattern, handler: (uri, {protocols, headers, match}) async { print('path: ${match.group(2)}'); return webSocket; });
-
Improvement: the content-type for HTTP requests can now be set manually.
var request = new Request() ..uri = Uri.parse('/example') ..contentType = new MediaType('application', 'x-custom', {'charset': UTF8.name});
-
The content-type still has a default value based on the type of request (
Request
- text/plain,JsonRequest
- application/json, etc.). -
The content-type's charset parameter will still be updated automatically when you set the
encoding
, but once you manually setcontentType
, this behavior will stop. In other words, we are assuming that if you setcontentType
manually, you are intentionally overriding the defaults and are taking responsibility of setting thecharset
parameter appropriately.
-
-
Bug Fix: the
StreamedRequest
now properly verifies that the request has not been sent when settingcontentType
. It will now throw aStateError
like the rest of the request types.
June 16, 2016
- Error Messaging: When a response body cannot be properly decoded/encoded
using the
Encoding
dictated by thecontent-type
header, aResponseFormatException
will now be thrown with a much more descriptive message. The content-type, encoding, and body will be included.
June 15, 2016
-
Bug Fix:
WSocket
extendsStream
andStreamSink
, but was not fulfilling those contracts in all scenarios. In particular:-
After obtaining a
StreamSubscription
instance from a call toWSocket.listen()
, reassigning theonData()
,onError()
, andonDone()
handlers had no effect.var webSocket = await WSocket.connect(...); var subscription = webSocket.listen((data) { ... }); // This does nothing: subscription.onData((data) { ... }); // Same goes for onError() and onDone()
-
A subscription to a
WSocket
instance did not properly respect pause and resume signals. This could produce a memory leak by buffering WebSocket events indefinitely. -
A
WSocket
instance was immediately listening to the underlying WebSocket and buffering events from the underlying WebSocket until a listener was registered. This is not how a standard DartStream
works. -
The SockJS configuration was not properly handling the fact that the SockJS
Client
produces WebSocket events with a broadcast stream. -
All of these issues have been addressed, and every
WSocket
instance should now behave exactly as a standardStream
andStreamSink
would, regardless of the platform (VM, browser, SockJS, or mock).
-
The
WSocketCloseEvent
class has been deprecated. This class was only used internally and should not have been exported as a part of the public API.
The WSocket implementations are no longer registering an
onError
handler for the underlying WebSocket stream. If an error occurs on the server, it will not add the error to the stream, it will just close the connection. As a result, theMockWSocket.triggerServerError()
method has been deprecated - useMockWSocket.triggerServerClose()
instead.
May 4, 2016
-
Improvement:
FormRequest
now supports fields with multiple values.var request = new FormRequest() ..fields['multi'] = ['one', 'two'];
-
SDK Compatibility: Dart 1.16 exposed a new
Client
class from thedart:html
library that conflicted with theClient
class in this library. This has been fixed by adjusting our imports internally, but it may still affect consumers of this library. -
Documentation: fixed inaccurate documentation around mocking & testing with WebSockets.
March 2, 2016
- Bug Fix: requests created from a
Client
now properly inherit all of theautoRetry
configuration. Previously thebackOff
,forTimeouts
, andmaxRetries
settings were missing.
February 11, 2016
-
Implemented retry back-off to allow fixed or exponential back-off between request retries. By default, there is no back-off.
// Fixed back-off: 1 second between attempts. var request = new Request(); request.autoRetry ..enabled = true ..backOff = new RetryBackOff.fixed(new Duration(seconds: 1)); // Exponential back-off: 250ms, 500ms, 1s, 2s, etc (base*2^attempt) var request = new Request(); request.autoRetry ..enabled = true ..backOff = new RetryBackOff.exponential(new Duration(milliseconds: 125));
-
Added methods to all request classes for manually retrying failures. This is mainly useful for corner cases where the request's success is dependent on something else and where automatic retrying won't help.
var request = new Request(); // send request, catch failure var response = await request.retry(); // normal var response = await request.streamRetry(); // streamed
-
Improved error messaging around failed requests. If automatic retrying is enabled, the error message for a failed request will include each individual attempt and why it failed.
February 8, 2016
-
Added an
autoRetry.forTimeouts
flag (defaults totrue
) to theClient
class and all request classes. This flag determines whether or not requests that are canceled due to exceeding the timeout threshold should be retried.// This request will retry if the timeout is exceeded. var request = new Request() ..timeoutThreshold = new Duration(seconds: 10) ..autoRetry.enabled = true; // This request will NOT retry if the timeout is exceeded. var request = new Request() ..timeoutThreshold = new Duration(seconds: 10) ..autoRetry.enabled = true ..autoRetry.forTimeouts = false;
-
Added a
Duration sockJSTimeout
config option toWSocket.connect()
.// browser only var socket = await WSocket.connect(Uri.parse('...'), useSockJS: true, sockJSTimeout: new Duration(seconds: 5));
January 7, 2016
As of v2.0.0, this library could be configured to use SockJS under the hood when
the WSocket
class was used to establish WebSocket connections. This
configuration occurred on a global basis (meaning it affected every WSocket
instance) which is undesirable for applications with a mixed usage of native
WebSockets and SockJS. This global configuration has been deprecated.
As of v2.1.0, passing useSockJS: true
to the configureWTransportForBrowser()
method will cause a deprecation warning to be printed to the console.
The SockJS configuration should now occur on a per-socket basis via the
WSocket.connect()
method:
Uri uri = Uri.parse('ws://echo.websocket.org');
WSocket webSocket = await WSocket.connect(uri,
useSockJS: true, sockJSProtocolsWhitelist: ['websocket', 'xhr-streaming']);
-
Added a
baseUri
field toClient
that all requests from the client will inherit. -
All request classes now support a timeout threshold via the
timeoutTreshold
field. This was also added to theClient
class and all requests created from a client will inherit this value. -
Request and response interception is now supported. This can be done directly on a request instance, but more usefully through a
Client
instance. See "request & response interception" and "intercepting requests & responses from a client" in the README. -
All request classes and the
Client
class now include an API for automatic retrying via theautoRetry
field. See "automatic request retrying" in the README. -
Added a
replace
method toResponse
andStreamedResponse
to allow simple creation of new responses based on another response, while changing only the fields you specify. This is particularly useful during response interception.
- Headers passed into a request's dispatch method (ex:
.get(headers: {...})
) are now merged with any existing headers on the request (previously they were being ignored).
November 24, 2015
The 2.0.0 release is a major breaking release. While many of the patterns from 1.0.x were maintained, the HTTP API was broken up into several request classes and two response classes for a much more robust and useful API. As such, there is no backwards compatibility, but a migration guide is included below.
-
WebSockets
- Single API for the browser and the Dart VM.
- Option to use SockJS library in place of native WebSockets for the ability to fall back to XHR streaming (configuration only, no API usage difference).
-
HTTP
- Support for most commonly used request types:
Request
(content-type: text/plain)JsonRequest
(content-type: application/json)FormRequest
(content-type: application/x-www-form-urlencoded)MultipartRequest
(content-type: multipart/form-data)
- Synchronous access to response bodies as bytes, text, and JSON.
- Asynchronous request bodies (
StreamedRequest
). - Asynchronous response bodies via
streamGet()
,streamPost()
, etc. on any of the above request classes. - Automatic request encoding and response decoding.
- Support for most commonly used request types:
-
Mocks
- Because this library is designed to be platform-agnostic, it's easy to introduce mocks simply by treating tests as another platform, just like the browser or the Dart VM.
- Import
package:w_transport/w_transport_mock.dart
and callconfigureWTransportForTest()
to configure w_transport to use mock implementations for every class. - No changes necessary to your source code!
- Utilize the
MockTransports
class to control WebSocket connections and HTTP requests.
-
Testing
- A big initiative in this 2.0.0 release was to increase our test coverage -
which we've done. With almost 1000 statements,
w_transport
has 99.7% coverage! - Since this library is concerned with transport protocols, it is imperative that our testing included rigorous integration tests. We have over 1000 integration tests that run in the browser and on the Dart VM against real servers.
- Our test suites run against our mock implementations as well to ensure they are in parity with the real implementations.
- A big initiative in this 2.0.0 release was to increase our test coverage -
which we've done. With almost 1000 statements,
The WRequest
class attempted to cover all HTTP request use cases. Its closest
analog now is Request
- the class for sending plain-text requests. All other
request classes share a similar base API with additional support for a specific
type of request data (JSON, form, multipart, or streamed).
The WResponse
class made request meta data (status, headers) available as soon
as the request had finished; however, in an attempt to unify the API between the
dart:io
HTTP requests and dart:html
XHR requests, the response body was only
available asynchronously (as a stream, an untyped future, or decoded to text).
This meant two asynchronous steps were required for every request - one to get
the response, and one to get the response body.
This has been greatly improved by switching to two different response classes:
Response
- response meta data and body available synchronouslyStreamedResponse
- response meta data available synchronously, body available as a stream of bytes
June 23, 2015
Bug Fixes:
- Allow request data to be set to
null
. - Canceling an in-flight request now properly results in the returned Future completing with an error.
- Request data type validation now happens when sending the request instead of upon assignment, allowing intermediate data assignments.
- Verify w_transport configuration has been set before constructing a
WHttp
instance.
May 21, 2015
- Initial version of w_transport: a fluent-style, platform-agnostic library with ready to use transport classes for sending and receiving data over HTTP.