feat(http): refactor library to work in dart
Mostly internal refactoring needed to make ts2dart and DartAnalyzer happy. Fixes #2415
This commit is contained in:
parent
fa7da0ca5d
commit
55bf0e554f
@ -1 +0,0 @@
|
|||||||
library angular2.http;
|
|
@ -10,20 +10,24 @@ import {Http, HttpFactory} from './src/http/http';
|
|||||||
import {XHRBackend, XHRConnection} from 'angular2/src/http/backends/xhr_backend';
|
import {XHRBackend, XHRConnection} from 'angular2/src/http/backends/xhr_backend';
|
||||||
import {BrowserXHR} from 'angular2/src/http/backends/browser_xhr';
|
import {BrowserXHR} from 'angular2/src/http/backends/browser_xhr';
|
||||||
import {BaseRequestOptions, RequestOptions} from 'angular2/src/http/base_request_options';
|
import {BaseRequestOptions, RequestOptions} from 'angular2/src/http/base_request_options';
|
||||||
|
import {ConnectionBackend} from 'angular2/src/http/interfaces';
|
||||||
|
|
||||||
export {MockConnection, MockBackend} from 'angular2/src/http/backends/mock_backend';
|
export {MockConnection, MockBackend} from 'angular2/src/http/backends/mock_backend';
|
||||||
export {Request} from 'angular2/src/http/static_request';
|
export {Request} from 'angular2/src/http/static_request';
|
||||||
export {Response} from 'angular2/src/http/static_response';
|
export {Response} from 'angular2/src/http/static_response';
|
||||||
|
|
||||||
export {Http, XHRBackend, XHRConnection, BaseRequestOptions, RequestOptions, HttpFactory};
|
|
||||||
export {
|
export {
|
||||||
IHttp,
|
IHttp,
|
||||||
IRequestOptions,
|
IRequestOptions,
|
||||||
IRequest,
|
|
||||||
IResponse,
|
IResponse,
|
||||||
Connection,
|
Connection,
|
||||||
ConnectionBackend
|
ConnectionBackend
|
||||||
} from 'angular2/src/http/interfaces';
|
} from 'angular2/src/http/interfaces';
|
||||||
|
|
||||||
|
export {BaseRequestOptions, RequestOptions} from 'angular2/src/http/base_request_options';
|
||||||
|
export {XHRBackend, XHRConnection} from 'angular2/src/http/backends/xhr_backend';
|
||||||
|
export {Http, HttpFactory} from './src/http/http';
|
||||||
|
|
||||||
export {Headers} from 'angular2/src/http/headers';
|
export {Headers} from 'angular2/src/http/headers';
|
||||||
|
|
||||||
export * from 'angular2/src/http/enums';
|
export * from 'angular2/src/http/enums';
|
||||||
@ -47,8 +51,9 @@ export {URLSearchParams} from 'angular2/src/http/url_search_params';
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export var httpInjectables: List<any> = [
|
export var httpInjectables: List<any> = [
|
||||||
bind(BrowserXHR)
|
bind(ConnectionBackend)
|
||||||
.toValue(BrowserXHR),
|
.toClass(XHRBackend),
|
||||||
|
BrowserXHR,
|
||||||
XHRBackend,
|
XHRBackend,
|
||||||
BaseRequestOptions,
|
BaseRequestOptions,
|
||||||
bind(HttpFactory).toFactory(HttpFactory, [XHRBackend, BaseRequestOptions]),
|
bind(HttpFactory).toFactory(HttpFactory, [XHRBackend, BaseRequestOptions]),
|
||||||
|
@ -11,6 +11,8 @@ class Math {
|
|||||||
static double random() => _random.nextDouble();
|
static double random() => _random.nextDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ENUM_INDEX(value) => value.index;
|
||||||
|
|
||||||
class CONST {
|
class CONST {
|
||||||
const CONST();
|
const CONST();
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,11 @@ _global.assert = function assert(condition) {
|
|||||||
_global['assert'].call(condition);
|
_global['assert'].call(condition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function ENUM_INDEX(value: int): int {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// This function is needed only to properly support Dart's const expressions
|
// This function is needed only to properly support Dart's const expressions
|
||||||
// see https://github.com/angular/ts2dart/pull/151 for more info
|
// see https://github.com/angular/ts2dart/pull/151 for more info
|
||||||
export function CONST_EXPR<T>(expr: T): T {
|
export function CONST_EXPR<T>(expr: T): T {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
library angular2.src.http.backends.browser_xhr;
|
library angular2.src.http.backends.browser_xhr;
|
||||||
|
|
||||||
/// import 'dart:html' show HttpRequest;
|
import 'dart:html' show HttpRequest;
|
||||||
/// import 'package:angular2/di.dart';
|
import 'package:angular2/di.dart';
|
||||||
|
|
||||||
/// @Injectable()
|
@Injectable()
|
||||||
/// class BrowserXHR {
|
class BrowserXHR {
|
||||||
/// factory BrowserXHR() => new HttpRequest();
|
HttpRequest build() {
|
||||||
/// }
|
return new HttpRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,5 +5,6 @@ import {Injectable} from 'angular2/di';
|
|||||||
// Make sure not to evaluate this in a non-browser environment!
|
// Make sure not to evaluate this in a non-browser environment!
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BrowserXHR {
|
export class BrowserXHR {
|
||||||
constructor() { return <any>(new window.XMLHttpRequest()); }
|
constructor() {}
|
||||||
|
build(): any { return <any>(new window.XMLHttpRequest()); }
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ import {Request} from 'angular2/src/http/static_request';
|
|||||||
import {Response} from 'angular2/src/http/static_response';
|
import {Response} from 'angular2/src/http/static_response';
|
||||||
import {ReadyStates} from 'angular2/src/http/enums';
|
import {ReadyStates} from 'angular2/src/http/enums';
|
||||||
import {Connection, ConnectionBackend} from 'angular2/src/http/interfaces';
|
import {Connection, ConnectionBackend} from 'angular2/src/http/interfaces';
|
||||||
import * as Rx from 'rx';
|
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
|
import {IMPLEMENTS, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -14,7 +16,8 @@ import * as Rx from 'rx';
|
|||||||
* {@link MockBackend} in order to mock responses to requests.
|
* {@link MockBackend} in order to mock responses to requests.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
export class MockConnection implements Connection {
|
@IMPLEMENTS(Connection)
|
||||||
|
export class MockConnection {
|
||||||
// TODO Name `readyState` should change to be more generic, and states could be made to be more
|
// TODO Name `readyState` should change to be more generic, and states could be made to be more
|
||||||
// descriptive than XHR states.
|
// descriptive than XHR states.
|
||||||
/**
|
/**
|
||||||
@ -33,18 +36,12 @@ export class MockConnection implements Connection {
|
|||||||
* Observable](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observable.md)
|
* Observable](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observable.md)
|
||||||
* of {@link Response}. Can be subscribed to in order to be notified when a response is available.
|
* of {@link Response}. Can be subscribed to in order to be notified when a response is available.
|
||||||
*/
|
*/
|
||||||
response: Rx.Subject<Response>;
|
response: EventEmitter;
|
||||||
|
|
||||||
constructor(req: Request) {
|
constructor(req: Request) {
|
||||||
if (Rx.hasOwnProperty('default')) {
|
this.response = new EventEmitter();
|
||||||
this.response = new ((<any>Rx).default.Rx.Subject)();
|
|
||||||
} else {
|
|
||||||
this.response = new Rx.Subject<Response>();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.readyState = ReadyStates.OPEN;
|
this.readyState = ReadyStates.OPEN;
|
||||||
this.request = req;
|
this.request = req;
|
||||||
this.dispose = this.dispose.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,12 +68,12 @@ export class MockConnection implements Connection {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
mockRespond(res: Response) {
|
mockRespond(res: Response) {
|
||||||
if (this.readyState >= ReadyStates.DONE) {
|
if (this.readyState === ReadyStates.DONE || this.readyState === ReadyStates.CANCELLED) {
|
||||||
throw new Error('Connection has already been resolved');
|
throw new BaseException('Connection has already been resolved');
|
||||||
}
|
}
|
||||||
this.readyState = ReadyStates.DONE;
|
this.readyState = ReadyStates.DONE;
|
||||||
this.response.onNext(res);
|
ObservableWrapper.callNext(this.response, res);
|
||||||
this.response.onCompleted();
|
ObservableWrapper.callReturn(this.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,8 +97,8 @@ export class MockConnection implements Connection {
|
|||||||
mockError(err?) {
|
mockError(err?) {
|
||||||
// Matches XHR semantics
|
// Matches XHR semantics
|
||||||
this.readyState = ReadyStates.DONE;
|
this.readyState = ReadyStates.DONE;
|
||||||
this.response.onError(err);
|
ObservableWrapper.callThrow(this.response, err);
|
||||||
this.response.onCompleted();
|
ObservableWrapper.callReturn(this.response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +134,8 @@ export class MockConnection implements Connection {
|
|||||||
* This method only exists in the mock implementation, not in real Backends.
|
* This method only exists in the mock implementation, not in real Backends.
|
||||||
**/
|
**/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MockBackend implements ConnectionBackend {
|
@IMPLEMENTS(ConnectionBackend)
|
||||||
|
export class MockBackend {
|
||||||
/**
|
/**
|
||||||
* [RxJS
|
* [RxJS
|
||||||
* Subject](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md)
|
* Subject](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md)
|
||||||
@ -171,7 +169,7 @@ export class MockBackend implements ConnectionBackend {
|
|||||||
*
|
*
|
||||||
* This property only exists in the mock implementation, not in real Backends.
|
* This property only exists in the mock implementation, not in real Backends.
|
||||||
*/
|
*/
|
||||||
connections: Rx.Subject<MockConnection>;
|
connections: EventEmitter; //<MockConnection>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array representation of `connections`. This array will be updated with each connection that
|
* An array representation of `connections`. This array will be updated with each connection that
|
||||||
@ -188,20 +186,14 @@ export class MockBackend implements ConnectionBackend {
|
|||||||
*
|
*
|
||||||
* This property only exists in the mock implementation, not in real Backends.
|
* This property only exists in the mock implementation, not in real Backends.
|
||||||
*/
|
*/
|
||||||
pendingConnections: Rx.Observable<MockConnection>;
|
pendingConnections: EventEmitter; //<MockConnection>
|
||||||
constructor() {
|
constructor() {
|
||||||
var Observable;
|
|
||||||
this.connectionsArray = [];
|
this.connectionsArray = [];
|
||||||
if (Rx.hasOwnProperty('default')) {
|
this.connections = new EventEmitter();
|
||||||
this.connections = new (<any>Rx).default.Rx.Subject();
|
ObservableWrapper.subscribe(this.connections,
|
||||||
Observable = (<any>Rx).default.Rx.Observable;
|
connection => this.connectionsArray.push(connection));
|
||||||
} else {
|
this.pendingConnections = new EventEmitter();
|
||||||
this.connections = new Rx.Subject<MockConnection>();
|
// Observable.fromArray(this.connectionsArray).filter((c) => c.readyState < ReadyStates.DONE);
|
||||||
Observable = Rx.Observable;
|
|
||||||
}
|
|
||||||
this.connections.subscribe(connection => this.connectionsArray.push(connection));
|
|
||||||
this.pendingConnections =
|
|
||||||
Observable.fromArray(this.connectionsArray).filter((c) => c.readyState < ReadyStates.DONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -211,8 +203,8 @@ export class MockBackend implements ConnectionBackend {
|
|||||||
*/
|
*/
|
||||||
verifyNoPendingRequests() {
|
verifyNoPendingRequests() {
|
||||||
let pending = 0;
|
let pending = 0;
|
||||||
this.pendingConnections.subscribe((c) => pending++);
|
ObservableWrapper.subscribe(this.pendingConnections, c => pending++);
|
||||||
if (pending > 0) throw new Error(`${pending} pending connections to be resolved`);
|
if (pending > 0) throw new BaseException(`${pending} pending connections to be resolved`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,7 +213,7 @@ export class MockBackend implements ConnectionBackend {
|
|||||||
*
|
*
|
||||||
* This method only exists in the mock implementation, not in real Backends.
|
* This method only exists in the mock implementation, not in real Backends.
|
||||||
*/
|
*/
|
||||||
resolveAllConnections() { this.connections.subscribe((c) => c.readyState = 4); }
|
resolveAllConnections() { ObservableWrapper.subscribe(this.connections, c => c.readyState = 4); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link MockConnection}. This is equivalent to calling `new
|
* Creates a new {@link MockConnection}. This is equivalent to calling `new
|
||||||
@ -229,12 +221,12 @@ export class MockBackend implements ConnectionBackend {
|
|||||||
* observable of this `MockBackend` instance. This method will usually only be used by tests
|
* observable of this `MockBackend` instance. This method will usually only be used by tests
|
||||||
* against the framework itself, not by end-users.
|
* against the framework itself, not by end-users.
|
||||||
*/
|
*/
|
||||||
createConnection(req: Request): Connection {
|
createConnection(req: Request) {
|
||||||
if (!req || !(req instanceof Request)) {
|
if (!isPresent(req) || !(req instanceof Request)) {
|
||||||
throw new Error(`createConnection requires an instance of Request, got ${req}`);
|
throw new BaseException(`createConnection requires an instance of Request, got ${req}`);
|
||||||
}
|
}
|
||||||
let connection = new MockConnection(req);
|
let connection = new MockConnection(req);
|
||||||
this.connections.onNext(connection);
|
ObservableWrapper.callNext(this.connections, connection);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import {ConnectionBackend, Connection} from '../interfaces';
|
import {ConnectionBackend, Connection} from '../interfaces';
|
||||||
import {ReadyStates, RequestMethods} from '../enums';
|
import {ReadyStates, RequestMethods, RequestMethodsMap} from '../enums';
|
||||||
import {Request} from '../static_request';
|
import {Request} from '../static_request';
|
||||||
import {Response} from '../static_response';
|
import {Response} from '../static_response';
|
||||||
import {Inject} from 'angular2/di';
|
|
||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {BrowserXHR} from './browser_xhr';
|
import {BrowserXHR} from './browser_xhr';
|
||||||
import * as Rx from 'rx';
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {isPresent, ENUM_INDEX} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
||||||
@ -22,22 +22,24 @@ export class XHRConnection implements Connection {
|
|||||||
* [Subject](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md)
|
* [Subject](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md)
|
||||||
* which emits a single {@link Response} value on load event of `XMLHttpRequest`.
|
* which emits a single {@link Response} value on load event of `XMLHttpRequest`.
|
||||||
*/
|
*/
|
||||||
response: Rx.Subject<Response>;
|
response: EventEmitter; //<Response>;
|
||||||
readyState: ReadyStates;
|
readyState: ReadyStates;
|
||||||
private _xhr;
|
private _xhr;
|
||||||
constructor(req: Request, NativeConstruct: any) {
|
constructor(req: Request, browserXHR: BrowserXHR) {
|
||||||
|
// TODO: get rid of this when enum lookups are available in ts2dart
|
||||||
|
// https://github.com/angular/ts2dart/issues/221
|
||||||
|
var requestMethodsMap = new RequestMethodsMap();
|
||||||
this.request = req;
|
this.request = req;
|
||||||
if (Rx.hasOwnProperty('default')) {
|
this.response = new EventEmitter();
|
||||||
this.response = new (<any>Rx).default.Rx.Subject();
|
this._xhr = browserXHR.build();
|
||||||
} else {
|
|
||||||
this.response = new Rx.Subject<Response>();
|
|
||||||
}
|
|
||||||
this._xhr = new NativeConstruct();
|
|
||||||
// TODO(jeffbcross): implement error listening/propagation
|
// TODO(jeffbcross): implement error listening/propagation
|
||||||
this._xhr.open(RequestMethods[req.method], req.url);
|
this._xhr.open(requestMethodsMap.getMethod(ENUM_INDEX(req.method)), req.url);
|
||||||
this._xhr.addEventListener(
|
this._xhr.addEventListener(
|
||||||
'load',
|
'load',
|
||||||
() => {this.response.onNext(new Response(this._xhr.response || this._xhr.responseText))});
|
(_) => {ObservableWrapper.callNext(
|
||||||
|
this.response, new Response({
|
||||||
|
body: isPresent(this._xhr.response) ? this._xhr.response : this._xhr.responseText
|
||||||
|
}))});
|
||||||
// TODO(jeffbcross): make this more dynamic based on body type
|
// TODO(jeffbcross): make this more dynamic based on body type
|
||||||
this._xhr.send(this.request.text());
|
this._xhr.send(this.request.text());
|
||||||
}
|
}
|
||||||
@ -76,8 +78,8 @@ export class XHRConnection implements Connection {
|
|||||||
**/
|
**/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class XHRBackend implements ConnectionBackend {
|
export class XHRBackend implements ConnectionBackend {
|
||||||
constructor(private _NativeConstruct: BrowserXHR) {}
|
constructor(private _browserXHR: BrowserXHR) {}
|
||||||
createConnection(request: Request): XHRConnection {
|
createConnection(request: Request): XHRConnection {
|
||||||
return new XHRConnection(request, this._NativeConstruct);
|
return new XHRConnection(request, this._browserXHR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import {CONST_EXPR, CONST, isPresent} from 'angular2/src/facade/lang';
|
import {CONST_EXPR, CONST, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {Headers} from './headers';
|
import {Headers} from './headers';
|
||||||
import {URLSearchParams} from './url_search_params';
|
|
||||||
import {RequestModesOpts, RequestMethods, RequestCacheOpts, RequestCredentialsOpts} from './enums';
|
import {RequestModesOpts, RequestMethods, RequestCacheOpts, RequestCredentialsOpts} from './enums';
|
||||||
import {IRequestOptions} from './interfaces';
|
import {IRequestOptions} from './interfaces';
|
||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
const INITIALIZER = CONST_EXPR({});
|
||||||
/**
|
/**
|
||||||
* Creates a request options object with default properties as described in the [Fetch
|
* Creates a request options object with default properties as described in the [Fetch
|
||||||
* Spec](https://fetch.spec.whatwg.org/#requestinit) to be optionally provided when instantiating a
|
* Spec](https://fetch.spec.whatwg.org/#requestinit) to be optionally provided when instantiating a
|
||||||
@ -28,28 +28,49 @@ export class RequestOptions implements IRequestOptions {
|
|||||||
/**
|
/**
|
||||||
* Body to be used when creating the request.
|
* Body to be used when creating the request.
|
||||||
*/
|
*/
|
||||||
body: URLSearchParams | FormData | Blob | string;
|
// TODO: support FormData, Blob, URLSearchParams, JSON
|
||||||
|
body: string;
|
||||||
mode: RequestModesOpts = RequestModesOpts.Cors;
|
mode: RequestModesOpts = RequestModesOpts.Cors;
|
||||||
credentials: RequestCredentialsOpts;
|
credentials: RequestCredentialsOpts;
|
||||||
cache: RequestCacheOpts;
|
cache: RequestCacheOpts;
|
||||||
constructor({method, headers, body, mode, credentials, cache}: IRequestOptions = {
|
url: string;
|
||||||
method: RequestMethods.GET,
|
constructor({method, headers, body, mode, credentials, cache, url}: IRequestOptions = {}) {
|
||||||
mode: RequestModesOpts.Cors
|
this.method = isPresent(method) ? method : RequestMethods.GET;
|
||||||
}) {
|
|
||||||
this.method = method;
|
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.mode = mode;
|
this.mode = isPresent(mode) ? mode : RequestModesOpts.Cors;
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a copy of the `RequestOptions` instance, using the optional input as values to override
|
* Creates a copy of the `RequestOptions` instance, using the optional input as values to override
|
||||||
* existing values.
|
* existing values.
|
||||||
*/
|
*/
|
||||||
merge(opts: IRequestOptions = {}): RequestOptions {
|
merge({url = null, method = null, headers = null, body = null, mode = null, credentials = null,
|
||||||
return new RequestOptions(StringMapWrapper.merge(this, opts));
|
cache = null}: any = {}): RequestOptions {
|
||||||
|
return new RequestOptions({
|
||||||
|
method: isPresent(method) ? method : this.method,
|
||||||
|
headers: isPresent(headers) ? headers : this.headers,
|
||||||
|
body: isPresent(body) ? body : this.body,
|
||||||
|
mode: isPresent(mode) ? mode : this.mode,
|
||||||
|
credentials: isPresent(credentials) ? credentials : this.credentials,
|
||||||
|
cache: isPresent(cache) ? cache : this.cache,
|
||||||
|
url: isPresent(url) ? url : this.url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromStringWrapper(map: StringMap<string, any>): RequestOptions {
|
||||||
|
return new RequestOptions({
|
||||||
|
method: StringMapWrapper.get(map, 'method'),
|
||||||
|
headers: StringMapWrapper.get(map, 'headers'),
|
||||||
|
body: StringMapWrapper.get(map, 'body'),
|
||||||
|
mode: StringMapWrapper.get(map, 'mode'),
|
||||||
|
credentials: StringMapWrapper.get(map, 'credentials'),
|
||||||
|
cache: StringMapWrapper.get(map, 'cache'),
|
||||||
|
url:<string>StringMapWrapper.get(map, 'url')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,21 +3,19 @@ import {ResponseTypes} from './enums';
|
|||||||
import {ResponseOptions} from './interfaces';
|
import {ResponseOptions} from './interfaces';
|
||||||
|
|
||||||
export class BaseResponseOptions implements ResponseOptions {
|
export class BaseResponseOptions implements ResponseOptions {
|
||||||
|
body: string | Object | ArrayBuffer | JSON | FormData | Blob;
|
||||||
status: number;
|
status: number;
|
||||||
headers: Headers | Object;
|
headers: Headers;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
type: ResponseTypes;
|
type: ResponseTypes;
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
constructor({status = 200, statusText = 'Ok', type = ResponseTypes.Default,
|
constructor() {
|
||||||
headers = new Headers(), url = ''}: ResponseOptions = {}) {
|
this.status = 200;
|
||||||
this.status = status;
|
this.statusText = 'Ok';
|
||||||
this.statusText = statusText;
|
this.type = ResponseTypes.Default;
|
||||||
this.type = type;
|
this.headers = new Headers();
|
||||||
this.headers = headers;
|
|
||||||
this.url = url;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
|
||||||
export var baseResponseOptions = Object.freeze(new BaseResponseOptions());
|
export var baseResponseOptions = new BaseResponseOptions();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
export enum RequestModesOpts {
|
export enum RequestModesOpts {
|
||||||
Cors,
|
Cors,
|
||||||
NoCors,
|
NoCors,
|
||||||
@ -29,6 +31,14 @@ export enum RequestMethods {
|
|||||||
PATCH
|
PATCH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this when enum lookups are available in ts2dart
|
||||||
|
// https://github.com/angular/ts2dart/issues/221
|
||||||
|
export class RequestMethodsMap {
|
||||||
|
private _methods: List<string>;
|
||||||
|
constructor() { this._methods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH']; }
|
||||||
|
getMethod(method: int): string { return this._methods[method]; }
|
||||||
|
}
|
||||||
|
|
||||||
export enum ReadyStates {
|
export enum ReadyStates {
|
||||||
UNSENT,
|
UNSENT,
|
||||||
OPEN,
|
OPEN,
|
||||||
|
@ -11,7 +11,8 @@ import {
|
|||||||
List,
|
List,
|
||||||
Map,
|
Map,
|
||||||
MapWrapper,
|
MapWrapper,
|
||||||
ListWrapper
|
ListWrapper,
|
||||||
|
StringMap
|
||||||
} from 'angular2/src/facade/collection';
|
} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,15 +22,15 @@ import {
|
|||||||
*/
|
*/
|
||||||
export class Headers {
|
export class Headers {
|
||||||
_headersMap: Map<string, List<string>>;
|
_headersMap: Map<string, List<string>>;
|
||||||
constructor(headers?: Headers | Object) {
|
constructor(headers?: Headers | StringMap<string, any>) {
|
||||||
if (isBlank(headers)) {
|
if (isBlank(headers)) {
|
||||||
this._headersMap = new Map();
|
this._headersMap = new Map();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent((<Headers>headers)._headersMap)) {
|
if (headers instanceof Headers) {
|
||||||
this._headersMap = (<Headers>headers)._headersMap;
|
this._headersMap = (<Headers>headers)._headersMap;
|
||||||
} else if (isJsObject(headers)) {
|
} else if (headers instanceof StringMap) {
|
||||||
this._headersMap = MapWrapper.createFromStringMap(headers);
|
this._headersMap = MapWrapper.createFromStringMap(headers);
|
||||||
MapWrapper.forEach(this._headersMap, (v, k) => {
|
MapWrapper.forEach(this._headersMap, (v, k) => {
|
||||||
if (!isListLikeIterable(v)) {
|
if (!isListLikeIterable(v)) {
|
||||||
@ -42,7 +43,8 @@ export class Headers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
append(name: string, value: string): void {
|
append(name: string, value: string): void {
|
||||||
var list = this._headersMap.get(name) || [];
|
var mapName = this._headersMap.get(name);
|
||||||
|
var list = isListLikeIterable(mapName) ? mapName : [];
|
||||||
list.push(value);
|
list.push(value);
|
||||||
this._headersMap.set(name, list);
|
this._headersMap.set(name, list);
|
||||||
}
|
}
|
||||||
@ -57,13 +59,19 @@ export class Headers {
|
|||||||
|
|
||||||
keys(): List<string> { return MapWrapper.keys(this._headersMap); }
|
keys(): List<string> { return MapWrapper.keys(this._headersMap); }
|
||||||
|
|
||||||
// TODO: this implementation seems wrong. create list then check if it's iterable?
|
|
||||||
set(header: string, value: string | List<string>): void {
|
set(header: string, value: string | List<string>): void {
|
||||||
var list = [];
|
var list = [];
|
||||||
if (!isListLikeIterable(value)) {
|
var isDart = false;
|
||||||
list.push(value);
|
// Dart hack
|
||||||
|
if (list.toString().length === 2) {
|
||||||
|
isDart = true;
|
||||||
|
}
|
||||||
|
if (isListLikeIterable(value)) {
|
||||||
|
var pushValue = (<List<string>>value).toString();
|
||||||
|
if (isDart) pushValue = pushValue.substring(1, pushValue.length - 1);
|
||||||
|
list.push(pushValue);
|
||||||
} else {
|
} else {
|
||||||
list.push(ListWrapper.toString((<List<string>>value)));
|
list.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._headersMap.set(header, list);
|
this._headersMap.set(header, list);
|
||||||
@ -71,7 +79,10 @@ export class Headers {
|
|||||||
|
|
||||||
values(): List<List<string>> { return MapWrapper.values(this._headersMap); }
|
values(): List<List<string>> { return MapWrapper.values(this._headersMap); }
|
||||||
|
|
||||||
getAll(header: string): Array<string> { return this._headersMap.get(header) || []; }
|
getAll(header: string): Array<string> {
|
||||||
|
var headers = this._headersMap.get(header);
|
||||||
|
return isListLikeIterable(headers) ? headers : [];
|
||||||
|
}
|
||||||
|
|
||||||
entries() { throw new BaseException('"entries" method is not implemented on Headers class'); }
|
entries() { throw new BaseException('"entries" method is not implemented on Headers class'); }
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
/// <reference path="../../typings/rx/rx.d.ts" />
|
import {isString, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {Injectable} from 'angular2/src/di/decorators';
|
import {Injectable} from 'angular2/src/di/decorators';
|
||||||
import {IRequestOptions, Connection, IHttp} from './interfaces';
|
import {IRequestOptions, Connection, ConnectionBackend} from './interfaces';
|
||||||
import {Request} from './static_request';
|
import {Request} from './static_request';
|
||||||
import {Response} from './static_response';
|
import {BaseRequestOptions, RequestOptions} from './base_request_options';
|
||||||
import {XHRBackend} from './backends/xhr_backend';
|
|
||||||
import {BaseRequestOptions} from './base_request_options';
|
|
||||||
import {RequestMethods} from './enums';
|
import {RequestMethods} from './enums';
|
||||||
import {URLSearchParams} from './url_search_params';
|
import {EventEmitter} from 'angular2/src/facade/async';
|
||||||
import * as Rx from 'rx';
|
|
||||||
|
|
||||||
function httpRequest(backend: XHRBackend, request: Request): Rx.Observable<Response> {
|
function httpRequest(backend: ConnectionBackend, request: Request): EventEmitter {
|
||||||
return <Rx.Observable<Response>>(Observable.create(observer => {
|
return backend.createConnection(request).response;
|
||||||
var connection: Connection = backend.createConnection(request);
|
}
|
||||||
var internalSubscription = connection.response.subscribe(observer);
|
|
||||||
return () => {
|
function mergeOptions(defaultOpts, providedOpts, method, url): RequestOptions {
|
||||||
internalSubscription.dispose();
|
var newOptions = defaultOpts;
|
||||||
connection.dispose();
|
if (isPresent(providedOpts)) {
|
||||||
};
|
newOptions = newOptions.merge(providedOpts);
|
||||||
}));
|
}
|
||||||
|
if (isPresent(method)) {
|
||||||
|
return newOptions.merge({method: method, url: url});
|
||||||
|
} else {
|
||||||
|
return newOptions.merge({url: url});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,7 +73,7 @@ function httpRequest(backend: XHRBackend, request: Request): Rx.Observable<Respo
|
|||||||
**/
|
**/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Http {
|
export class Http {
|
||||||
constructor(private _backend: XHRBackend, private _defaultOptions: BaseRequestOptions) {}
|
constructor(private _backend: ConnectionBackend, private _defaultOptions: BaseRequestOptions) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs any type of http request. First argument is required, and can either be a url or
|
* Performs any type of http request. First argument is required, and can either be a url or
|
||||||
@ -80,77 +81,70 @@ export class Http {
|
|||||||
* object can be provided as the 2nd argument. The options object will be merged with the values
|
* object can be provided as the 2nd argument. The options object will be merged with the values
|
||||||
* of {@link BaseRequestOptions} before performing the request.
|
* of {@link BaseRequestOptions} before performing the request.
|
||||||
*/
|
*/
|
||||||
request(url: string | Request, options?: IRequestOptions): Rx.Observable<Response> {
|
request(url: string | Request, options?: IRequestOptions): EventEmitter {
|
||||||
if (typeof url === 'string') {
|
var responseObservable: EventEmitter;
|
||||||
return httpRequest(this._backend, new Request(url, this._defaultOptions.merge(options)));
|
if (isString(url)) {
|
||||||
|
responseObservable = httpRequest(
|
||||||
|
this._backend,
|
||||||
|
new Request(mergeOptions(this._defaultOptions, options, RequestMethods.GET, url)));
|
||||||
} else if (url instanceof Request) {
|
} else if (url instanceof Request) {
|
||||||
return httpRequest(this._backend, url);
|
responseObservable = httpRequest(this._backend, url);
|
||||||
}
|
}
|
||||||
|
return responseObservable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `get` http method.
|
* Performs a request with `get` http method.
|
||||||
*/
|
*/
|
||||||
get(url: string, options?: IRequestOptions): Rx.Observable<Response> {
|
get(url: string, options?: IRequestOptions) {
|
||||||
return httpRequest(this._backend, new Request(url, this._defaultOptions.merge(options)
|
return httpRequest(this._backend, new Request(mergeOptions(this._defaultOptions, options,
|
||||||
.merge({method: RequestMethods.GET})));
|
RequestMethods.GET, url)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `post` http method.
|
* Performs a request with `post` http method.
|
||||||
*/
|
*/
|
||||||
post(url: string, body: URLSearchParams | FormData | Blob | string,
|
post(url: string, body: string, options?: IRequestOptions) {
|
||||||
options?: IRequestOptions): Rx.Observable<Response> {
|
|
||||||
return httpRequest(this._backend,
|
return httpRequest(this._backend,
|
||||||
new Request(url, this._defaultOptions.merge(options)
|
new Request(mergeOptions(this._defaultOptions.merge({body: body}), options,
|
||||||
|
RequestMethods.POST, url)));
|
||||||
.merge({body: body, method: RequestMethods.POST})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `put` http method.
|
* Performs a request with `put` http method.
|
||||||
*/
|
*/
|
||||||
put(url: string, body: URLSearchParams | FormData | Blob | string,
|
put(url: string, body: string, options?: IRequestOptions) {
|
||||||
options?: IRequestOptions): Rx.Observable<Response> {
|
|
||||||
return httpRequest(this._backend,
|
return httpRequest(this._backend,
|
||||||
new Request(url, this._defaultOptions.merge(options)
|
new Request(mergeOptions(this._defaultOptions.merge({body: body}), options,
|
||||||
.merge({body: body, method: RequestMethods.PUT})));
|
RequestMethods.PUT, url)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `delete` http method.
|
* Performs a request with `delete` http method.
|
||||||
*/
|
*/
|
||||||
delete (url: string, options?: IRequestOptions): Rx.Observable<Response> {
|
delete (url: string, options?: IRequestOptions) {
|
||||||
return httpRequest(this._backend, new Request(url, this._defaultOptions.merge(options).merge(
|
return httpRequest(this._backend, new Request(mergeOptions(this._defaultOptions, options,
|
||||||
{method: RequestMethods.DELETE})));
|
RequestMethods.DELETE, url)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `patch` http method.
|
* Performs a request with `patch` http method.
|
||||||
*/
|
*/
|
||||||
patch(url: string, body: URLSearchParams | FormData | Blob | string,
|
patch(url: string, body: string, options?: IRequestOptions) {
|
||||||
options?: IRequestOptions): Rx.Observable<Response> {
|
|
||||||
return httpRequest(this._backend,
|
return httpRequest(this._backend,
|
||||||
new Request(url, this._defaultOptions.merge(options)
|
new Request(mergeOptions(this._defaultOptions.merge({body: body}), options,
|
||||||
.merge({body: body, method: RequestMethods.PATCH})));
|
RequestMethods.PATCH, url)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a request with `head` http method.
|
* Performs a request with `head` http method.
|
||||||
*/
|
*/
|
||||||
head(url: string, options?: IRequestOptions): Rx.Observable<Response> {
|
head(url: string, options?: IRequestOptions) {
|
||||||
return httpRequest(this._backend, new Request(url, this._defaultOptions.merge(options)
|
return httpRequest(this._backend, new Request(mergeOptions(this._defaultOptions, options,
|
||||||
.merge({method: RequestMethods.HEAD})));
|
RequestMethods.HEAD, url)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Observable;
|
|
||||||
if (Rx.hasOwnProperty('default')) {
|
|
||||||
Observable = (<any>Rx).default.Rx.Observable;
|
|
||||||
} else {
|
|
||||||
Observable = Rx.Observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Alias to the `request` method of {@link Http}, for those who'd prefer a simple function instead
|
* Alias to the `request` method of {@link Http}, for those who'd prefer a simple function instead
|
||||||
@ -174,10 +168,10 @@ if (Rx.hasOwnProperty('default')) {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
**/
|
**/
|
||||||
export function HttpFactory(backend: XHRBackend, defaultOptions: BaseRequestOptions): IHttp {
|
export function HttpFactory(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
|
||||||
return function(url: string | Request, options?: IRequestOptions) {
|
return function(url: string | Request, options?: IRequestOptions) {
|
||||||
if (typeof url === 'string') {
|
if (isString(url)) {
|
||||||
return httpRequest(backend, new Request(url, defaultOptions.merge(options)));
|
return httpRequest(backend, new Request(mergeOptions(defaultOptions, options, null, url)));
|
||||||
} else if (url instanceof Request) {
|
} else if (url instanceof Request) {
|
||||||
return httpRequest(backend, url);
|
return httpRequest(backend, url);
|
||||||
}
|
}
|
||||||
|
@ -9,24 +9,36 @@ import {
|
|||||||
ResponseTypes
|
ResponseTypes
|
||||||
} from './enums';
|
} from './enums';
|
||||||
import {Headers} from './headers';
|
import {Headers} from './headers';
|
||||||
import {URLSearchParams} from './url_search_params';
|
import {BaseException} from 'angular2/src/facade/lang';
|
||||||
|
import {EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
import {Request} from './static_request';
|
||||||
|
|
||||||
|
export class ConnectionBackend {
|
||||||
|
constructor() {}
|
||||||
|
createConnection(request: any): Connection { throw new BaseException('Abstract!'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Connection {
|
||||||
|
readyState: ReadyStates;
|
||||||
|
request: Request;
|
||||||
|
response: EventEmitter; //<IResponse>;
|
||||||
|
dispose(): void { throw new BaseException('Abstract!'); }
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRequestOptions {
|
export interface IRequestOptions {
|
||||||
|
url?: string;
|
||||||
method?: RequestMethods;
|
method?: RequestMethods;
|
||||||
headers?: Headers;
|
headers?: Headers;
|
||||||
body?: URLSearchParams | FormData | Blob | string;
|
// TODO: Support Blob, ArrayBuffer, JSON, URLSearchParams, FormData
|
||||||
|
body?: string;
|
||||||
mode?: RequestModesOpts;
|
mode?: RequestModesOpts;
|
||||||
credentials?: RequestCredentialsOpts;
|
credentials?: RequestCredentialsOpts;
|
||||||
cache?: RequestCacheOpts;
|
cache?: RequestCacheOpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRequest {
|
|
||||||
method: RequestMethods;
|
|
||||||
mode: RequestModesOpts;
|
|
||||||
credentials: RequestCredentialsOpts;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResponseOptions {
|
export interface ResponseOptions {
|
||||||
|
// TODO: Support Blob, ArrayBuffer, JSON
|
||||||
|
body?: string | Object | FormData;
|
||||||
status?: number;
|
status?: number;
|
||||||
statusText?: string;
|
statusText?: string;
|
||||||
headers?: Headers | Object;
|
headers?: Headers | Object;
|
||||||
@ -43,23 +55,12 @@ export interface IResponse {
|
|||||||
url: string;
|
url: string;
|
||||||
totalBytes: number;
|
totalBytes: number;
|
||||||
bytesLoaded: number;
|
bytesLoaded: number;
|
||||||
blob(): Blob;
|
blob(): any; // TODO: Blob
|
||||||
arrayBuffer(): ArrayBuffer;
|
arrayBuffer(): any; // TODO: ArrayBuffer
|
||||||
text(): string;
|
text(): string;
|
||||||
json(): Object;
|
json(): Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnectionBackend {
|
|
||||||
createConnection(observer: any, config: IRequest): Connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Connection {
|
|
||||||
readyState: ReadyStates;
|
|
||||||
request: IRequest;
|
|
||||||
response: Rx.Subject<IResponse>;
|
|
||||||
dispose(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an interface to provide type information for {@link HttpFactory} when injecting.
|
* Provides an interface to provide type information for {@link HttpFactory} when injecting.
|
||||||
*
|
*
|
||||||
@ -83,4 +84,4 @@ export interface Connection {
|
|||||||
*/
|
*/
|
||||||
// Prefixed as IHttp because used in conjunction with Http class, but interface is callable
|
// Prefixed as IHttp because used in conjunction with Http class, but interface is callable
|
||||||
// constructor(@Inject(Http) http:IHttp)
|
// constructor(@Inject(Http) http:IHttp)
|
||||||
export interface IHttp { (url: string, options?: IRequestOptions): Rx.Observable<IResponse> }
|
export interface IHttp { (url: string, options?: IRequestOptions): EventEmitter }
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {RequestMethods, RequestModesOpts, RequestCredentialsOpts} from './enums';
|
import {RequestMethods, RequestModesOpts, RequestCredentialsOpts, RequestCacheOpts} from './enums';
|
||||||
import {URLSearchParams} from './url_search_params';
|
import {RequestOptions} from './base_request_options';
|
||||||
import {IRequestOptions, IRequest} from './interfaces';
|
import {IRequestOptions} from './interfaces';
|
||||||
import {Headers} from './headers';
|
import {Headers} from './headers';
|
||||||
import {BaseException, RegExpWrapper} from 'angular2/src/facade/lang';
|
import {BaseException, RegExpWrapper, CONST_EXPR, isPresent} from 'angular2/src/facade/lang';
|
||||||
|
import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
// TODO(jeffbcross): properly implement body accessors
|
// TODO(jeffbcross): properly implement body accessors
|
||||||
/**
|
/**
|
||||||
@ -13,7 +14,7 @@ import {BaseException, RegExpWrapper} from 'angular2/src/facade/lang';
|
|||||||
* but is considered a static value whose body can be accessed many times. There are other
|
* but is considered a static value whose body can be accessed many times. There are other
|
||||||
* differences in the implementation, but this is the most significant.
|
* differences in the implementation, but this is the most significant.
|
||||||
*/
|
*/
|
||||||
export class Request implements IRequest {
|
export class Request {
|
||||||
/**
|
/**
|
||||||
* Http method with which to perform the request.
|
* Http method with which to perform the request.
|
||||||
*
|
*
|
||||||
@ -27,22 +28,27 @@ export class Request implements IRequest {
|
|||||||
* Spec](https://fetch.spec.whatwg.org/#headers-class). {@link Headers} class reference.
|
* Spec](https://fetch.spec.whatwg.org/#headers-class). {@link Headers} class reference.
|
||||||
*/
|
*/
|
||||||
headers: Headers;
|
headers: Headers;
|
||||||
|
/** Url of the remote resource */
|
||||||
|
url: string;
|
||||||
|
// TODO: support URLSearchParams | FormData | Blob | ArrayBuffer
|
||||||
|
private _body: string;
|
||||||
|
cache: RequestCacheOpts;
|
||||||
|
// TODO(jeffbcross): determine way to add type to destructured args
|
||||||
|
constructor(options?: IRequestOptions) {
|
||||||
|
var requestOptions: RequestOptions = options instanceof
|
||||||
|
StringMap ? RequestOptions.fromStringWrapper(<StringMap<string, any>>options) :
|
||||||
|
<RequestOptions>options;
|
||||||
|
|
||||||
private _body: URLSearchParams | FormData | Blob | string;
|
this.url = requestOptions.url;
|
||||||
|
this._body = requestOptions.body;
|
||||||
constructor(/** Url of the remote resource */ public url: string,
|
this.method = requestOptions.method;
|
||||||
{body, method = RequestMethods.GET, mode = RequestModesOpts.Cors,
|
|
||||||
credentials = RequestCredentialsOpts.Omit,
|
|
||||||
headers = new Headers()}: IRequestOptions = {}) {
|
|
||||||
this._body = body;
|
|
||||||
this.method = method;
|
|
||||||
// Defaults to 'cors', consistent with browser
|
|
||||||
// TODO(jeffbcross): implement behavior
|
// TODO(jeffbcross): implement behavior
|
||||||
this.mode = mode;
|
this.mode = requestOptions.mode;
|
||||||
// Defaults to 'omit', consistent with browser
|
// Defaults to 'omit', consistent with browser
|
||||||
// TODO(jeffbcross): implement behavior
|
// TODO(jeffbcross): implement behavior
|
||||||
this.credentials = credentials;
|
this.credentials = requestOptions.credentials;
|
||||||
this.headers = headers;
|
this.headers = requestOptions.headers;
|
||||||
|
this.cache = requestOptions.cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,5 +56,5 @@ export class Request implements IRequest {
|
|||||||
* empty
|
* empty
|
||||||
* string.
|
* string.
|
||||||
*/
|
*/
|
||||||
text(): String { return this._body ? this._body.toString() : ''; }
|
text(): String { return isPresent(this._body) ? this._body.toString() : ''; }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {IResponse, ResponseOptions} from './interfaces';
|
import {IResponse, ResponseOptions} from './interfaces';
|
||||||
import {ResponseTypes} from './enums';
|
import {ResponseTypes} from './enums';
|
||||||
import {baseResponseOptions} from './base_response_options';
|
import {baseResponseOptions} from './base_response_options';
|
||||||
import {BaseException, isJsObject, isString, global} from 'angular2/src/facade/lang';
|
import {BaseException, isJsObject, isString, isPresent, Json} from 'angular2/src/facade/lang';
|
||||||
import {Headers} from './headers';
|
import {Headers} from './headers';
|
||||||
|
|
||||||
// TODO: make this injectable so baseResponseOptions can be overridden, mostly for the benefit of
|
// TODO: make this injectable so baseResponseOptions can be overridden, mostly for the benefit of
|
||||||
@ -72,34 +72,37 @@ export class Response implements IResponse {
|
|||||||
* Spec](https://fetch.spec.whatwg.org/#headers-class).
|
* Spec](https://fetch.spec.whatwg.org/#headers-class).
|
||||||
*/
|
*/
|
||||||
headers: Headers;
|
headers: Headers;
|
||||||
constructor(private _body?: string | Object | ArrayBuffer | JSON | FormData | Blob,
|
// TODO: Support ArrayBuffer, JSON, FormData, Blob
|
||||||
{status, statusText, headers, type, url}: ResponseOptions = baseResponseOptions) {
|
private _body: string | Object;
|
||||||
|
constructor({body, status, statusText, headers, type, url}: ResponseOptions = {}) {
|
||||||
if (isJsObject(headers)) {
|
if (isJsObject(headers)) {
|
||||||
headers = new Headers(headers);
|
headers = new Headers(headers);
|
||||||
}
|
}
|
||||||
this.status = status;
|
this._body = isPresent(body) ? body : baseResponseOptions.body;
|
||||||
this.statusText = statusText;
|
this.status = isPresent(status) ? status : baseResponseOptions.status;
|
||||||
this.headers = <Headers>headers;
|
this.statusText = isPresent(statusText) ? statusText : baseResponseOptions.statusText;
|
||||||
this.type = type;
|
this.headers = isPresent(headers) ? <Headers>headers : baseResponseOptions.headers;
|
||||||
this.url = url;
|
this.type = isPresent(type) ? type : baseResponseOptions.type;
|
||||||
|
this.url = isPresent(url) ? url : baseResponseOptions.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not yet implemented
|
* Not yet implemented
|
||||||
*/
|
*/
|
||||||
blob(): Blob {
|
// TODO: Blob return type
|
||||||
throw new BaseException('"blob()" method not implemented on Response superclass');
|
blob(): any { throw new BaseException('"blob()" method not implemented on Response superclass'); }
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to return body as parsed `JSON` object, or raises an exception.
|
* Attempts to return body as parsed `JSON` object, or raises an exception.
|
||||||
*/
|
*/
|
||||||
json(): JSON {
|
json(): Object {
|
||||||
|
var jsonResponse;
|
||||||
if (isJsObject(this._body)) {
|
if (isJsObject(this._body)) {
|
||||||
return <JSON>this._body;
|
jsonResponse = this._body;
|
||||||
} else if (isString(this._body)) {
|
} else if (isString(this._body)) {
|
||||||
return global.JSON.parse(<string>this._body);
|
jsonResponse = Json.parse(<string>this._body);
|
||||||
}
|
}
|
||||||
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +113,8 @@ export class Response implements IResponse {
|
|||||||
/**
|
/**
|
||||||
* Not yet implemented
|
* Not yet implemented
|
||||||
*/
|
*/
|
||||||
arrayBuffer(): ArrayBuffer {
|
// TODO: ArrayBuffer return type
|
||||||
|
arrayBuffer(): any {
|
||||||
throw new BaseException('"arrayBuffer()" method not implemented on Response superclass');
|
throw new BaseException('"arrayBuffer()" method not implemented on Response superclass');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import {isPresent, isBlank, StringWrapper} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, StringWrapper} from 'angular2/src/facade/lang';
|
||||||
import {Map, MapWrapper, List, ListWrapper} from 'angular2/src/facade/collection';
|
import {
|
||||||
|
Map,
|
||||||
|
MapWrapper,
|
||||||
|
List,
|
||||||
|
ListWrapper,
|
||||||
|
isListLikeIterable
|
||||||
|
} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
function paramParser(rawParams: string): Map<string, List<string>> {
|
function paramParser(rawParams: string): Map<string, List<string>> {
|
||||||
var map: Map<string, List<string>> = new Map();
|
var map: Map<string, List<string>> = new Map();
|
||||||
var params: List<string> = StringWrapper.split(rawParams, '&');
|
var params: List<string> = StringWrapper.split(rawParams, new RegExp('&'));
|
||||||
ListWrapper.forEach(params, (param: string) => {
|
ListWrapper.forEach(params, (param: string) => {
|
||||||
var split: List<string> = StringWrapper.split(param, '=');
|
var split: List<string> = StringWrapper.split(param, new RegExp('='));
|
||||||
var key = ListWrapper.get(split, 0);
|
var key = ListWrapper.get(split, 0);
|
||||||
var val = ListWrapper.get(split, 1);
|
var val = ListWrapper.get(split, 1);
|
||||||
var list = map.get(key) || [];
|
var list = isPresent(map.get(key)) ? map.get(key) : [];
|
||||||
list.push(val);
|
list.push(val);
|
||||||
map.set(key, list);
|
map.set(key, list);
|
||||||
});
|
});
|
||||||
@ -21,12 +27,23 @@ export class URLSearchParams {
|
|||||||
|
|
||||||
has(param: string): boolean { return this.paramsMap.has(param); }
|
has(param: string): boolean { return this.paramsMap.has(param); }
|
||||||
|
|
||||||
get(param: string): string { return ListWrapper.first(this.paramsMap.get(param)); }
|
get(param: string): string {
|
||||||
|
var storedParam = this.paramsMap.get(param);
|
||||||
|
if (isListLikeIterable(storedParam)) {
|
||||||
|
return ListWrapper.first(storedParam);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getAll(param: string): List<string> { return this.paramsMap.get(param) || []; }
|
getAll(param: string): List<string> {
|
||||||
|
var mapParam = this.paramsMap.get(param);
|
||||||
|
return isPresent(mapParam) ? mapParam : [];
|
||||||
|
}
|
||||||
|
|
||||||
append(param: string, val: string): void {
|
append(param: string, val: string): void {
|
||||||
var list = this.paramsMap.get(param) || [];
|
var mapParam = this.paramsMap.get(param);
|
||||||
|
var list = isPresent(mapParam) ? mapParam : [];
|
||||||
list.push(val);
|
list.push(val);
|
||||||
this.paramsMap.set(param, list);
|
this.paramsMap.set(param, list);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,15 @@ import {BrowserXHR} from 'angular2/src/http/backends/browser_xhr';
|
|||||||
import {XHRConnection, XHRBackend} from 'angular2/src/http/backends/xhr_backend';
|
import {XHRConnection, XHRBackend} from 'angular2/src/http/backends/xhr_backend';
|
||||||
import {bind, Injector} from 'angular2/di';
|
import {bind, Injector} from 'angular2/di';
|
||||||
import {Request} from 'angular2/src/http/static_request';
|
import {Request} from 'angular2/src/http/static_request';
|
||||||
|
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {RequestOptions} from 'angular2/src/http/base_request_options';
|
||||||
|
|
||||||
var abortSpy;
|
var abortSpy;
|
||||||
var sendSpy;
|
var sendSpy;
|
||||||
var openSpy;
|
var openSpy;
|
||||||
var addEventListenerSpy;
|
var addEventListenerSpy;
|
||||||
|
|
||||||
class MockBrowserXHR extends SpyObject {
|
class MockBrowserXHR extends BrowserXHR {
|
||||||
abort: any;
|
abort: any;
|
||||||
send: any;
|
send: any;
|
||||||
open: any;
|
open: any;
|
||||||
@ -29,24 +31,26 @@ class MockBrowserXHR extends SpyObject {
|
|||||||
responseText: string;
|
responseText: string;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.abort = abortSpy = this.spy('abort');
|
var spy = new SpyObject();
|
||||||
this.send = sendSpy = this.spy('send');
|
this.abort = abortSpy = spy.spy('abort');
|
||||||
this.open = openSpy = this.spy('open');
|
this.send = sendSpy = spy.spy('send');
|
||||||
this.addEventListener = addEventListenerSpy = this.spy('addEventListener');
|
this.open = openSpy = spy.spy('open');
|
||||||
|
this.addEventListener = addEventListenerSpy = spy.spy('addEventListener');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build() { return new MockBrowserXHR(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('XHRBackend', () => {
|
describe('XHRBackend', () => {
|
||||||
var backend;
|
var backend;
|
||||||
var sampleRequest;
|
var sampleRequest;
|
||||||
var constructSpy = new SpyObject();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
var injector =
|
var injector =
|
||||||
Injector.resolveAndCreate([bind(BrowserXHR).toValue(MockBrowserXHR), XHRBackend]);
|
Injector.resolveAndCreate([bind(BrowserXHR).toClass(MockBrowserXHR), XHRBackend]);
|
||||||
backend = injector.get(XHRBackend);
|
backend = injector.get(XHRBackend);
|
||||||
sampleRequest = new Request('https://google.com');
|
sampleRequest = new Request(new RequestOptions({url: 'https://google.com'}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a connection',
|
it('should create a connection',
|
||||||
@ -55,22 +59,21 @@ export function main() {
|
|||||||
|
|
||||||
describe('XHRConnection', () => {
|
describe('XHRConnection', () => {
|
||||||
it('should call abort when disposed', () => {
|
it('should call abort when disposed', () => {
|
||||||
var connection = new XHRConnection(sampleRequest, MockBrowserXHR);
|
var connection = new XHRConnection(sampleRequest, new MockBrowserXHR());
|
||||||
connection.dispose();
|
connection.dispose();
|
||||||
expect(abortSpy).toHaveBeenCalled();
|
expect(abortSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should automatically call open with method and url', () => {
|
it('should automatically call open with method and url', () => {
|
||||||
new XHRConnection(sampleRequest, MockBrowserXHR);
|
new XHRConnection(sampleRequest, new MockBrowserXHR());
|
||||||
expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
|
expect(openSpy).toHaveBeenCalledWith('GET', sampleRequest.url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should automatically call send on the backend with request body', () => {
|
it('should automatically call send on the backend with request body', () => {
|
||||||
var body = 'Some body to love';
|
var body = 'Some body to love';
|
||||||
var request = new Request('https://google.com', {body: body});
|
new XHRConnection(new Request(new RequestOptions({body: body})), new MockBrowserXHR());
|
||||||
var connection = new XHRConnection(request, MockBrowserXHR);
|
|
||||||
expect(sendSpy).toHaveBeenCalledWith(body);
|
expect(sendSpy).toHaveBeenCalledWith(body);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {Headers} from 'angular2/src/http/headers';
|
import {Headers} from 'angular2/src/http/headers';
|
||||||
import {Map} from 'angular2/src/facade/collection';
|
import {Map, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {
|
import {
|
||||||
AsyncTestCompleter,
|
AsyncTestCompleter,
|
||||||
beforeEach,
|
beforeEach,
|
||||||
@ -17,27 +17,24 @@ export function main() {
|
|||||||
it('should conform to spec', () => {
|
it('should conform to spec', () => {
|
||||||
// Examples borrowed from https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers
|
// Examples borrowed from https://developer.mozilla.org/en-US/docs/Web/API/Headers/Headers
|
||||||
// Spec at https://fetch.spec.whatwg.org/#dom-headers
|
// Spec at https://fetch.spec.whatwg.org/#dom-headers
|
||||||
var myHeaders = new Headers(); // Currently empty
|
var firstHeaders = new Headers(); // Currently empty
|
||||||
myHeaders.append('Content-Type', 'image/jpeg');
|
firstHeaders.append('Content-Type', 'image/jpeg');
|
||||||
expect(myHeaders.get('Content-Type')).toBe('image/jpeg');
|
expect(firstHeaders.get('Content-Type')).toBe('image/jpeg');
|
||||||
var httpHeaders = {
|
var httpHeaders = StringMapWrapper.create();
|
||||||
'Content-Type': 'image/jpeg',
|
StringMapWrapper.set(httpHeaders, 'Content-Type', 'image/jpeg');
|
||||||
'Accept-Charset': 'utf-8',
|
StringMapWrapper.set(httpHeaders, 'Accept-Charset', 'utf-8');
|
||||||
'X-My-Custom-Header': 'Zeke are cool'
|
StringMapWrapper.set(httpHeaders, 'X-My-Custom-Header', 'Zeke are cool');
|
||||||
};
|
var secondHeaders = new Headers(httpHeaders);
|
||||||
var myHeaders = new Headers(httpHeaders);
|
var secondHeadersObj = new Headers(secondHeaders);
|
||||||
var secondHeadersObj = new Headers(myHeaders);
|
|
||||||
expect(secondHeadersObj.get('Content-Type')).toBe('image/jpeg');
|
expect(secondHeadersObj.get('Content-Type')).toBe('image/jpeg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('initialization', () => {
|
describe('initialization', () => {
|
||||||
it('should create a private headersMap map',
|
|
||||||
() => { expect(new Headers()._headersMap).toBeAnInstanceOf(Map); });
|
|
||||||
|
|
||||||
|
|
||||||
it('should merge values in provided dictionary', () => {
|
it('should merge values in provided dictionary', () => {
|
||||||
var headers = new Headers({foo: 'bar'});
|
var map = StringMapWrapper.create();
|
||||||
|
StringMapWrapper.set(map, 'foo', 'bar');
|
||||||
|
var headers = new Headers(map);
|
||||||
expect(headers.get('foo')).toBe('bar');
|
expect(headers.get('foo')).toBe('bar');
|
||||||
expect(headers.getAll('foo')).toEqual(['bar']);
|
expect(headers.getAll('foo')).toEqual(['bar']);
|
||||||
});
|
});
|
||||||
@ -46,7 +43,9 @@ export function main() {
|
|||||||
|
|
||||||
describe('.set()', () => {
|
describe('.set()', () => {
|
||||||
it('should clear all values and re-set for the provided key', () => {
|
it('should clear all values and re-set for the provided key', () => {
|
||||||
var headers = new Headers({foo: 'bar'});
|
var map = StringMapWrapper.create();
|
||||||
|
StringMapWrapper.set(map, 'foo', 'bar');
|
||||||
|
var headers = new Headers(map);
|
||||||
expect(headers.get('foo')).toBe('bar');
|
expect(headers.get('foo')).toBe('bar');
|
||||||
expect(headers.getAll('foo')).toEqual(['bar']);
|
expect(headers.getAll('foo')).toEqual(['bar']);
|
||||||
headers.set('foo', 'baz');
|
headers.set('foo', 'baz');
|
||||||
@ -57,9 +56,10 @@ export function main() {
|
|||||||
|
|
||||||
it('should convert input array to string', () => {
|
it('should convert input array to string', () => {
|
||||||
var headers = new Headers();
|
var headers = new Headers();
|
||||||
headers.set('foo', ['bar', 'baz']);
|
var inputArr = ['bar', 'baz'];
|
||||||
expect(headers.get('foo')).toBe('bar,baz');
|
headers.set('foo', inputArr);
|
||||||
expect(headers.getAll('foo')).toEqual(['bar,baz']);
|
expect(/bar, ?baz/g.test(headers.get('foo'))).toBe(true);
|
||||||
|
expect(/bar, ?baz/g.test(headers.getAll('foo')[0])).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
AsyncTestCompleter,
|
AsyncTestCompleter,
|
||||||
|
afterEach,
|
||||||
beforeEach,
|
beforeEach,
|
||||||
ddescribe,
|
ddescribe,
|
||||||
describe,
|
describe,
|
||||||
@ -11,13 +12,14 @@ import {
|
|||||||
SpyObject
|
SpyObject
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {Http, HttpFactory} from 'angular2/src/http/http';
|
import {Http, HttpFactory} from 'angular2/src/http/http';
|
||||||
import {XHRBackend} from 'angular2/src/http/backends/xhr_backend';
|
|
||||||
import {Injector, bind} from 'angular2/di';
|
import {Injector, bind} from 'angular2/di';
|
||||||
import {MockBackend} from 'angular2/src/http/backends/mock_backend';
|
import {MockBackend} from 'angular2/src/http/backends/mock_backend';
|
||||||
import {Response} from 'angular2/src/http/static_response';
|
import {Response} from 'angular2/src/http/static_response';
|
||||||
import {RequestMethods} from 'angular2/src/http/enums';
|
import {RequestMethods} from 'angular2/src/http/enums';
|
||||||
import {BaseRequestOptions} from 'angular2/src/http/base_request_options';
|
import {BaseRequestOptions, RequestOptions} from 'angular2/src/http/base_request_options';
|
||||||
import {Request} from 'angular2/src/http/static_request';
|
import {Request} from 'angular2/src/http/static_request';
|
||||||
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {ConnectionBackend} from 'angular2/src/http/interfaces';
|
||||||
|
|
||||||
class SpyObserver extends SpyObject {
|
class SpyObserver extends SpyObject {
|
||||||
onNext: Function;
|
onNext: Function;
|
||||||
@ -34,20 +36,19 @@ class SpyObserver extends SpyObject {
|
|||||||
export function main() {
|
export function main() {
|
||||||
describe('http', () => {
|
describe('http', () => {
|
||||||
var url = 'http://foo.bar';
|
var url = 'http://foo.bar';
|
||||||
var http;
|
var http: Http;
|
||||||
var injector;
|
var injector: Injector;
|
||||||
var backend: MockBackend;
|
var backend: MockBackend;
|
||||||
var baseResponse;
|
var baseResponse;
|
||||||
var sampleObserver;
|
|
||||||
var httpFactory;
|
var httpFactory;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
injector = Injector.resolveAndCreate([
|
injector = Injector.resolveAndCreate([
|
||||||
BaseRequestOptions,
|
BaseRequestOptions,
|
||||||
MockBackend,
|
MockBackend,
|
||||||
bind(XHRBackend).toClass(MockBackend),
|
bind(ConnectionBackend).toClass(MockBackend),
|
||||||
bind(HttpFactory).toFactory(HttpFactory, [MockBackend, BaseRequestOptions]),
|
bind(HttpFactory).toFactory(HttpFactory, [MockBackend, BaseRequestOptions]),
|
||||||
bind(Http).toFactory(
|
bind(Http).toFactory(
|
||||||
function(backend: XHRBackend, defaultOptions: BaseRequestOptions) {
|
function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
|
||||||
return new Http(backend, defaultOptions);
|
return new Http(backend, defaultOptions);
|
||||||
},
|
},
|
||||||
[MockBackend, BaseRequestOptions])
|
[MockBackend, BaseRequestOptions])
|
||||||
@ -55,224 +56,194 @@ export function main() {
|
|||||||
http = injector.get(Http);
|
http = injector.get(Http);
|
||||||
httpFactory = injector.get(HttpFactory);
|
httpFactory = injector.get(HttpFactory);
|
||||||
backend = injector.get(MockBackend);
|
backend = injector.get(MockBackend);
|
||||||
baseResponse = new Response('base response');
|
baseResponse = new Response({body: 'base response'});
|
||||||
sampleObserver = new SpyObserver();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => backend.verifyNoPendingRequests());
|
afterEach(() => backend.verifyNoPendingRequests());
|
||||||
|
|
||||||
describe('HttpFactory', () => {
|
describe('HttpFactory', () => {
|
||||||
it('should return an Observable', () => {
|
it('should return an Observable', () => {
|
||||||
expect(typeof httpFactory(url).subscribe).toBe('function');
|
expect(ObservableWrapper.isObservable(httpFactory(url))).toBe(true);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should perform a get request for given url if only passed a string',
|
it('should perform a get request for given url if only passed a string',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
var connection;
|
ObservableWrapper.subscribe(backend.connections, c => c.mockRespond(baseResponse));
|
||||||
backend.connections.subscribe((c) => connection = c);
|
ObservableWrapper.subscribe(httpFactory('http://basic.connection'), res => {
|
||||||
var subscription = httpFactory('http://basic.connection')
|
|
||||||
.subscribe(res => {
|
|
||||||
expect(res.text()).toBe('base response');
|
expect(res.text()).toBe('base response');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
connection.mockRespond(baseResponse)
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should accept a fully-qualified request as its only parameter', () => {
|
it('should accept a fully-qualified request as its only parameter',
|
||||||
var req = new Request('https://google.com');
|
inject([AsyncTestCompleter], (async) => {
|
||||||
backend.connections.subscribe(c => {
|
var req = new Request(new RequestOptions({url: 'https://google.com'}));
|
||||||
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.url).toBe('https://google.com');
|
expect(c.request.url).toBe('https://google.com');
|
||||||
c.mockRespond(new Response('Thank you'));
|
c.mockRespond(new Response({body: 'Thank you'}));
|
||||||
});
|
|
||||||
httpFactory(req).subscribe(() => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should perform a get request for given url if passed a ConnectionConfig instance',
|
|
||||||
inject([AsyncTestCompleter], async => {
|
|
||||||
var connection;
|
|
||||||
backend.connections.subscribe((c) => connection = c);
|
|
||||||
httpFactory('http://basic.connection', {method: RequestMethods.GET})
|
|
||||||
.subscribe(res => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
connection.mockRespond(baseResponse)
|
ObservableWrapper.subscribe(httpFactory(req), (res) => {});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// TODO: make dart not complain about "argument type 'Map' cannot be assigned to the parameter
|
||||||
it('should perform a get request for given url if passed a dictionary',
|
// type 'IRequestOptions'"
|
||||||
inject([AsyncTestCompleter], async => {
|
// xit('should perform a get request for given url if passed a dictionary',
|
||||||
var connection;
|
// inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => connection = c);
|
// ObservableWrapper.subscribe(backend.connections, c => c.mockRespond(baseResponse));
|
||||||
httpFactory(url, {method: RequestMethods.GET})
|
// ObservableWrapper.subscribe(httpFactory(url, {method: RequestMethods.GET}), res => {
|
||||||
.subscribe(res => {
|
// expect(res.text()).toBe('base response');
|
||||||
expect(res.text()).toBe('base response');
|
// async.done();
|
||||||
async.done();
|
// });
|
||||||
});
|
// }));
|
||||||
connection.mockRespond(baseResponse)
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('Http', () => {
|
describe('Http', () => {
|
||||||
describe('.request()', () => {
|
describe('.request()', () => {
|
||||||
it('should return an Observable',
|
it('should return an Observable',
|
||||||
() => { expect(typeof http.request(url).subscribe).toBe('function'); });
|
() => { expect(ObservableWrapper.isObservable(http.request(url))).toBe(true); });
|
||||||
|
|
||||||
|
|
||||||
it('should accept a fully-qualified request as its only parameter', () => {
|
it('should accept a fully-qualified request as its only parameter',
|
||||||
var req = new Request('https://google.com');
|
inject([AsyncTestCompleter], (async) => {
|
||||||
backend.connections.subscribe(c => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.url).toBe('https://google.com');
|
expect(c.request.url).toBe('https://google.com');
|
||||||
c.mockRespond(new Response('Thank you'));
|
c.mockRespond(new Response({body: 'Thank you'}));
|
||||||
});
|
async.done();
|
||||||
http.request(req).subscribe(() => {});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
ObservableWrapper.subscribe(
|
||||||
|
http.request(new Request(new RequestOptions({url: 'https://google.com'}))),
|
||||||
|
(res) => {});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should perform a get request for given url if only passed a string',
|
it('should perform a get request for given url if only passed a string',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
var connection;
|
ObservableWrapper.subscribe(backend.connections, c => c.mockRespond(baseResponse));
|
||||||
backend.connections.subscribe((c) => connection = c);
|
ObservableWrapper.subscribe(http.request('http://basic.connection'), res => {
|
||||||
var subscription = http.request('http://basic.connection')
|
|
||||||
.subscribe(res => {
|
|
||||||
expect(res.text()).toBe('base response');
|
expect(res.text()).toBe('base response');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
connection.mockRespond(baseResponse)
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// TODO: make dart not complain about "argument type 'Map' cannot be assigned to the
|
||||||
it('should perform a get request for given url if passed a ConnectionConfig instance',
|
// parameter type 'IRequestOptions'"
|
||||||
inject([AsyncTestCompleter], async => {
|
// xit('should perform a get request for given url if passed a dictionary',
|
||||||
var connection;
|
// inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => connection = c);
|
// ObservableWrapper.subscribe(backend.connections, c => c.mockRespond(baseResponse));
|
||||||
http.request('http://basic.connection', {method: RequestMethods.GET})
|
// ObservableWrapper.subscribe(http.request(url, {method: RequestMethods.GET}), res =>
|
||||||
.subscribe(res => {
|
// {
|
||||||
expect(res.text()).toBe('base response');
|
// expect(res.text()).toBe('base response');
|
||||||
async.done();
|
// async.done();
|
||||||
|
// });
|
||||||
|
// }));
|
||||||
});
|
});
|
||||||
connection.mockRespond(baseResponse);
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should perform a get request for given url if passed a dictionary',
|
|
||||||
inject([AsyncTestCompleter], async => {
|
|
||||||
var connection;
|
|
||||||
backend.connections.subscribe((c) => connection = c);
|
|
||||||
http.request(url, {method: RequestMethods.GET})
|
|
||||||
.subscribe(res => {
|
|
||||||
expect(res.text()).toBe('base response');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
connection.mockRespond(baseResponse);
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
describe('.get()', () => {
|
describe('.get()', () => {
|
||||||
it('should perform a get request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a get request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.GET);
|
expect(c.request.method).toBe(RequestMethods.GET);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.get(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.get(url), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('.post()', () => {
|
describe('.post()', () => {
|
||||||
it('should perform a post request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a post request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.POST);
|
expect(c.request.method).toBe(RequestMethods.POST);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.post(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.post(url, 'post me'), res => {});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
||||||
var body = 'this is my put body';
|
var body = 'this is my post body';
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.text()).toBe(body);
|
expect(c.request.text()).toBe(body);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.post(url, body).subscribe(res => {});
|
ObservableWrapper.subscribe(http.post(url, body), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('.put()', () => {
|
describe('.put()', () => {
|
||||||
it('should perform a put request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a put request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.PUT);
|
expect(c.request.method).toBe(RequestMethods.PUT);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.put(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.put(url, 'put me'), res => {});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
||||||
var body = 'this is my put body';
|
var body = 'this is my put body';
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.text()).toBe(body);
|
expect(c.request.text()).toBe(body);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.put(url, body).subscribe(res => {});
|
ObservableWrapper.subscribe(http.put(url, body), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('.delete()', () => {
|
describe('.delete()', () => {
|
||||||
it('should perform a delete request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a delete request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.DELETE);
|
expect(c.request.method).toBe(RequestMethods.DELETE);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.delete(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.delete(url), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('.patch()', () => {
|
describe('.patch()', () => {
|
||||||
it('should perform a patch request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a patch request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.PATCH);
|
expect(c.request.method).toBe(RequestMethods.PATCH);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.patch(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.patch(url, 'this is my patch body'), res => {});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
it('should attach the provided body to the request', inject([AsyncTestCompleter], async => {
|
||||||
var body = 'this is my put body';
|
var body = 'this is my patch body';
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.text()).toBe(body);
|
expect(c.request.text()).toBe(body);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.patch(url, body).subscribe(res => {});
|
ObservableWrapper.subscribe(http.patch(url, body), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('.head()', () => {
|
describe('.head()', () => {
|
||||||
it('should perform a head request for given url', inject([AsyncTestCompleter], async => {
|
it('should perform a head request for given url', inject([AsyncTestCompleter], async => {
|
||||||
backend.connections.subscribe((c) => {
|
ObservableWrapper.subscribe(backend.connections, c => {
|
||||||
expect(c.request.method).toBe(RequestMethods.HEAD);
|
expect(c.request.method).toBe(RequestMethods.HEAD);
|
||||||
backend.resolveAllConnections();
|
backend.resolveAllConnections();
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
http.head(url).subscribe(res => {});
|
ObservableWrapper.subscribe(http.head(url), res => {});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -22,14 +22,14 @@ export function main() {
|
|||||||
// Compliant with spec described at https://url.spec.whatwg.org/#urlsearchparams
|
// Compliant with spec described at https://url.spec.whatwg.org/#urlsearchparams
|
||||||
expect(searchParams.has("topic")).toBe(true);
|
expect(searchParams.has("topic")).toBe(true);
|
||||||
expect(searchParams.has("foo")).toBe(false);
|
expect(searchParams.has("foo")).toBe(false);
|
||||||
expect(searchParams.get("topic")).toBe("api");
|
expect(searchParams.get("topic")).toEqual("api");
|
||||||
expect(searchParams.getAll("topic")).toEqual(["api"]);
|
expect(searchParams.getAll("topic")).toEqual(["api"]);
|
||||||
expect(searchParams.get("foo")).toBe(null);
|
expect(searchParams.get("foo")).toBe(null);
|
||||||
searchParams.append("topic", "webdev");
|
searchParams.append("topic", "webdev");
|
||||||
expect(searchParams.getAll("topic")).toEqual(["api", "webdev"]);
|
expect(searchParams.getAll("topic")).toEqual(["api", "webdev"]);
|
||||||
expect(searchParams.toString()).toBe("q=URLUtils.searchParams&topic=api&topic=webdev");
|
expect(searchParams.toString()).toEqual("q=URLUtils.searchParams&topic=api&topic=webdev");
|
||||||
searchParams.delete("topic");
|
searchParams.delete("topic");
|
||||||
expect(searchParams.toString()).toBe("q=URLUtils.searchParams");
|
expect(searchParams.toString()).toEqual("q=URLUtils.searchParams");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
5
modules/examples/e2e_test/http/http_spec.dart
Normal file
5
modules/examples/e2e_test/http/http_spec.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
library examples.e2e_test.http.http_spec;
|
||||||
|
|
||||||
|
main() {
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import {bootstrap, Component, View, NgFor, Inject} from 'angular2/angular2';
|
import {bootstrap, Component, View, NgFor, Inject} from 'angular2/angular2';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
import {Http, httpInjectables} from 'angular2/http';
|
import {Http, httpInjectables} from 'angular2/http';
|
||||||
|
|
||||||
@Component({selector: 'http-app'})
|
@Component({selector: 'http-app'})
|
||||||
@ -8,7 +9,7 @@ import {Http, httpInjectables} from 'angular2/http';
|
|||||||
<h1>people</h1>
|
<h1>people</h1>
|
||||||
<ul class="people">
|
<ul class="people">
|
||||||
<li *ng-for="#person of people">
|
<li *ng-for="#person of people">
|
||||||
hello, {{person.name}}
|
hello, {{person['name']}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
`
|
`
|
||||||
@ -16,6 +17,6 @@ import {Http, httpInjectables} from 'angular2/http';
|
|||||||
export class HttpCmp {
|
export class HttpCmp {
|
||||||
people: Object;
|
people: Object;
|
||||||
constructor(http: Http) {
|
constructor(http: Http) {
|
||||||
http.get('./people.json').map(res => res.json()).subscribe(people => this.people = people);
|
ObservableWrapper.subscribe(http.get('./people.json'), res => this.people = res.json());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -302,6 +302,7 @@ function define(classOrName, check) {
|
|||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var assert: any = function(value) {
|
var assert: any = function(value) {
|
||||||
return {
|
return {
|
||||||
is: function is(...types) {
|
is: function is(...types) {
|
||||||
|
@ -5,8 +5,6 @@ config.baseUrl = 'http://localhost:8002/';
|
|||||||
|
|
||||||
config.exclude.push(
|
config.exclude.push(
|
||||||
'dist/js/cjs/examples/e2e_test/sourcemap/sourcemap_spec.js',
|
'dist/js/cjs/examples/e2e_test/sourcemap/sourcemap_spec.js',
|
||||||
//TODO(jeffbcross): remove when http has been implemented for dart
|
|
||||||
'dist/js/cjs/examples/e2e_test/http/http_spec.js',
|
|
||||||
// TODO: remove this line when largetable dart has been added
|
// TODO: remove this line when largetable dart has been added
|
||||||
'dist/js/cjs/benchmarks_external/e2e_test/largetable_perf.js',
|
'dist/js/cjs/benchmarks_external/e2e_test/largetable_perf.js',
|
||||||
'dist/js/cjs/benchmarks_external/e2e_test/polymer_tree_perf.js',
|
'dist/js/cjs/benchmarks_external/e2e_test/polymer_tree_perf.js',
|
||||||
|
@ -44,16 +44,7 @@ function stripModulePrefix(relativePath: string): string {
|
|||||||
|
|
||||||
function getSourceTree() {
|
function getSourceTree() {
|
||||||
// Transpile everything in 'modules' except for rtts_assertions.
|
// Transpile everything in 'modules' except for rtts_assertions.
|
||||||
var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart'],
|
var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart'], ['rtts_assert/**/*']);
|
||||||
// TODO(jeffbcross): add http when lib supports dart
|
|
||||||
[
|
|
||||||
'rtts_assert/**/*',
|
|
||||||
'examples/e2e_test/http/**/*',
|
|
||||||
'examples/src/http/**/*',
|
|
||||||
'angular2/src/http/**/*',
|
|
||||||
'angular2/test/http/**/*',
|
|
||||||
'angular2/http.ts'
|
|
||||||
]);
|
|
||||||
var transpiled = ts2dart(tsInputTree, {
|
var transpiled = ts2dart(tsInputTree, {
|
||||||
generateLibraryName: true,
|
generateLibraryName: true,
|
||||||
generateSourceMap: false,
|
generateSourceMap: false,
|
||||||
@ -107,6 +98,11 @@ function getHtmlSourcesTree() {
|
|||||||
return mergeTrees([htmlSrcsTree, urlParamsToFormTree]);
|
return mergeTrees([htmlSrcsTree, urlParamsToFormTree]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getExamplesJsonTree() {
|
||||||
|
// Copy JSON files
|
||||||
|
return modulesFunnel(['examples/**/*.json']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getTemplatedPubspecsTree() {
|
function getTemplatedPubspecsTree() {
|
||||||
// The JSON structure for templating pubspec.yaml files.
|
// The JSON structure for templating pubspec.yaml files.
|
||||||
@ -154,7 +150,7 @@ function getDocsTree() {
|
|||||||
|
|
||||||
module.exports = function makeDartTree(options: AngularBuilderOptions) {
|
module.exports = function makeDartTree(options: AngularBuilderOptions) {
|
||||||
var dartSources = dartfmt(getSourceTree(), {dartSDK: options.dartSDK, logs: options.logs});
|
var dartSources = dartfmt(getSourceTree(), {dartSDK: options.dartSDK, logs: options.logs});
|
||||||
var sourceTree = mergeTrees([dartSources, getHtmlSourcesTree()]);
|
var sourceTree = mergeTrees([dartSources, getHtmlSourcesTree(), getExamplesJsonTree()]);
|
||||||
sourceTree = fixDartFolderLayout(sourceTree);
|
sourceTree = fixDartFolderLayout(sourceTree);
|
||||||
|
|
||||||
var dartTree = mergeTrees([sourceTree, getTemplatedPubspecsTree(), getDocsTree()]);
|
var dartTree = mergeTrees([sourceTree, getTemplatedPubspecsTree(), getDocsTree()]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user