1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import {
|
7 | config,
|
8 | CoreBindings,
|
9 | extensionPoint,
|
10 | extensions,
|
11 | Getter,
|
12 | inject,
|
13 | } from '@loopback/core';
|
14 | import {
|
15 | ModelApiBuilder,
|
16 | ModelApiConfig,
|
17 | MODEL_API_BUILDER_PLUGINS,
|
18 | } from '@loopback/model-api-builder';
|
19 | import {ApplicationWithRepositories} from '@loopback/repository';
|
20 | import debugFactory from 'debug';
|
21 | import * as path from 'path';
|
22 | import {BootBindings} from '../keys';
|
23 | import {ArtifactOptions, booter} from '../types';
|
24 | import {BaseArtifactBooter} from './base-artifact.booter';
|
25 |
|
26 | const debug = debugFactory('loopback:boot:model-api');
|
27 |
|
28 | @booter('modelApi')
|
29 | @extensionPoint(MODEL_API_BUILDER_PLUGINS)
|
30 | export class ModelApiBooter extends BaseArtifactBooter {
|
31 | constructor(
|
32 | @inject(CoreBindings.APPLICATION_INSTANCE)
|
33 | public app: ApplicationWithRepositories,
|
34 | @inject(BootBindings.PROJECT_ROOT) projectRoot: string,
|
35 | @extensions()
|
36 | public getModelApiBuilders: Getter<ModelApiBuilder[]>,
|
37 | @config()
|
38 | public booterConfig: ArtifactOptions = {},
|
39 | ) {
|
40 |
|
41 |
|
42 | super(
|
43 | projectRoot,
|
44 |
|
45 | Object.assign({}, RestDefaults, booterConfig),
|
46 | );
|
47 | }
|
48 |
|
49 | |
50 |
|
51 |
|
52 | async load(): Promise<void> {
|
53 |
|
54 |
|
55 | await Promise.all(
|
56 | this.discovered.map(async f => {
|
57 | try {
|
58 |
|
59 |
|
60 | await this.setupModel(f);
|
61 | } catch (err) {
|
62 | const shortPath = path.relative(this.projectRoot, f);
|
63 | err.message += ` (while loading ${shortPath})`;
|
64 | throw err;
|
65 | }
|
66 | }),
|
67 | );
|
68 | }
|
69 |
|
70 | |
71 |
|
72 |
|
73 | async setupModel(configFile: string): Promise<void> {
|
74 | const cfg: ModelApiConfig = require(configFile);
|
75 | debug(
|
76 | 'Loaded model config from %s',
|
77 | path.relative(this.projectRoot, configFile),
|
78 | cfg,
|
79 | );
|
80 |
|
81 | const modelClass = cfg.model;
|
82 | if (typeof modelClass !== 'function') {
|
83 | throw new Error(
|
84 | `Invalid "model" field. Expected a Model class, found ${modelClass}`,
|
85 | );
|
86 | }
|
87 |
|
88 | const builder = await this.getApiBuilderForPattern(cfg.pattern);
|
89 | await builder.build(this.app, modelClass, cfg);
|
90 | }
|
91 |
|
92 | |
93 |
|
94 |
|
95 |
|
96 | async getApiBuilderForPattern(pattern: string): Promise<ModelApiBuilder> {
|
97 | const allBuilders = await this.getModelApiBuilders();
|
98 | const builder = allBuilders.find(b => b.pattern === pattern);
|
99 | if (!builder) {
|
100 | const availableBuilders = allBuilders.map(b => b.pattern).join(', ');
|
101 | throw new Error(
|
102 | `Unsupported API pattern "${pattern}". ` +
|
103 | `Available patterns: ${availableBuilders || '<none>'}`,
|
104 | );
|
105 | }
|
106 | return builder;
|
107 | }
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 |
|
113 | export const RestDefaults: ArtifactOptions = {
|
114 | dirs: ['model-endpoints'],
|
115 | extensions: ['-config.js'],
|
116 | nested: true,
|
117 | };
|