UNPKG

9.3 kBTypeScriptView Raw
1declare var __SERVICEORIENTED_ID__: any;
2declare var __DATALAYER_ID__: any;
3declare var __ISOFFLINE__: any;
4
5// this must be imported to allow async-functions within an AWS lambda environment
6// see: https://github.com/babel/babel/issues/5085
7import "@babel/polyfill";
8
9import React, { ReactNode } from "react";
10import ReactDOMServer from "react-dom/server";
11import express from "express";
12import serverless from "serverless-http";
13
14import { serviceAttachStorage } from '../components/attach-storage';
15import { listFiles } from '../storage/storage-libs';
16import { findComponentRecursively } from '../libs';
17import {isStorage} from "../storage/storage-component";
18
19import { serviceAttachService } from '../components/attach-service';
20import { callService } from './service-libs';
21
22
23import Types from '../types';
24import { extractObject, INFRASTRUCTURE_MODES, loadConfigurationFromModule } from '../libs/loader';
25
26// DataLayer imports....
27import ConnectSequence from 'connect-sequence';
28import { graphql } from 'graphql';
29import {serviceAttachDataLayer} from "./attach-data-layer";
30
31//import { getClientFilename } from '../libs/server-libs';
32//import {loadIsoConfigFromComponent, applyCustomComponents} from "../isolib";
33//import { applyAppClientModules } from '../types/client-app-config';
34
35const createServer = (serviceOrientedId, isOffline) => {
36
37 // express is the web-framework that lets us configure the endpoints
38 const app = express();
39
40
41 // in production, API-Gateway proxy redirects the request to S3
42 // serve static files - the async components of the server - only used of localhost
43 //app.use('/'+assetsDir, express.static(resolvedAssetsPath));
44
45
46 // load the IsomorphicComponent
47 // we must load it directly from the module here, to enable the aliad of the config_file_path
48 const soaConfig = loadConfigurationFromModule(require('__CONFIG_FILE_PATH__'), INFRASTRUCTURE_MODES.RUNTIME);
49
50
51 // let's extract it from the root configuration
52 const soaApp = extractObject(
53 soaConfig,
54 Types.INFRASTRUCTURE_TYPE_CONFIGURATION,
55 serviceOrientedId
56 );
57
58
59
60 // let's extract it from the root configuration
61 const dataLayer = extractObject(
62 soaConfig,
63 Types.INFRASTRUCTURE_TYPE_COMPONENT,
64 __DATALAYER_ID__
65 );
66
67 if (dataLayer) {
68
69 //console.log ("Datalayer Active: ", dataLayer.id)
70
71 console.log ("isOffline: ", isOffline);
72
73 if (isOffline) {
74 console.log("setOffline!")
75 dataLayer.setOffline(true);
76
77
78 } else {
79
80 const cors = require('cors');
81
82 const corsOptions = {
83 origin(origin, callback) {
84 callback(null, true);
85 },
86 credentials: true
87 };
88 app.use(cors(corsOptions));
89
90 // TODO only allow the domains of the app (S3, APIs)
91 var allowCrossDomain = function(req, res, next) {
92 res.header('Access-Control-Allow-Origin', '*');
93 res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
94 //res.header('Access-Control-Allow-Headers', 'Content-Type,token');
95 next();
96 }
97 app.use(allowCrossDomain);
98
99 }
100
101 app.use('/query', async (req, res, next) => {
102 //console.log("request: ", req);
103
104 const parseBody = (body) => {
105 try {
106 return JSON.parse(body);
107 } catch (e) {
108 console.log("cannot parse body: ", body.toString());
109
110
111 return body.toJSON();
112 }
113 }
114
115
116 const parsedBody = parseBody(req.body);
117 //console.log("parsedBody: ", parsedBody);
118
119 if (!parsedBody.query) {
120 res.status(500).set({
121 "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
122 //"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
123 }).send(JSON.stringify(req))
124 }
125
126 //console.log("now starting qgl-query/mutation")
127 await graphql(dataLayer.getSchema(false), parsedBody.query).then(
128 result_type => {
129 //console.log("result_type: ", result_type);
130 const entryQueryName = Object.keys(result_type.data)[0];
131
132 // when the query resolves, we get back
133 //console.log("pre-resolve | found entry: ", entryQueryName)
134
135 new ConnectSequence(req, res, next)
136 .append(...dataLayer.entries.filter(entry => entry.providesQuery(entryQueryName)).map(entry=> entry.middleware.callback))
137 .append(async (req, res, next) => {
138
139 //console.log("DL-mw: req: ");
140 //const parsedBody = JSON.parse(req.body);
141 //console.log("parsedBody: ", parsedBody);
142
143 // now we let the schema resolve with data
144 await graphql(dataLayer.getSchema(true), parsedBody.query).then(
145 result => res.status(200).set({
146 "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
147 // both does not work together?! see: https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i
148 //"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
149 }).send(JSON.stringify(result)),
150 err => res.set({
151 "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
152 //"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
153 }).status(500).send(err)
154 );
155 })
156 .run();
157 },
158 err => res.set({
159 "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
160 //"Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
161 }).status(500).send(err)
162 );
163
164 });
165
166
167 };
168
169 // let's extract it from the root configuration
170 const storages = findComponentRecursively(soaConfig, c => isStorage(c));
171
172 const reqListFiles = (
173 storageId: string,
174 prefix: string,
175 listMode: string,
176 data: any,
177 onComplete: (data: any) => void,
178 onError: (err: string) => void
179 ) => {
180
181 //console.log("listFiles function: ", storageId);
182 //console.log("found storages: ", storages);
183
184 const storage = storages.find(storage => storage.id == storageId);
185 if (storage) {
186 listFiles(storageId, prefix, listMode, data, onComplete, onError, storage, isOffline);
187 } else {
188 onError("could not find storage with id "+ storageId);
189 }
190 };
191
192 const reqCallService = (
193 id: string,
194 args: any,
195 onResult: (result: any) => void,
196 onError: (error: any) => void,
197 config: any,
198 isOffline: Boolean = false
199 ) => callService(id, args,onResult,onError,soaConfig,isOffline);
200
201
202 // flattens the callbacks
203 const unpackMiddlewares = (middlewares) => {
204 // always returns the list of callbacks
205 const cbList = (mw) => Array.isArray(mw.callback) ? mw.callback : [mw.callback];
206 return middlewares.reduce(
207 (res,mw) => res.concat(...cbList(mw)),
208 // attach the callService-function
209 [serviceAttachService(reqCallService)].concat(
210 // when we have a dataLayer, let's attach it to the request
211 dataLayer ? [serviceAttachDataLayer(dataLayer)] : [],
212
213 //when we have a storage, attach the listFiles-function
214 storages ? [ serviceAttachStorage(reqListFiles)] : []
215 )
216 );
217 };
218
219 // split the clientApps here and define a function for each of the clientApps, with the right middleware
220 soaApp.services.map(service => {
221
222 //console.log("found service: ", service);
223
224 if (service.method.toUpperCase() == "GET") {
225 app.get(service.path, ...unpackMiddlewares(service.middlewares));
226
227 } else if (service.method.toUpperCase() == "POST") {
228 app.post(service.path, ...unpackMiddlewares(service.middlewares));
229
230 } else if (service.method.toUpperCase() == "PUT") {
231 app.put(service.path, ...unpackMiddlewares(service.middlewares));
232
233 } else if (service.method.toUpperCase() == "DELETE") {
234 app.delete(service.path, ...unpackMiddlewares(service.middlewares));
235
236 }
237
238 return service;
239 });
240
241 return app;
242};
243
244
245
246// these variables are replaced during compilation
247export default serverless(createServer(__SERVICEORIENTED_ID__, __ISOFFLINE__));
\No newline at end of file