Skip to content

Commit 0b0daa2

Browse files
louislatreilleLouis Latreillebboure
authored
feat(simulator): Add support for multiple AppSync APIs (#92)
Co-authored-by: Louis Latreille <louis_latreille@trendmicro.com> Co-authored-by: Benoît <benoit.boure@gmail.com>
1 parent 45404d9 commit 0b0daa2

File tree

4 files changed

+69
-29
lines changed

4 files changed

+69
-29
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ Put options under `custom.appsync-simulator` in your `serverless.yml` file
5454
| option | default | description |
5555
| ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5656
| apiKey | `0123456789` | When using `API_KEY` as authentication type, the key to authenticate to the endpoint. |
57-
| port | 20002 | AppSync operations port |
58-
| wsPort | 20003 | AppSync subscriptions port |
57+
| port | 20002 | AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.) |
58+
| wsPort | 20003 | AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.) |
5959
| location | . (base directory) | Location of the lambda functions handlers. |
6060
| lambda.loadLocalEnv | false | If `true`, all environment variables (`$ env`) will be accessible from the resolver function. Read more in section [Environment variables](#environment-variables). |
6161
| refMap | {} | A mapping of [resource resolutions](#resource-cloudformation-functions-resolution) for the `Ref` function |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"url": "git+https://github.com/bboure/serverless-appsync-simulator.git"
1212
},
1313
"scripts": {
14-
"lint": "eslint",
14+
"lint": "eslint src/*/**.js",
1515
"tests": "jest",
1616
"build": "babel src/ -d lib/ --delete-dir-on-start --ignore '**/__tests__'",
1717
"prepare": "yarn run build",

src/data-loaders/NotImplementedDataLoader.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ export default class NotImplementedDataLoader {
55
}
66

77
async load() {
8-
console.log(`Data Loader not implemented for ${this.config.type} (${this.config.name})`);
8+
console.log(
9+
`Data Loader not implemented for ${this.config.type} (${this.config.name})`,
10+
);
911

1012
return null;
1113
}

src/index.js

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ class ServerlessAppSyncSimulator {
2323
this.log = this.log.bind(this);
2424
this.debugLog = this.debugLog.bind(this);
2525

26-
this.simulator = null;
26+
this.simulators = null;
2727

2828
addDataLoader('HTTP', HttpDataLoader);
2929
addDataLoader('AMAZON_ELASTICSEARCH', ElasticDataLoader);
3030
addDataLoader('RELATIONAL_DATABASE', NotImplementedDataLoader);
3131

3232
this.hooks = {
33-
'before:offline:start:init': this.startServer.bind(this),
34-
'before:offline:start:end': this.endServer.bind(this),
33+
'before:offline:start:init': this.startServers.bind(this),
34+
'before:offline:start:end': this.endServers.bind(this),
3535
};
3636
}
3737

@@ -45,7 +45,7 @@ class ServerlessAppSyncSimulator {
4545
}
4646
}
4747

48-
async startServer() {
48+
async startServers() {
4949
try {
5050
this.buildResolvedOptions();
5151
this.buildResourceResolvers();
@@ -59,43 +59,79 @@ class ServerlessAppSyncSimulator {
5959
this.serverless.service.custom.appSync,
6060
);
6161

62-
this.simulator = new AmplifyAppSyncSimulator({
63-
port: this.options.port,
64-
wsPort: this.options.wsPort,
65-
});
62+
this.simulators = [];
63+
if (Array.isArray(this.serverless.service.custom.appSync)) {
64+
let port = this.options.port;
65+
let wsPort = this.options.wsPort;
66+
for (let appSyncConfig of this.serverless.service.custom.appSync) {
67+
this.simulators.push({
68+
amplifySimulator: await this.startIndividualServer(port, wsPort),
69+
name: appSyncConfig.name,
70+
});
71+
port += 10;
72+
wsPort += 10;
73+
}
74+
} else {
75+
this.simulators.push({
76+
amplifySimulator: await this.startIndividualServer(
77+
this.options.port,
78+
this.options.wsPort,
79+
),
80+
name: this.serverless.service.custom.appSync.name,
81+
});
82+
}
6683

67-
await this.simulator.start();
6884
if (Array.isArray(this.options.watch) && this.options.watch.length > 0) {
6985
this.watch();
7086
} else {
71-
this.initServer();
87+
this.initServers();
7288
}
7389

74-
this.log(`AppSync endpoint: ${this.simulator.url}/graphql`);
75-
this.log(`GraphiQl: ${this.simulator.url}`);
90+
for (let sim of this.simulators) {
91+
this.log(
92+
`${sim.name} AppSync endpoint: ${sim.amplifySimulator.url}/graphql`,
93+
);
94+
this.log(`${sim.name} GraphiQl: ${sim.amplifySimulator.url}`);
95+
}
7696
} catch (error) {
7797
this.log(error, { color: 'red' });
7898
}
7999
}
80100

81-
initServer() {
82-
// TODO: suport several API's
83-
const appSync = Array.isArray(this.serverless.service.custom.appSync)
84-
? this.serverless.service.custom.appSync[0]
85-
: this.serverless.service.custom.appSync;
101+
async startIndividualServer(port, wsPort) {
102+
const simulator = new AmplifyAppSyncSimulator({
103+
port: port,
104+
wsPort: wsPort,
105+
});
106+
await simulator.start();
107+
108+
return simulator;
109+
}
110+
111+
initServers() {
112+
const appSyncConfig = Array.isArray(this.serverless.service.custom.appSync)
113+
? this.serverless.service.custom.appSync
114+
: [this.serverless.service.custom.appSync];
115+
116+
for (let [i, sim] of this.simulators.entries()) {
117+
this.initIndividualServer(sim, appSyncConfig[i]);
118+
}
119+
}
120+
121+
initIndividualServer(simulator, appSyncConfig) {
86122
const config = getAppSyncConfig(
87123
{
88124
plugin: this,
89125
serverless: this.serverless,
90126
options: this.options,
91127
},
92-
appSync,
128+
appSyncConfig,
93129
);
94130

95-
this.debugLog(`AppSync Config ${appSync.name}`);
131+
this.debugLog(`AppSync Config ${appSyncConfig.name}`);
96132
this.debugLog(inspect(config, { depth: 4, colors: true }));
97133

98-
this.simulator.init(config);
134+
simulator.amplifySimulator.init(config);
99135
}
100136

101137
watch() {
@@ -108,7 +144,7 @@ class ServerlessAppSyncSimulator {
108144
console.error('Error initiating watch:', error);
109145
console.log('AppSync Simulator hot-reloading will not be available');
110146
// init server once
111-
this.initServer();
147+
this.initServers();
112148
return;
113149
}
114150

@@ -151,15 +187,17 @@ class ServerlessAppSyncSimulator {
151187
client.on('subscription', async (resp) => {
152188
if (resp.subscription === 'appsync-simulator') {
153189
console.log('Hot-reloading AppSync simulator...');
154-
this.initServer();
190+
this.initServers();
155191
}
156192
});
157193
}
158194

159-
endServer() {
160-
if (this.simulator) {
195+
endServers() {
196+
if (this.simulators) {
161197
this.log('Halting AppSync Simulator');
162-
this.simulator.stop();
198+
for (let sim of this.simulators) {
199+
sim.amplifySimulator.stop();
200+
}
163201
}
164202
}
165203

0 commit comments

Comments
 (0)