@adobe/aio-cli-plugin-api-mesh 3.0.1 → 3.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/oclif.manifest.json +1 -1
- package/package.json +13 -5
- package/src/commands/api-mesh/__tests__/run.test.js +783 -0
- package/src/commands/api-mesh/init.js +18 -4
- package/src/commands/api-mesh/run.js +156 -0
- package/src/helpers.js +58 -5
- package/src/server.js +168 -0
- package/src/serverUtils.js +323 -0
- package/src/templates/npmrc +2 -0
- package/src/templates/package.json +29 -19
- package/src/utils.js +12 -0
- package/src/uuid.js +21 -0
|
@@ -70,6 +70,18 @@ class InitCommand extends Command {
|
|
|
70
70
|
await fs.writeFile(filePath, JSON.stringify(pkgJSON, null, 2), 'utf8', { mode: 'w' });
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
async createDotNpmrcFile(templatePath, filePath) {
|
|
74
|
+
const dotNpmrcFile = await fs.readFile(templatePath, 'utf8');
|
|
75
|
+
|
|
76
|
+
await fs.writeFile(filePath, dotNpmrcFile, 'utf8', { mode: 'w' });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async createGitIgnoreFile(templatePath, filePath) {
|
|
80
|
+
const gitIgnoreFile = await fs.readFile(templatePath, 'utf8');
|
|
81
|
+
|
|
82
|
+
await fs.writeFile(filePath, gitIgnoreFile, 'utf8', { mode: 'w' });
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
async run() {
|
|
74
86
|
const { args, flags } = await this.parse(InitCommand);
|
|
75
87
|
const gitFlagOptions = {
|
|
@@ -81,6 +93,7 @@ class InitCommand extends Command {
|
|
|
81
93
|
let shouldCreateGit = gitFlagOptions[flags.git];
|
|
82
94
|
let packageManagerChoice = flags.packageManager;
|
|
83
95
|
const packageJsonTemplate = `${getAppRootDir()}/src/templates/package.json`;
|
|
96
|
+
const dotNpmrcPath = `${getAppRootDir()}/src/templates/npmrc`;
|
|
84
97
|
const shouldCreateWorkspace = await promptConfirm(
|
|
85
98
|
`Do you want to create the workspace in ${absolutePath}`,
|
|
86
99
|
);
|
|
@@ -124,11 +137,10 @@ class InitCommand extends Command {
|
|
|
124
137
|
try {
|
|
125
138
|
await runCliCommand('git init', absolutePath);
|
|
126
139
|
|
|
127
|
-
const
|
|
140
|
+
const gitIgnoreTemplatePath = `${getAppRootDir()}/src/templates/gitignore`;
|
|
141
|
+
const gitIgnoreFilePath = `${absolutePath}/.gitignore`;
|
|
128
142
|
|
|
129
|
-
await
|
|
130
|
-
mode: 'w',
|
|
131
|
-
});
|
|
143
|
+
await this.createGitIgnoreFile(gitIgnoreTemplatePath, gitIgnoreFilePath);
|
|
132
144
|
} catch (error) {
|
|
133
145
|
this.error(error);
|
|
134
146
|
}
|
|
@@ -144,6 +156,8 @@ class InitCommand extends Command {
|
|
|
144
156
|
args.projectName,
|
|
145
157
|
);
|
|
146
158
|
|
|
159
|
+
await this.createDotNpmrcFile(dotNpmrcPath, `${absolutePath}/.npmrc`);
|
|
160
|
+
|
|
147
161
|
if (packageManagerChoice === 'npm') {
|
|
148
162
|
try {
|
|
149
163
|
await runCliCommand(`npm install`, absolutePath);
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
7
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
8
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
|
+
governing permissions and limitations under the License.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { Command } = require('@oclif/core');
|
|
13
|
+
const {
|
|
14
|
+
portNoFlag,
|
|
15
|
+
debugFlag,
|
|
16
|
+
envFileFlag,
|
|
17
|
+
autoConfirmActionFlag,
|
|
18
|
+
readFileContents,
|
|
19
|
+
validateAndInterpolateMesh,
|
|
20
|
+
checkPlaceholders,
|
|
21
|
+
getFilesInMeshConfig,
|
|
22
|
+
} = require('../../utils');
|
|
23
|
+
const meshBuilder = require('@adobe-apimesh/mesh-builder');
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const UUID = require('../../uuid');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
const { initRequestId, startGraphqlServer, importFiles } = require('../../helpers');
|
|
28
|
+
const logger = require('../../classes/logger');
|
|
29
|
+
require('dotenv').config();
|
|
30
|
+
|
|
31
|
+
const { validateMesh, buildMesh, compileMesh } = meshBuilder.default;
|
|
32
|
+
|
|
33
|
+
class RunCommand extends Command {
|
|
34
|
+
static summary = 'Run local development server';
|
|
35
|
+
static description = 'Run a local development server that builds and compiles a mesh locally';
|
|
36
|
+
|
|
37
|
+
static args = [
|
|
38
|
+
{
|
|
39
|
+
name: 'file',
|
|
40
|
+
description: 'Mesh File',
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
static flags = {
|
|
45
|
+
port: portNoFlag,
|
|
46
|
+
debug: debugFlag,
|
|
47
|
+
env: envFileFlag,
|
|
48
|
+
autoConfirmAction: autoConfirmActionFlag,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
static enableJsonFlag = true;
|
|
52
|
+
|
|
53
|
+
static examples = [];
|
|
54
|
+
|
|
55
|
+
async run() {
|
|
56
|
+
await initRequestId();
|
|
57
|
+
|
|
58
|
+
logger.info(`RequestId: ${global.requestId}`);
|
|
59
|
+
|
|
60
|
+
const { args, flags } = await this.parse(RunCommand);
|
|
61
|
+
|
|
62
|
+
if (!args.file) {
|
|
63
|
+
throw new Error('Missing file path. Run aio api-mesh run --help for more info.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let portNo;
|
|
67
|
+
|
|
68
|
+
//To set the port number using the environment file
|
|
69
|
+
if (process.env.PORT !== undefined) {
|
|
70
|
+
if (isNaN(process.env.PORT) || !Number.isInteger(parseInt(process.env.PORT))) {
|
|
71
|
+
throw new Error('PORT value in the .env file is not a valid integer');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
portNo = process.env.PORT;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//To set the port number as the provided value in the command
|
|
78
|
+
if (flags.port !== undefined) {
|
|
79
|
+
portNo = flags.port;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//To set the default port to 5000
|
|
83
|
+
if (!portNo) {
|
|
84
|
+
portNo = 5000;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const envFilePath = await flags.env;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
//Ensure that current directory includes package.json
|
|
91
|
+
if (fs.existsSync(path.join(process.cwd(), 'package.json'))) {
|
|
92
|
+
//Read the mesh input file
|
|
93
|
+
let inputMeshData = await readFileContents(args.file, this, 'mesh');
|
|
94
|
+
let data;
|
|
95
|
+
|
|
96
|
+
if (checkPlaceholders(inputMeshData)) {
|
|
97
|
+
this.log('The provided mesh contains placeholders. Starting mesh interpolation process.');
|
|
98
|
+
data = await validateAndInterpolateMesh(inputMeshData, envFilePath, this);
|
|
99
|
+
} else {
|
|
100
|
+
try {
|
|
101
|
+
data = JSON.parse(inputMeshData);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
this.log(err.message);
|
|
104
|
+
throw new Error('Input mesh file is not a valid JSON. Please check the file provided.');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let filesList = [];
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
filesList = getFilesInMeshConfig(data, args.file);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
this.log(err.message);
|
|
114
|
+
throw new Error('Input mesh config is not valid.');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// if local files are present, import them in files array in meshConfig
|
|
118
|
+
if (filesList.length) {
|
|
119
|
+
try {
|
|
120
|
+
// minification of js will not be done for run command if debugging is enabled
|
|
121
|
+
data = await importFiles(
|
|
122
|
+
data,
|
|
123
|
+
filesList,
|
|
124
|
+
args.file,
|
|
125
|
+
flags.autoConfirmAction,
|
|
126
|
+
!flags.debug,
|
|
127
|
+
);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
this.log(err.message);
|
|
130
|
+
throw new Error(
|
|
131
|
+
'Unable to import the files in the mesh config. Please check the file and try again.',
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//Generating unique mesh id
|
|
137
|
+
let meshId = UUID.newUuid().toString();
|
|
138
|
+
|
|
139
|
+
await validateMesh(data.meshConfig);
|
|
140
|
+
await buildMesh(meshId, data.meshConfig);
|
|
141
|
+
await compileMesh(meshId);
|
|
142
|
+
|
|
143
|
+
this.log(`Starting server on port : ${portNo}`);
|
|
144
|
+
await startGraphqlServer(meshId, portNo, flags.debug);
|
|
145
|
+
} else {
|
|
146
|
+
throw new Error(
|
|
147
|
+
'`aio api-mesh run` cannot be executed because there is no package.json file in the current directory. Use `aio api-mesh init` to set up a package.',
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
this.error(error.message);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = RunCommand;
|
package/src/helpers.js
CHANGED
|
@@ -522,7 +522,13 @@ async function promptInput(message) {
|
|
|
522
522
|
* @param meshConfigName MeshConfigName
|
|
523
523
|
* @param autoConfirmActionFlag The user won't be prompted any questions, if this flag is set
|
|
524
524
|
*/
|
|
525
|
-
async function importFiles(
|
|
525
|
+
async function importFiles(
|
|
526
|
+
data,
|
|
527
|
+
filesListArray,
|
|
528
|
+
meshConfigName,
|
|
529
|
+
autoConfirmActionFlag,
|
|
530
|
+
shouldMinifyJS = true,
|
|
531
|
+
) {
|
|
526
532
|
//if autoConfirmActionFlag is passed in the command, it should override by default
|
|
527
533
|
let shouldOverride = true;
|
|
528
534
|
let filesNotFound = [];
|
|
@@ -558,7 +564,7 @@ async function importFiles(data, filesListArray, meshConfigName, autoConfirmActi
|
|
|
558
564
|
} else {
|
|
559
565
|
//if file does not exist in files array, but exists in filesystem, we append
|
|
560
566
|
if (fs.existsSync(path.resolve(path.dirname(meshConfigName), file))) {
|
|
561
|
-
resultData = updateFilesArray(resultData, file, meshConfigName, -1);
|
|
567
|
+
resultData = updateFilesArray(resultData, file, meshConfigName, -1, shouldMinifyJS);
|
|
562
568
|
} else {
|
|
563
569
|
filesNotFound.push(file);
|
|
564
570
|
}
|
|
@@ -588,6 +594,7 @@ async function importFiles(data, filesListArray, meshConfigName, autoConfirmActi
|
|
|
588
594
|
overrideArr[i].fileName,
|
|
589
595
|
meshConfigName,
|
|
590
596
|
overrideArr[i].index,
|
|
597
|
+
shouldMinifyJS,
|
|
591
598
|
);
|
|
592
599
|
}
|
|
593
600
|
}
|
|
@@ -673,7 +680,7 @@ function runCliCommand(command, workingDirectory = '.') {
|
|
|
673
680
|
* @param meshConfigName MeshConfig name
|
|
674
681
|
* @param index Append operation if index is -1, else override, it is the index where the override takes place
|
|
675
682
|
*/
|
|
676
|
-
function updateFilesArray(data, file, meshConfigName, index) {
|
|
683
|
+
function updateFilesArray(data, file, meshConfigName, index, shouldMinifyJS = true) {
|
|
677
684
|
try {
|
|
678
685
|
let readFileData = fs.readFileSync(
|
|
679
686
|
path.resolve(path.dirname(meshConfigName), file),
|
|
@@ -695,8 +702,17 @@ function updateFilesArray(data, file, meshConfigName, index) {
|
|
|
695
702
|
throw new Error(`Invalid JSON content in ${path.basename(file)}`);
|
|
696
703
|
}
|
|
697
704
|
|
|
698
|
-
//
|
|
699
|
-
|
|
705
|
+
// shouldMinifyJS would be always true for create and update commands
|
|
706
|
+
// if run command run on debug mode it will be false and js files wont be minified
|
|
707
|
+
if (shouldMinifyJS) {
|
|
708
|
+
readFileData = jsmin(readFileData);
|
|
709
|
+
} else {
|
|
710
|
+
if (path.extname(file) !== '.js') {
|
|
711
|
+
readFileData = jsmin(readFileData);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const dataInFilesArray = readFileData;
|
|
700
716
|
|
|
701
717
|
if (index >= 0) {
|
|
702
718
|
data.meshConfig.files[index] = {
|
|
@@ -723,6 +739,42 @@ function updateFilesArray(data, file, meshConfigName, index) {
|
|
|
723
739
|
}
|
|
724
740
|
}
|
|
725
741
|
|
|
742
|
+
/**
|
|
743
|
+
* Start GraphQL server for a particular mesh on a particular port
|
|
744
|
+
*
|
|
745
|
+
* @param meshId MeshId of the mesh
|
|
746
|
+
* @param port Port number at which the server is to be started
|
|
747
|
+
* @param debug Boolean flag to set the debug mode
|
|
748
|
+
*/
|
|
749
|
+
function startGraphqlServer(meshId, port, debug) {
|
|
750
|
+
const serverPath = `${__dirname}/server.js ${meshId} ${port}`;
|
|
751
|
+
const command = debug
|
|
752
|
+
? `node --inspect-brk --trace-warnings ${serverPath}`
|
|
753
|
+
: `node ${serverPath}`;
|
|
754
|
+
|
|
755
|
+
const server = exec(command);
|
|
756
|
+
|
|
757
|
+
server.stdout.on('data', data => {
|
|
758
|
+
console.log(data);
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
server.stderr.on('data', data => {
|
|
762
|
+
console.error(data);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
server.on('close', code => {
|
|
766
|
+
console.log(`Server closed with code ${code}`);
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
server.on('exit', code => {
|
|
770
|
+
console.log(`Server exited with code ${code}`);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
server.on('error', err => {
|
|
774
|
+
console.error(`Server exited with error ${err}`);
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
726
778
|
module.exports = {
|
|
727
779
|
objToString,
|
|
728
780
|
promptInput,
|
|
@@ -737,4 +789,5 @@ module.exports = {
|
|
|
737
789
|
interpolateMesh,
|
|
738
790
|
runCliCommand,
|
|
739
791
|
updateFilesArray,
|
|
792
|
+
startGraphqlServer,
|
|
740
793
|
};
|
package/src/server.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// Resolve the path to 'fastify' and 'graphql-yoga' within the local 'node_modules'
|
|
2
|
+
const fastifyPath = require.resolve('fastify', { paths: [process.cwd()] });
|
|
3
|
+
const yogaPath = require.resolve('graphql-yoga', { paths: [process.cwd()] });
|
|
4
|
+
|
|
5
|
+
// Load 'fastify' and 'graphql-yoga' using the resolved paths
|
|
6
|
+
const fastify = require(fastifyPath);
|
|
7
|
+
const { createYoga } = require(yogaPath);
|
|
8
|
+
const logger = require('./classes/logger');
|
|
9
|
+
|
|
10
|
+
//Load the functions from serverUtils.js
|
|
11
|
+
const {
|
|
12
|
+
readMeshConfig,
|
|
13
|
+
removeRequestHeaders,
|
|
14
|
+
prepSourceResponseHeaders,
|
|
15
|
+
processResponseHeaders,
|
|
16
|
+
} = require('./serverUtils');
|
|
17
|
+
|
|
18
|
+
let yogaServer = null;
|
|
19
|
+
let meshConfig;
|
|
20
|
+
|
|
21
|
+
// catch unhandled promise rejections
|
|
22
|
+
process.on('unhandledRejection', reason => {
|
|
23
|
+
logger.error('Unhandled Rejection at:', reason.stack || reason);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// catch uncaught exceptions
|
|
27
|
+
process.on('uncaughtException', err => {
|
|
28
|
+
logger.error('Uncaught Exception thrown');
|
|
29
|
+
logger.error(err.stack);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// get meshId from command line arguments
|
|
34
|
+
const meshId = process.argv[2];
|
|
35
|
+
|
|
36
|
+
// get PORT number from command line arguments
|
|
37
|
+
const portNo = parseInt(process.argv[3]);
|
|
38
|
+
|
|
39
|
+
const getCORSOptions = () => {
|
|
40
|
+
try {
|
|
41
|
+
const currentWorkingDirectory = process.cwd();
|
|
42
|
+
const meshConfigPath = `${currentWorkingDirectory}/mesh-artifact/${meshId}/.meshrc.json`;
|
|
43
|
+
|
|
44
|
+
const meshConfig = require(meshConfigPath);
|
|
45
|
+
const { responseConfig } = meshConfig;
|
|
46
|
+
const { CORS } = responseConfig;
|
|
47
|
+
|
|
48
|
+
return CORS;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const getYogaServer = async () => {
|
|
55
|
+
if (yogaServer) {
|
|
56
|
+
return yogaServer;
|
|
57
|
+
} else {
|
|
58
|
+
const currentWorkingDirectory = process.cwd();
|
|
59
|
+
const meshArtifactsPath = `${currentWorkingDirectory}/mesh-artifact/${meshId}`;
|
|
60
|
+
|
|
61
|
+
const meshArtifacts = require(meshArtifactsPath);
|
|
62
|
+
const { getBuiltMesh } = meshArtifacts;
|
|
63
|
+
|
|
64
|
+
const tenantMesh = await getBuiltMesh();
|
|
65
|
+
const corsOptions = getCORSOptions();
|
|
66
|
+
|
|
67
|
+
logger.info('Creating graphQL server');
|
|
68
|
+
|
|
69
|
+
meshConfig = readMeshConfig(meshId);
|
|
70
|
+
|
|
71
|
+
yogaServer = createYoga({
|
|
72
|
+
plugins: tenantMesh.plugins,
|
|
73
|
+
graphqlEndpoint: `/graphql`,
|
|
74
|
+
graphiql: true,
|
|
75
|
+
cors: corsOptions,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return yogaServer;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const app = fastify();
|
|
83
|
+
|
|
84
|
+
app.route({
|
|
85
|
+
method: ['GET', 'POST'],
|
|
86
|
+
url: '/graphql',
|
|
87
|
+
handler: async (req, res) => {
|
|
88
|
+
logger.info('Request received: ', req.body);
|
|
89
|
+
|
|
90
|
+
let body = null;
|
|
91
|
+
let responseBody = null;
|
|
92
|
+
let includeMetaData = false;
|
|
93
|
+
|
|
94
|
+
if (req.headers['x-include-metadata'] && req.headers['x-include-metadata'].length > 0) {
|
|
95
|
+
if (req.headers['x-include-metadata'].toLowerCase() === 'true') {
|
|
96
|
+
includeMetaData = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const response = await yogaServer.handleNodeRequest(req, {
|
|
101
|
+
req,
|
|
102
|
+
reply: res,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
try {
|
|
107
|
+
body = await response.text();
|
|
108
|
+
if (body) {
|
|
109
|
+
responseBody = JSON.parse(body);
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
logger.error(`Error parsing response body: ${err}`);
|
|
113
|
+
logger.error(response);
|
|
114
|
+
throw new Error(`Error parsing response body: ${err}`);
|
|
115
|
+
}
|
|
116
|
+
//Set the value of includeHTTPDetails flag
|
|
117
|
+
|
|
118
|
+
const includeHTTPDetails = !!meshConfig?.responseConfig?.includeHTTPDetails;
|
|
119
|
+
const meshHTTPDetails = responseBody?.extensions?.httpDetails;
|
|
120
|
+
logger.info('Mesh HTTP Details: ', meshHTTPDetails);
|
|
121
|
+
|
|
122
|
+
/* the logic for handling mesh response headers using includeMetaData */
|
|
123
|
+
prepSourceResponseHeaders(meshHTTPDetails, req.id);
|
|
124
|
+
const responseHeaders = processResponseHeaders(meshId, req.id, includeMetaData, req.method);
|
|
125
|
+
|
|
126
|
+
/** Adding the yoga response headers to the response */
|
|
127
|
+
response.headers?.forEach((value, key) => {
|
|
128
|
+
res.header(key, value);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Delete the httpDetails extensions details if mesh owner has disabled those details in the config
|
|
132
|
+
if (includeHTTPDetails !== true) {
|
|
133
|
+
delete responseBody?.extensions?.httpDetails;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//make sure to remove the request headers from cache after the request is complete
|
|
137
|
+
removeRequestHeaders(req.id);
|
|
138
|
+
const fastifyResponseBody = JSON.stringify(responseBody);
|
|
139
|
+
res.status(response.status).headers(responseHeaders).send(fastifyResponseBody);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
logger.error(`Error parsing response body: ${err}`);
|
|
142
|
+
//we have this fallback catch clause if someone wants to load the graphiql engine. This returns the default headers back
|
|
143
|
+
response.headers?.forEach((value, key) => {
|
|
144
|
+
res.header(key, value);
|
|
145
|
+
});
|
|
146
|
+
res.status(response.status);
|
|
147
|
+
res.send(response.body);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return res;
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
app.listen(
|
|
155
|
+
{
|
|
156
|
+
//set the port no of the server based on the input value
|
|
157
|
+
port: portNo,
|
|
158
|
+
},
|
|
159
|
+
async err => {
|
|
160
|
+
if (err) {
|
|
161
|
+
console.error(err);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
yogaServer = await getYogaServer();
|
|
165
|
+
|
|
166
|
+
console.log(`Server is running on http://localhost:${portNo}/graphql`);
|
|
167
|
+
},
|
|
168
|
+
);
|