1- import { Http , BaseRequestOptions , Response , ResponseOptions , RequestMethod , XHRBackend , RequestOptions } from '@angular/http' ;
2- import { MockBackend , MockConnection } from '@angular/http/testing' ;
1+ import { Injectable } from '@angular/core' ;
2+ import { HttpRequest , HttpResponse , HttpHandler , HttpEvent , HttpInterceptor , HTTP_INTERCEPTORS } from '@angular/common/http' ;
3+ import { Observable } from 'rxjs/Observable' ;
4+ import 'rxjs/add/observable/of' ;
5+ import 'rxjs/add/observable/throw' ;
6+ import 'rxjs/add/operator/delay' ;
7+ import 'rxjs/add/operator/mergeMap' ;
8+ import 'rxjs/add/operator/materialize' ;
9+ import 'rxjs/add/operator/dematerialize' ;
310
4- export function fakeBackendFactory ( backend : MockBackend , options : BaseRequestOptions , realBackend : XHRBackend ) {
5- // array in local storage for registered users
6- let users : any [ ] = JSON . parse ( localStorage . getItem ( 'users' ) ) || [ ] ;
11+ @Injectable ( )
12+ export class FakeBackendInterceptor implements HttpInterceptor {
713
8- // configure fake backend
9- backend . connections . subscribe ( ( connection : MockConnection ) => {
10- // wrap in timeout to simulate server api call
11- setTimeout ( ( ) => {
14+ constructor ( ) { }
1215
13- // authenticate
14- if ( connection . request . url . endsWith ( '/api/authenticate' ) && connection . request . method === RequestMethod . Post ) {
15- // get parameters from post request
16- let params = JSON . parse ( connection . request . getBody ( ) ) ;
16+ intercept ( request : HttpRequest < any > , next : HttpHandler ) : Observable < HttpEvent < any > > {
17+ // array in local storage for registered users
18+ let users : any [ ] = JSON . parse ( localStorage . getItem ( 'users' ) ) || [ ] ;
19+
20+ // wrap in delayed observable to simulate server api call
21+ return Observable . of ( null ) . mergeMap ( ( ) => {
1722
23+ // authenticate
24+ if ( request . url . endsWith ( '/api/authenticate' ) && request . method === 'POST' ) {
1825 // find if any user matches login credentials
1926 let filteredUsers = users . filter ( user => {
20- return user . username === params . username && user . password === params . password ;
27+ return user . username === request . body . username && user . password === request . body . password ;
2128 } ) ;
2229
2330 if ( filteredUsers . length ) {
2431 // if login details are valid return 200 OK with user details and fake jwt token
2532 let user = filteredUsers [ 0 ] ;
26- connection . mockRespond ( new Response ( new ResponseOptions ( {
27- status : 200 ,
28- body : {
29- id : user . id ,
30- username : user . username ,
31- firstName : user . firstName ,
32- lastName : user . lastName ,
33- token : 'fake-jwt-token'
34- }
35- } ) ) ) ;
33+ let body = {
34+ id : user . id ,
35+ username : user . username ,
36+ firstName : user . firstName ,
37+ lastName : user . lastName ,
38+ token : 'fake-jwt-token'
39+ } ;
40+
41+ return Observable . of ( new HttpResponse ( { status : 200 , body : body } ) ) ;
3642 } else {
3743 // else return 400 bad request
38- connection . mockError ( new Error ( 'Username or password is incorrect' ) ) ;
44+ return Observable . throw ( 'Username or password is incorrect' ) ;
3945 }
40-
41- return ;
4246 }
4347
4448 // get users
45- if ( connection . request . url . endsWith ( '/api/users' ) && connection . request . method === RequestMethod . Get ) {
49+ if ( request . url . endsWith ( '/api/users' ) && request . method === 'GET' ) {
4650 // check for fake auth token in header and return users if valid, this security is implemented server side in a real application
47- if ( connection . request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
48- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 200 , body : users } ) ) ) ;
51+ if ( request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
52+ return Observable . of ( new HttpResponse ( { status : 200 , body : users } ) ) ;
4953 } else {
5054 // return 401 not authorised if token is null or invalid
51- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 401 } ) ) ) ;
55+ return Observable . throw ( 'Unauthorised' ) ;
5256 }
53-
54- return ;
5557 }
5658
5759 // get user by id
58- if ( connection . request . url . match ( / \/ a p i \/ u s e r s \/ \d + $ / ) && connection . request . method === RequestMethod . Get ) {
60+ if ( request . url . match ( / \/ a p i \/ u s e r s \/ \d + $ / ) && request . method === 'GET' ) {
5961 // check for fake auth token in header and return user if valid, this security is implemented server side in a real application
60- if ( connection . request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
62+ if ( request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
6163 // find user by id in users array
62- let urlParts = connection . request . url . split ( '/' ) ;
64+ let urlParts = request . url . split ( '/' ) ;
6365 let id = parseInt ( urlParts [ urlParts . length - 1 ] ) ;
6466 let matchedUsers = users . filter ( user => { return user . id === id ; } ) ;
6567 let user = matchedUsers . length ? matchedUsers [ 0 ] : null ;
6668
67- // respond 200 OK with user
68- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 200 , body : user } ) ) ) ;
69+ return Observable . of ( new HttpResponse ( { status : 200 , body : user } ) ) ;
6970 } else {
7071 // return 401 not authorised if token is null or invalid
71- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 401 } ) ) ) ;
72+ return Observable . throw ( 'Unauthorised' ) ;
7273 }
73-
74- return ;
7574 }
7675
7776 // create user
78- if ( connection . request . url . endsWith ( '/api/users' ) && connection . request . method === RequestMethod . Post ) {
77+ if ( request . url . endsWith ( '/api/users' ) && request . method === 'POST' ) {
7978 // get new user object from post body
80- let newUser = JSON . parse ( connection . request . getBody ( ) ) ;
79+ let newUser = request . body ;
8180
8281 // validation
8382 let duplicateUser = users . filter ( user => { return user . username === newUser . username ; } ) . length ;
8483 if ( duplicateUser ) {
85- return connection . mockError ( new Error ( 'Username "' + newUser . username + '" is already taken' ) ) ;
84+ return Observable . throw ( 'Username "' + newUser . username + '" is already taken' ) ;
8685 }
8786
8887 // save new user
@@ -91,17 +90,15 @@ export function fakeBackendFactory(backend: MockBackend, options: BaseRequestOpt
9190 localStorage . setItem ( 'users' , JSON . stringify ( users ) ) ;
9291
9392 // respond 200 OK
94- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 200 } ) ) ) ;
95-
96- return ;
93+ return Observable . of ( new HttpResponse ( { status : 200 } ) ) ;
9794 }
9895
9996 // delete user
100- if ( connection . request . url . match ( / \/ a p i \/ u s e r s \/ \d + $ / ) && connection . request . method === RequestMethod . Delete ) {
97+ if ( request . url . match ( / \/ a p i \/ u s e r s \/ \d + $ / ) && request . method === 'DELETE' ) {
10198 // check for fake auth token in header and return user if valid, this security is implemented server side in a real application
102- if ( connection . request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
99+ if ( request . headers . get ( 'Authorization' ) === 'Bearer fake-jwt-token' ) {
103100 // find user by id in users array
104- let urlParts = connection . request . url . split ( '/' ) ;
101+ let urlParts = request . url . split ( '/' ) ;
105102 let id = parseInt ( urlParts [ urlParts . length - 1 ] ) ;
106103 for ( let i = 0 ; i < users . length ; i ++ ) {
107104 let user = users [ i ] ;
@@ -114,43 +111,28 @@ export function fakeBackendFactory(backend: MockBackend, options: BaseRequestOpt
114111 }
115112
116113 // respond 200 OK
117- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 200 } ) ) ) ;
114+ return Observable . of ( new HttpResponse ( { status : 200 } ) ) ;
118115 } else {
119116 // return 401 not authorised if token is null or invalid
120- connection . mockRespond ( new Response ( new ResponseOptions ( { status : 401 } ) ) ) ;
117+ return Observable . throw ( 'Unauthorised' ) ;
121118 }
122-
123- return ;
124119 }
125120
126121 // pass through any requests not handled above
127- let realHttp = new Http ( realBackend , options ) ;
128- let requestOptions = new RequestOptions ( {
129- method : connection . request . method ,
130- headers : connection . request . headers ,
131- body : connection . request . getBody ( ) ,
132- url : connection . request . url ,
133- withCredentials : connection . request . withCredentials ,
134- responseType : connection . request . responseType
135- } ) ;
136- realHttp . request ( connection . request . url , requestOptions )
137- . subscribe ( ( response : Response ) => {
138- connection . mockRespond ( response ) ;
139- } ,
140- ( error : any ) => {
141- connection . mockError ( error ) ;
142- } ) ;
143-
144- } , 500 ) ;
145-
146- } ) ;
122+ return next . handle ( request ) ;
123+
124+ } )
147125
148- return new Http ( backend , options ) ;
149- } ;
126+ // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
127+ . materialize ( )
128+ . delay ( 500 )
129+ . dematerialize ( ) ;
130+ }
131+ }
150132
151133export let fakeBackendProvider = {
152134 // use fake backend in place of Http service for backend-less development
153- provide : Http ,
154- useFactory : fakeBackendFactory ,
155- deps : [ MockBackend , BaseRequestOptions , XHRBackend ]
135+ provide : HTTP_INTERCEPTORS ,
136+ useClass : FakeBackendInterceptor ,
137+ multi : true
156138} ;
0 commit comments