Skip to content

Commit c722edd

Browse files
committed
refactored fake backend
1 parent 6dede63 commit c722edd

File tree

2 files changed

+66
-43
lines changed

2 files changed

+66
-43
lines changed

src/app/_helpers/fake-backend.ts

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,56 +13,59 @@ const users: User[] = [
1313
@Injectable()
1414
export class FakeBackendInterceptor implements HttpInterceptor {
1515
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
16-
const authHeader = request.headers.get('Authorization');
17-
const isLoggedIn = authHeader && authHeader.startsWith('Bearer fake-jwt-token');
18-
const roleString = isLoggedIn && authHeader.split('.')[1];
19-
const role = roleString ? Role[roleString] : null;
16+
const { url, method, headers, body } = request;
2017

2118
// wrap in delayed observable to simulate server api call
22-
return of(null).pipe(mergeMap(handleRoute))
23-
.pipe(materialize()) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
24-
.pipe(delay(500))
25-
.pipe(dematerialize());
19+
return of(null)
20+
.pipe(mergeMap(handleRoute))
21+
.pipe(materialize()) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
22+
.pipe(delay(500))
23+
.pipe(dematerialize());
2624

2725
function handleRoute() {
28-
// authenticate - public
29-
if (request.url.endsWith('/users/authenticate') && request.method === 'POST') {
30-
const user = users.find(x => x.username === request.body.username && x.password === request.body.password);
31-
if (!user) return error('Username or password is incorrect');
32-
return ok({
33-
id: user.id,
34-
username: user.username,
35-
firstName: user.firstName,
36-
lastName: user.lastName,
37-
role: user.role,
38-
token: `fake-jwt-token.${user.role}`
39-
});
26+
switch (true) {
27+
case url.endsWith('/users/authenticate') && method === 'POST':
28+
return authenticate();
29+
case url.endsWith('/users') && method === 'GET':
30+
return getUsers();
31+
case url.match(/\/users\/\d+$/) && method === 'GET':
32+
return getUserById();
33+
default:
34+
// pass through any requests not handled above
35+
return next.handle(request);
4036
}
4137

42-
// get user by id - admin or user (user can only access their own record)
43-
if (request.url.match(/\/users\/\d+$/) && request.method === 'GET') {
44-
if (!isLoggedIn) return unauthorised();
38+
}
4539

46-
// get id from request url
47-
let urlParts = request.url.split('/');
48-
let id = parseInt(urlParts[urlParts.length - 1]);
40+
// route functions
41+
42+
function authenticate() {
43+
const { username, password } = body;
44+
const user = users.find(x => x.username === username && x.password === password);
45+
if (!user) return error('Username or password is incorrect');
46+
return ok({
47+
id: user.id,
48+
username: user.username,
49+
firstName: user.firstName,
50+
lastName: user.lastName,
51+
role: user.role,
52+
token: `fake-jwt-token.${user.id}`
53+
});
54+
}
4955

50-
// only allow normal users access to their own record
51-
const currentUser = users.find(x => x.role === role);
52-
if (id !== currentUser.id && role !== Role.Admin) return unauthorised();
56+
function getUsers() {
57+
if (!isAdmin()) return unauthorized();
58+
return ok(users);
59+
}
5360

54-
const user = users.find(x => x.id === id);
55-
return ok(user);
56-
}
61+
function getUserById() {
62+
if (!isLoggedIn()) return unauthorized();
5763

58-
// get all users (admin only)
59-
if (request.url.endsWith('/users') && request.method === 'GET') {
60-
if (role !== Role.Admin) return unauthorised();
61-
return ok(users);
62-
}
64+
// only admins can access other user records
65+
if (!isAdmin() && currentUser().id !== idFromUrl()) return unauthorized();
6366

64-
// pass through any requests not handled above
65-
return next.handle(request);
67+
const user = users.find(x => x.id === idFromUrl());
68+
return ok(user);
6669
}
6770

6871
// helper functions
@@ -71,17 +74,37 @@ export class FakeBackendInterceptor implements HttpInterceptor {
7174
return of(new HttpResponse({ status: 200, body }));
7275
}
7376

74-
function unauthorised() {
75-
return throwError({ status: 401, error: { message: 'Unauthorised' } });
77+
function unauthorized() {
78+
return throwError({ status: 401, error: { message: 'unauthorized' } });
7679
}
7780

7881
function error(message) {
7982
return throwError({ status: 400, error: { message } });
8083
}
84+
85+
function isLoggedIn() {
86+
const authHeader = headers.get('Authorization') || '';
87+
return authHeader.startsWith('Bearer fake-jwt-token');
88+
}
89+
90+
function isAdmin() {
91+
return isLoggedIn() && currentUser().role === Role.Admin;
92+
}
93+
94+
function currentUser() {
95+
if (!isLoggedIn()) return;
96+
const id = parseInt(headers.get('Authorization').split('.')[1]);
97+
return users.find(x => x.id === id);
98+
}
99+
100+
function idFromUrl() {
101+
const urlParts = url.split('/');
102+
return parseInt(urlParts[urlParts.length - 1]);
103+
}
81104
}
82105
}
83106

84-
export let fakeBackendProvider = {
107+
export const fakeBackendProvider = {
85108
// use fake backend in place of Http service for backend-less development
86109
provide: HTTP_INTERCEPTORS,
87110
useClass: FakeBackendInterceptor,

src/app/admin/admin.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="card mt-4">
22
<h4 class="card-header">Admin</h4>
33
<div class="card-body">
4-
<p>This page can only be accessed <u>only by administrators</u>.</p>
4+
<p>This page can be accessed <u>only by administrators</u>.</p>
55
<p class="mb-1">All users from secure (admin only) api end point:</p>
66
<div *ngIf="loading" class="spinner-border spinner-border-sm"></div>
77
<ul *ngIf="users">

0 commit comments

Comments
 (0)