Browse Source

[0.9.9] Release 0.9.9

master
Miguel Castiblanco 3 years ago
parent
commit
d6f907c1d7
  1. 9
      CHANGELOG.md
  2. 89
      lib/simple_http_client.dart
  3. 2
      pubspec.yaml
  4. 35
      test/simple_client_test.dart

9
CHANGELOG.md

@ -1,8 +1,13 @@
# Changelog
## 0.9.0 - Dec 30, 2018
## 0.9.9 - Jan 19, 2020
- Added `addResponseIterceptor` in order to allow for interception of the response for logging and analytics purposes
- Renamed `addInterceptor` to `addRequestInterceptor` for clarity
- Updated tests
- Removed `debug` flag to promote the usage of `ResponseInterceptor` for logs
First public version of the lib
## 0.9.0 - Dec 30, 2018
First public version of the library
### Added
- Support for interceptors

89
lib/simple_http_client.dart

@ -18,10 +18,16 @@ import 'dart:async';
import 'dart:io';
import 'dart:convert';
/// If one or more interceptors are set, they will be called before the request
/// is made in order to allow for modifications of the [HttpClientRequest]
/// See [SimpleHttpClient.addInterceptor]
typedef Future<HttpClientRequest> Interceptor(HttpClientRequest request);
/// If one or more request interceptors are set, they will be called before the
/// request is made in order to allow for modifications of the [HttpClientRequest]
/// See [SimpleHttpClient.addRequestInterceptor]
typedef Future<HttpClientRequest> RequestInterceptor(HttpClientRequest request);
/// This type is used in order to allow the interception of the response,
/// usually you will want to use this for logging or analytics. See
/// [SimpleHttpClient.addResponseInterceptor]
typedef Future<Null> ResponseInterceptor(
HttpClientRequest request, Response response);
// Defines a certificate by its bytes
class SimpleCertificate {
@ -42,7 +48,9 @@ class SimpleCertificate {
/// Set an authenticator to have it called if a request receives a [:401:] response,
/// or set an interceptor if you want to modify all the requests made with this
/// client (e.g adding a header). See [SimpleHttpClient.setAuthenticator],
/// [SimpleHttpClient.addInterceptor], and [Interceptor].
/// [SimpleHttpClient.addRequestInterceptor], and [RequestInterceptor]. For logging
/// or analytics purposes, you may want to set a [ResponseInterceptor], see
/// [SimpleHttpClient.addResponseInterceptor].
///
/// Set a timeout [Duration] when creating the instance
/// `new SimpleHttpClient(timeout: new Duration(seconds: 7))`.
@ -70,11 +78,10 @@ class SimpleHttpClient {
/// Timeout for the requests. Default value is [:10:] seconds
final Duration timeout;
final bool debug;
HttpClient _httpClient;
List<Interceptor> _interceptors = new List();
Interceptor _authenticate;
List<RequestInterceptor> _requestInterceptors = new List();
List<ResponseInterceptor> _responseInterceptors = new List();
RequestInterceptor _authenticate;
final SecurityContext _securityContext;
/// Creates an instance of [SimpleHttpClient].
@ -102,7 +109,6 @@ class SimpleHttpClient {
this.followRedirects: true,
this.maxRedirects: 5,
this.maxAuthRetries: 1,
this.debug: false,
List<SimpleCertificate> trustedCertificates})
: _securityContext =
(trustedCertificates != null) ? new SecurityContext() : null {
@ -121,14 +127,22 @@ class SimpleHttpClient {
request.headers.add("user-agent", userAgent);
}
_intercept(HttpClientRequest request) async {
if (_interceptors.isNotEmpty) {
for (Interceptor interceptor in _interceptors) {
_interceptRequest(HttpClientRequest request) async {
if (_requestInterceptors.isNotEmpty) {
for (RequestInterceptor interceptor in _requestInterceptors) {
await interceptor(request);
}
}
}
_interceptResponse(HttpClientRequest request, Response response) async {
if (_responseInterceptors.isNotEmpty) {
for (ResponseInterceptor interceptor in _responseInterceptors) {
await interceptor(request, response);
}
}
}
_setContentType(HttpClientRequest request, {ContentType contentType}) {
if (contentType == null) {
contentType = ContentType.json;
@ -155,7 +169,7 @@ class SimpleHttpClient {
}
if (authenticate) await _authenticate(request);
await _intercept(request);
await _interceptRequest(request);
if (body != null) {
request.write(body);
@ -166,6 +180,9 @@ class SimpleHttpClient {
throw new TimeOutException();
});
var simpleResponse = await _read(response);
await _interceptResponse(request, simpleResponse);
if (HttpStatus.unauthorized == response.statusCode &&
_authenticate != null &&
requestNumber <= maxAuthRetries) {
@ -178,7 +195,7 @@ class SimpleHttpClient {
throw new UnauthorizedException();
}
return _read(response);
return simpleResponse;
} on SocketException catch (_) {
throw new CantConnectException();
} on HandshakeException catch (_) {
@ -231,7 +248,7 @@ class SimpleHttpClient {
}
/// Set the authenticator for the client. If an authenticator is set,
/// the app will call it when a response has the HTTP Status Code [:401:].
/// the library will call it when a response has the HTTP Status Code [:401:].
/// The authenticator will be called with a request identical to the original
/// one, and the authenticator has to modify that request in whichever way
/// needed. After the authenticator is called, the request will be sent and
@ -240,20 +257,31 @@ class SimpleHttpClient {
/// not set, an [UnauthorizedException] will be thrown.
///
/// The authenticator will be called before any interceptor.
void setAuthenticator(Interceptor authenticator) {
void setAuthenticator(RequestInterceptor authenticator) {
this._authenticate = authenticator;
}
/// Add an [Interceptor]. Each interceptor will be called sequentially in the same
/// Add a [RequestInterceptor]. Each interceptor will be called sequentially in the same
/// order it was added, before executing the request, and after the authenticator
/// if authentication was needed.
void addInterceptor(Interceptor interceptor) {
_interceptors.add(interceptor);
void addRequestInterceptor(RequestInterceptor interceptor) {
_requestInterceptors.add(interceptor);
}
/// Remove a request interceptor from the list
void removeRequestInterceptor(RequestInterceptor interceptor) {
_requestInterceptors.remove(interceptor);
}
/// Remove an interceptor from the list
void removeInterceptor(Interceptor interceptor) {
_interceptors.remove(interceptor);
/// ResponseInterceptor are called as soon as a response is obtained. Usually
/// this type of interceptor is used for analytics or logging
void addResponseInterceptor(ResponseInterceptor interceptor) {
_responseInterceptors.add(interceptor);
}
/// Remove a response interceptor from the list
void removeResponseInterceptor(ResponseInterceptor interceptor) {
_requestInterceptors.remove(interceptor);
}
/// Execute a POST call.
@ -270,9 +298,6 @@ class SimpleHttpClient {
{ContentType contentType, Map<String, String> headers}) async {
var response = await _execute(() => _post(url, contentType: contentType),
body: body, headers: headers);
if (debug) {
print("POST $url [${response.statusCode}]");
}
return response;
}
@ -290,10 +315,6 @@ class SimpleHttpClient {
{ContentType contentType, Map<String, String> headers}) async {
var response = await _execute(() => _put(url, contentType: contentType),
body: body, headers: headers);
if (debug) {
print("PUT $url [${response.statusCode}]");
}
return response;
}
@ -306,10 +327,6 @@ class SimpleHttpClient {
/// Will return a [Response]
Future<Response> get(String url, {Map<String, String> headers}) async {
var response = await _execute(() => _get(url), headers: headers);
if (debug) {
print("GET $url [${response.statusCode}]");
}
return response;
}
@ -322,10 +339,6 @@ class SimpleHttpClient {
/// Will return a [Response]
Future<Response> delete(String url, {Map<String, String> headers}) async {
var response = await _execute(() => _delete(url), headers: headers);
if (debug) {
print("DELETE $url [${response.statusCode}]");
}
return response;
}
}

2
pubspec.yaml

@ -1,5 +1,5 @@
name: simple_http_client
version: 0.9.0
version: 0.9.9
description: Simple HTTP client for Flutter and Dart server
author: Miguel Castiblanco <miguel@starcarr.co>
homepage: https://git.starcarr.co/Dart/SimpleWebClient

35
test/simple_client_test.dart

@ -74,7 +74,7 @@ main() {
expect(_server.requestCount, 3);
});
test('simple intercept', () async {
test('simple request intercept', () async {
String responseBody = "Intercepted Response";
String headerAuth = "BEARER XAZSA";
@ -82,12 +82,14 @@ main() {
_server.enqueue(body: responseBody);
SimpleHttpClient client = new SimpleHttpClient();
client.addInterceptor((HttpClientRequest request) async {
client.addRequestInterceptor((HttpClientRequest request) async {
// Request and add the auth header only to the first request
if ("/user/1" == request.uri.path) {
String token = (await client.get(_server.url)).body;
request.headers.set("Authorization", token);
}
return request;
});
String response = (await client.get(_server.url + "user/1")).body;
@ -101,6 +103,25 @@ main() {
expect(headerAuth, request.headers["authorization"]);
});
test('simple response intercept', () async {
String responseBody = "Intercepted Response";
_server.enqueue(body: responseBody);
SimpleHttpClient client = new SimpleHttpClient();
Completer completer = Completer<bool>();
client.addResponseInterceptor((HttpClientRequest request, Response response) async {
expect(response.body, responseBody);
expect(response.statusCode, 200);
expect(request.uri.toString(), _server.url + "user/1");
completer.complete(true);
});
await client.get(_server.url + "user/1");
await completer.future;
});
test('useragent', () async {
String responseBody = "Response";
String userAgent = "Awesome client";
@ -124,8 +145,10 @@ main() {
_server.enqueue(body: body);
SimpleHttpClient client = new SimpleHttpClient();
client.setAuthenticator((request) {
client.setAuthenticator((request) async {
request.headers.set("Authorization", header);
return request;
});
String response = (await client.post(_server.url, requestBody)).body;
@ -148,8 +171,9 @@ main() {
_server.enqueue(httpCode: HttpStatus.unauthorized);
SimpleHttpClient client = new SimpleHttpClient(maxAuthRetries: 2);
client.setAuthenticator((request) {
client.setAuthenticator((request) async {
// Do nothing
return request;
});
await expectLater(client.get(_server.url),
@ -217,8 +241,9 @@ main() {
_server.enqueue();
SimpleHttpClient client = new SimpleHttpClient();
client.setAuthenticator((request) {
client.setAuthenticator((request) async {
// Do nothing
return request;
});
await client.get(_server.url, headers: {"name": name});

Loading…
Cancel
Save