Skip to content

Commit 8a616ee

Browse files
authored
feat(driver): add backend delegate service (#3146)
1 parent 87277c6 commit 8a616ee

File tree

6 files changed

+143
-0
lines changed

6 files changed

+143
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createServicesInjectionToken } from '@daffodil/core';
2+
3+
import { DaffInMemoryBackendInterface } from './type';
4+
5+
export const {
6+
token: DAFF_IN_MEMORY_BACKENDS,
7+
provider: provideDaffInMemoryBackends,
8+
} = createServicesInjectionToken<DaffInMemoryBackendInterface>('DAFF_IN_MEMORY_BACKENDS');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { STATUS } from 'angular-in-memory-web-api';
2+
3+
import {
4+
DaffInMemoryBackendInterface,
5+
DaffInMemoryDataServiceInterface,
6+
} from '@daffodil/driver/in-memory';
7+
8+
import { DaffInMemoryBackendDelegate } from './delegate.service';
9+
10+
describe('@daffodil/driver/in-memory', () => {
11+
let service: DaffInMemoryBackendDelegate;
12+
let backends: Array<jasmine.SpyObj<DaffInMemoryBackendInterface>>;
13+
let methods: Array<keyof DaffInMemoryDataServiceInterface>;
14+
15+
beforeEach(() => {
16+
methods = ['get', 'put', 'post', 'delete'];
17+
backends = [
18+
jasmine.createSpyObj('a', methods, {
19+
collectionName: 'a',
20+
}),
21+
jasmine.createSpyObj('b', methods, {
22+
collectionName: 'b',
23+
}),
24+
jasmine.createSpyObj('c', [], {
25+
collectionName: 'c',
26+
}),
27+
];
28+
service = new DaffInMemoryBackendDelegate(backends);
29+
});
30+
31+
// eslint-disable-next-line guard-for-in
32+
for (const method in methods) {
33+
describe(method, () => {
34+
it('should delegate requests to the correct backend', () => {
35+
const reqInfo: any = {
36+
collectionName: 'a',
37+
};
38+
service[method](reqInfo);
39+
expect(backends[0][method]).toHaveBeenCalledWith(reqInfo);
40+
reqInfo.collectionName = 'b';
41+
service[method](reqInfo);
42+
expect(backends[1][method]).toHaveBeenCalledWith(reqInfo);
43+
});
44+
45+
it('should return a "not found" if the method is missing from the backend', (done) => {
46+
const reqInfo: any = {
47+
collectionName: 'c',
48+
};
49+
service[method](reqInfo).subscribe((res) => {
50+
expect(res.status).toEqual(STATUS.NOT_FOUND);
51+
done();
52+
});
53+
});
54+
55+
it('should return a "not found" if there isn\'t a backend for the collection name', (done) => {
56+
const reqInfo: any = {
57+
collectionName: '404backendnotfound',
58+
};
59+
service[method](reqInfo).subscribe((res) => {
60+
expect(res.status).toEqual(STATUS.NOT_FOUND);
61+
done();
62+
});
63+
});
64+
});
65+
}
66+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
Inject,
3+
Injectable,
4+
} from '@angular/core';
5+
import {
6+
RequestInfo,
7+
STATUS,
8+
} from 'angular-in-memory-web-api';
9+
import { Observable } from 'rxjs';
10+
11+
import { DAFF_IN_MEMORY_BACKENDS } from './backends.token';
12+
import { DaffInMemoryDataServiceInterface } from './data-service.type';
13+
import { DaffInMemoryBackendInterface } from './type';
14+
15+
/**
16+
* An in-memory backend that automatically delegates requests to backends provided to {@link DAFF_IN_MEMORY_BACKENDS}.
17+
*
18+
* @inheritdoc
19+
*/
20+
@Injectable({
21+
providedIn: 'root',
22+
})
23+
export class DaffInMemoryBackendDelegate implements DaffInMemoryDataServiceInterface {
24+
constructor(
25+
@Inject(DAFF_IN_MEMORY_BACKENDS) private backends: Array<DaffInMemoryBackendInterface>,
26+
) {}
27+
28+
protected delegateRequest(reqInfo: RequestInfo, method: keyof DaffInMemoryDataServiceInterface): Observable<any> {
29+
const backend = this.backends.find((b) => b.collectionName === reqInfo.collectionName);
30+
return backend?.[method](reqInfo) || reqInfo.utils.createResponse$(() => ({
31+
status: STATUS.NOT_FOUND,
32+
statusText: `Backend ${reqInfo.collectionName} not found or does not support the ${method} request method`,
33+
}));
34+
}
35+
36+
get?(reqInfo: RequestInfo): Observable<any> {
37+
return this.delegateRequest(reqInfo, 'get');
38+
}
39+
40+
post?(reqInfo: RequestInfo): Observable<any> {
41+
return this.delegateRequest(reqInfo, 'post');
42+
}
43+
44+
put?(reqInfo: RequestInfo): Observable<any> {
45+
return this.delegateRequest(reqInfo, 'put');
46+
}
47+
48+
delete?(reqInfo: RequestInfo): Observable<any> {
49+
return this.delegateRequest(reqInfo, 'delete');
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
export * from './backends.token';
12
export * from './data-service.type';
3+
export * from './delegate.service';
4+
export * from './type';
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { DaffInMemoryDataServiceInterface } from './data-service.type';
2+
3+
/**
4+
* An interface for defining in memory backends that use the angular in memory web api.
5+
*/
6+
export interface DaffInMemoryBackendInterface extends DaffInMemoryDataServiceInterface {
7+
/**
8+
* The collection name of the backend service.
9+
* Used for routing requests to the correct backend.
10+
*/
11+
readonly collectionName: string;
12+
}

libs/driver/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
"publish": "cd ../../dist/driver && npm publish --access=public"
2727
},
2828
"homepage": "https://github.com/graycoreio/daffodil",
29+
"optionalDependencies": {
30+
"angular-in-memory-web-api": "0.0.0-PLACEHOLDER"
31+
},
2932
"peerDependencies": {
3033
"@angular/common": "0.0.0-PLACEHOLDER",
3134
"@angular/core": "0.0.0-PLACEHOLDER",

0 commit comments

Comments
 (0)