@flink-app/flink 0.4.5 → 0.4.7

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.
@@ -107,6 +107,11 @@ export interface FlinkOptions {
107
107
  */
108
108
  enabled?: boolean;
109
109
  };
110
+ /**
111
+ * If true, the HTTP server will be disabled.
112
+ * Only useful when starting a Flink app for testing purposes.
113
+ */
114
+ disableHttpServer?: boolean;
110
115
  }
111
116
  export interface HandlerConfig {
112
117
  schema?: {
@@ -145,6 +150,7 @@ export declare class FlinkApp<C extends FlinkContext> {
145
150
  private routingConfigured;
146
151
  private jsonOptions?;
147
152
  private schedulingOptions?;
153
+ private disableHttpServer;
148
154
  private repos;
149
155
  /**
150
156
  * Internal cache used to track registered handlers and potentially any overlapping routes
@@ -93,6 +93,7 @@ var FlinkApp = /** @class */ (function () {
93
93
  this.debug = false;
94
94
  this.plugins = [];
95
95
  this.routingConfigured = false;
96
+ this.disableHttpServer = false;
96
97
  this.repos = {};
97
98
  /**
98
99
  * Internal cache used to track registered handlers and potentially any overlapping routes
@@ -108,6 +109,7 @@ var FlinkApp = /** @class */ (function () {
108
109
  this.auth = opts.auth;
109
110
  this.jsonOptions = opts.jsonOptions || { limit: "1mb" };
110
111
  this.schedulingOptions = opts.scheduling;
112
+ this.disableHttpServer = !!opts.disableHttpServer;
111
113
  }
112
114
  Object.defineProperty(FlinkApp.prototype, "ctx", {
113
115
  get: function () {
@@ -146,13 +148,18 @@ var FlinkApp = /** @class */ (function () {
146
148
  if (this.isSchedulingEnabled) {
147
149
  this.scheduler = new toad_scheduler_1.ToadScheduler();
148
150
  }
149
- this.expressApp = express_1.default();
150
- this.expressApp.use(cors_1.default(this.corsOpts));
151
- this.expressApp.use(body_parser_1.default.json(this.jsonOptions));
152
- this.expressApp.use(function (req, res, next) {
153
- req.reqId = uuid_1.v4();
154
- next();
155
- });
151
+ else {
152
+ FlinkLog_1.log.info("🚫 Scheduling is disabled");
153
+ }
154
+ if (!this.disableHttpServer) {
155
+ this.expressApp = express_1.default();
156
+ this.expressApp.use(cors_1.default(this.corsOpts));
157
+ this.expressApp.use(body_parser_1.default.json(this.jsonOptions));
158
+ this.expressApp.use(function (req, res, next) {
159
+ req.reqId = uuid_1.v4();
160
+ next();
161
+ });
162
+ }
156
163
  _i = 0, _b = this.plugins;
157
164
  _c.label = 3;
158
165
  case 3:
@@ -196,15 +203,23 @@ var FlinkApp = /** @class */ (function () {
196
203
  // Register 404 with slight delay to allow all manually added routes to be added
197
204
  // TODO: Is there a better solution to force this handler to always run last?
198
205
  setTimeout(function () {
199
- _this.expressApp.use(function (req, res, next) {
200
- res.status(404).json(FlinkErrors_1.notFound());
201
- });
206
+ if (!_this.disableHttpServer) {
207
+ _this.expressApp.use(function (req, res, next) {
208
+ res.status(404).json(FlinkErrors_1.notFound());
209
+ });
210
+ }
202
211
  _this.routingConfigured = true;
203
212
  });
204
- (_a = this.expressApp) === null || _a === void 0 ? void 0 : _a.listen(this.port, function () {
205
- FlinkLog_1.log.fontColorLog("magenta", "\u26A1\uFE0F HTTP server '" + _this.name + "' is running and waiting for connections on " + _this.port);
206
- _this.started = true;
207
- });
213
+ if (this.disableHttpServer) {
214
+ FlinkLog_1.log.info("🚧 HTTP server is disabled, but flink app is running");
215
+ this.started = true;
216
+ }
217
+ else {
218
+ (_a = this.expressApp) === null || _a === void 0 ? void 0 : _a.listen(this.port, function () {
219
+ FlinkLog_1.log.fontColorLog("magenta", "\u26A1\uFE0F HTTP server '" + _this.name + "' is running and waiting for connections on " + _this.port);
220
+ _this.started = true;
221
+ });
222
+ }
208
223
  return [2 /*return*/, this];
209
224
  }
210
225
  });
@@ -258,13 +273,15 @@ var FlinkApp = /** @class */ (function () {
258
273
  this.handlers.push(handlerConfig);
259
274
  var routeProps = handlerConfig.routeProps, _a = handlerConfig.schema, schema = _a === void 0 ? {} : _a;
260
275
  var method = routeProps.method;
261
- var app = this.expressApp;
262
276
  if (!method) {
263
277
  FlinkLog_1.log.error("Route " + routeProps.path + " is missing http method");
264
278
  }
265
279
  if (method) {
266
280
  var methodAndRoute_1 = method.toUpperCase() + " " + routeProps.path;
267
- app[method](routeProps.path, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
281
+ if (this.disableHttpServer) {
282
+ return;
283
+ }
284
+ this.expressApp[method](routeProps.path, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
268
285
  var validate, valid, data, handlerRes, err_1, validate, valid;
269
286
  return __generator(this, function (_a) {
270
287
  switch (_a.label) {
@@ -475,8 +475,8 @@ var TypeScriptCompiler = /** @class */ (function () {
475
475
  };
476
476
  TypeScriptCompiler.prototype.initJsonSchemaGenerator = function () {
477
477
  var conf = {
478
- // expose: "",
479
- // topRef: false,
478
+ expose: "none",
479
+ topRef: false, // Removes the wrapper object around the schema.
480
480
  };
481
481
  var formatter = ts_json_schema_generator_1.createFormatter(conf);
482
482
  var parser = ts_json_schema_generator_1.createParser(this.project.getProgram().compilerObject, conf);
@@ -486,17 +486,18 @@ var TypeScriptCompiler = /** @class */ (function () {
486
486
  TypeScriptCompiler.prototype.generateAndSaveJsonSchemas = function (schemas) {
487
487
  return __awaiter(this, void 0, void 0, function () {
488
488
  var jsonSchemas, _i, schemas_1, _a, reqSchemaType, resSchemaType, mergedSchemas, filePath;
489
- return __generator(this, function (_b) {
490
- switch (_b.label) {
489
+ var _b, _c;
490
+ return __generator(this, function (_d) {
491
+ switch (_d.label) {
491
492
  case 0:
492
493
  jsonSchemas = [];
493
494
  for (_i = 0, schemas_1 = schemas; _i < schemas_1.length; _i++) {
494
495
  _a = schemas_1[_i], reqSchemaType = _a.reqSchemaType, resSchemaType = _a.resSchemaType;
495
496
  if (reqSchemaType) {
496
- jsonSchemas.push(this.generateJsonSchema(reqSchemaType));
497
+ jsonSchemas.push({ definitions: (_b = {}, _b[reqSchemaType] = this.generateJsonSchema(reqSchemaType), _b) });
497
498
  }
498
499
  if (resSchemaType) {
499
- jsonSchemas.push(this.generateJsonSchema(resSchemaType));
500
+ jsonSchemas.push({ definitions: (_c = {}, _c[resSchemaType] = this.generateJsonSchema(resSchemaType), _c) });
500
501
  }
501
502
  }
502
503
  mergedSchemas = jsonSchemas.reduce(function (out, schema) {
@@ -512,7 +513,7 @@ var TypeScriptCompiler = /** @class */ (function () {
512
513
  filePath = path_1.join(this.cwd, ".flink", "schemas", "schemas.json");
513
514
  return [4 /*yield*/, FsUtils_1.writeJsonFile(filePath, mergedSchemas)];
514
515
  case 1:
515
- _b.sent();
516
+ _d.sent();
516
517
  this.project.addSourceFileAtPath(filePath);
517
518
  return [2 /*return*/, mergedSchemas];
518
519
  }
@@ -612,15 +613,15 @@ var TypeScriptCompiler = /** @class */ (function () {
612
613
  for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) {
613
614
  var _a = handlers_1[_i], sourceFile = _a.sourceFile, reqSchemaType = _a.reqSchemaType, resSchemaType = _a.resSchemaType;
614
615
  if (reqSchemaType && !jsonSchemaDefs[reqSchemaType]) {
615
- console.error("Handler " + sourceFile.getBaseName + " has request schema\u00A0(" + reqSchemaType + ") defined, but JSON schema has been generated");
616
+ console.error("Handler " + sourceFile.getBaseName() + " has request schema\u00A0(" + reqSchemaType + ") defined, but no JSON schema has been generated");
616
617
  continue;
617
618
  }
618
619
  if (resSchemaType && !jsonSchemaDefs[resSchemaType]) {
619
- console.error("Handler " + sourceFile.getBaseName + " has response schema\u00A0(" + resSchemaType + ") defined, but JSON schema has been generated");
620
+ console.error("Handler " + sourceFile.getBaseName() + " has response schema\u00A0(" + resSchemaType + ") defined, but no JSON schema has been generated");
620
621
  continue;
621
622
  }
622
- var reqJsonSchema = JSON.stringify(reqSchemaType ? utils_1.deRefSchema(jsonSchemaDefs[reqSchemaType], jsonSchemas) : undefined);
623
- var resJsonSchema = JSON.stringify(resSchemaType ? utils_1.deRefSchema(jsonSchemaDefs[resSchemaType], jsonSchemas) : undefined);
623
+ var reqJsonSchema = JSON.stringify(reqSchemaType ? jsonSchemaDefs[reqSchemaType] : undefined);
624
+ var resJsonSchema = JSON.stringify(resSchemaType ? jsonSchemaDefs[resSchemaType] : undefined);
624
625
  sourceFile.addVariableStatement({
625
626
  declarationKind: ts_morph_1.VariableDeclarationKind.Const,
626
627
  isExported: true,
@@ -1,5 +1,4 @@
1
1
  import { Request } from "express";
2
- import { JSONSchema7, JSONSchema7Definition } from "json-schema";
3
2
  import { HttpMethod } from "./FlinkHttpHandler";
4
3
  import { FlinkResponse } from "./FlinkResponse";
5
4
  export declare function handlersPath(appRoot: string): string;
@@ -18,13 +17,4 @@ export declare function getRepoInstanceName(fn: string): string;
18
17
  * if it starts with i.e "GetFoo"
19
18
  */
20
19
  export declare function getHttpMethodFromHandlerName(handlerFilename: string): HttpMethod | undefined;
21
- /**
22
- * Recursively iterates thru json schema properties and replaces any $ref
23
- * with the actual definiton if it exists withing provided `jsonSchemas`.
24
- *
25
- * @param schemaToDeRef
26
- * @param jsonSchemas
27
- * @returns
28
- */
29
- export declare function deRefSchema(schemaToDeRef: JSONSchema7Definition, jsonSchemas: JSONSchema7): boolean | JSONSchema7;
30
20
  export declare function getJsDocComment(comment: string): string;
package/dist/src/utils.js CHANGED
@@ -39,7 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.getJsDocComment = exports.deRefSchema = exports.getHttpMethodFromHandlerName = exports.getRepoInstanceName = exports.getCollectionNameForRepo = exports.getSchemaFiles = exports.getHandlerFiles = exports.isError = exports.isRouteMatch = exports.schemasPath = exports.handlersPath = void 0;
42
+ exports.getJsDocComment = exports.getHttpMethodFromHandlerName = exports.getRepoInstanceName = exports.getCollectionNameForRepo = exports.getSchemaFiles = exports.getHandlerFiles = exports.isError = exports.isRouteMatch = exports.schemasPath = exports.handlersPath = void 0;
43
43
  var path_1 = require("path");
44
44
  var tiny_glob_1 = __importDefault(require("tiny-glob"));
45
45
  var FlinkHttpHandler_1 = require("./FlinkHttpHandler");
@@ -138,86 +138,6 @@ function getHttpMethodFromHandlerName(handlerFilename) {
138
138
  return FlinkHttpHandler_1.HttpMethod.delete;
139
139
  }
140
140
  exports.getHttpMethodFromHandlerName = getHttpMethodFromHandlerName;
141
- /**
142
- * Recursively iterates thru json schema properties and replaces any $ref
143
- * with the actual definiton if it exists withing provided `jsonSchemas`.
144
- *
145
- * @param schemaToDeRef
146
- * @param jsonSchemas
147
- * @returns
148
- */
149
- function deRefSchema(schemaToDeRef, jsonSchemas) {
150
- if (typeof schemaToDeRef === "boolean") {
151
- return schemaToDeRef;
152
- }
153
- if (schemaToDeRef.type === "array") {
154
- var items = schemaToDeRef.items;
155
- if (items.$ref) {
156
- var _a = items.$ref.split("/"), _0 = _a[0], _1 = _a[1], defKey = _a[2];
157
- var refedSchema = (jsonSchemas.definitions || {})[defKey];
158
- if (refedSchema) {
159
- schemaToDeRef.items = deRefSchema(refedSchema, jsonSchemas);
160
- }
161
- else {
162
- console.warn("Failed to find deref " + schemaToDeRef.$ref);
163
- }
164
- }
165
- else {
166
- schemaToDeRef.items = deRefSchema(schemaToDeRef.items, jsonSchemas);
167
- }
168
- }
169
- else if (schemaToDeRef.properties) {
170
- for (var k in schemaToDeRef.properties) {
171
- var prop = schemaToDeRef.properties[k];
172
- if (typeof prop === "boolean") {
173
- continue;
174
- }
175
- if (prop.$ref) {
176
- var _b = prop.$ref.split("/"), _0 = _b[0], _1 = _b[1], defKey = _b[2];
177
- var refedSchema = (jsonSchemas.definitions || {})[defKey];
178
- if (refedSchema) {
179
- schemaToDeRef.properties[k] = deRefSchema(refedSchema, jsonSchemas);
180
- }
181
- else {
182
- console.warn("Failed to find deref " + prop.$ref);
183
- }
184
- }
185
- else if (prop.type === "array" && prop.items.$ref) {
186
- var _c = prop.items.$ref.split("/"), _0 = _c[0], _1 = _c[1], defKey = _c[2];
187
- var refedSchema = (jsonSchemas.definitions || {})[defKey];
188
- if (refedSchema) {
189
- schemaToDeRef.properties[k].items = deRefSchema(refedSchema, jsonSchemas);
190
- }
191
- else {
192
- console.warn("Failed to find deref " + prop.$ref);
193
- }
194
- }
195
- else if (prop.type === "object" || prop.type === "array") {
196
- schemaToDeRef.properties[k] = deRefSchema(prop, jsonSchemas);
197
- }
198
- }
199
- }
200
- else if (schemaToDeRef.anyOf) {
201
- var i = 0;
202
- for (var _i = 0, _d = schemaToDeRef.anyOf; _i < _d.length; _i++) {
203
- var anyOf = _d[_i];
204
- var anyOfSchema = anyOf;
205
- if (anyOfSchema.$ref) {
206
- var _e = anyOfSchema.$ref.split("/"), _0 = _e[0], _1 = _e[1], defKey = _e[2];
207
- var refedSchema = (jsonSchemas.definitions || {})[defKey];
208
- if (refedSchema) {
209
- schemaToDeRef.anyOf[i] = deRefSchema(refedSchema, jsonSchemas);
210
- }
211
- else {
212
- console.warn("Failed to find deref " + anyOfSchema.$ref);
213
- }
214
- }
215
- i++;
216
- }
217
- }
218
- return schemaToDeRef;
219
- }
220
- exports.deRefSchema = deRefSchema;
221
141
  function getJsDocComment(comment) {
222
142
  var rows = comment.split("\n").map(function (line) {
223
143
  line = line.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flink-app/flink",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "Typescript only framework for creating REST-like APIs on top of Express and mongodb",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "main": "dist/src/index.js",
@@ -65,5 +65,5 @@
65
65
  "rimraf": "^3.0.2",
66
66
  "ts-node": "^9.1.1"
67
67
  },
68
- "gitHead": "38a0ca4c987f280accc5f4c7f408e51f7b076587"
68
+ "gitHead": "b565d5987e08ba3aba3653325e935e6c56cab24c"
69
69
  }
@@ -56,4 +56,4 @@ var GetCar = function (_a) {
56
56
  };
57
57
  exports.default = GetCar;
58
58
  exports.__assumedHttpMethod = "get", exports.__file = "GetCar.ts", exports.__query = [{ description: "For pagination", name: "page" }], exports.__params = [{ description: "", name: "id" }];
59
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] } };
59
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} } };
@@ -58,4 +58,4 @@ var GetCar2 = function (_a) {
58
58
  };
59
59
  exports.default = GetCar2;
60
60
  exports.__assumedHttpMethod = "get", exports.__file = "GetCar2.ts", exports.__query = [], exports.__params = [];
61
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "properties": { "model": { "type": "object", "properties": { "name": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["name"], "additionalProperties": false }, "engine": { "type": "object", "properties": { "name": { "type": "string" } }, "required": ["name"], "additionalProperties": false } }, "required": ["model", "engine"], "additionalProperties": false } };
61
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "model": { "type": "object", "properties": { "name": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["name"], "additionalProperties": false }, "engine": { "type": "object", "properties": { "name": { "type": "string" } }, "required": ["name"], "additionalProperties": false } }, "required": ["model", "engine"], "additionalProperties": false, "definitions": {} } };
@@ -52,4 +52,4 @@ var GetCarWithArraySchema = function (_a) {
52
52
  };
53
53
  exports.default = GetCarWithArraySchema;
54
54
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithArraySchema.ts", exports.__query = [], exports.__params = [];
55
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } } };
55
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false }, "definitions": {} } };
@@ -52,4 +52,4 @@ var GetCarWithArraySchema2 = function (_a) {
52
52
  };
53
53
  exports.default = GetCarWithArraySchema2;
54
54
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithArraySchema2.ts", exports.__query = [], exports.__params = [];
55
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "array", "items": { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false } } };
55
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "array", "items": { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false }, "definitions": {} } };
@@ -52,4 +52,4 @@ var GetCarWithArraySchema3 = function (_a) {
52
52
  };
53
53
  exports.default = GetCarWithArraySchema3;
54
54
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithArraySchema3.ts", exports.__query = [], exports.__params = [];
55
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "array", "items": { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false }, "year": { "type": "number" } }, "required": ["car", "year"], "additionalProperties": false } } };
55
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "array", "items": { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false }, "year": { "type": "number" } }, "required": ["car", "year"], "additionalProperties": false }, "definitions": {} } };
@@ -54,4 +54,4 @@ var GetCarWithLiteralSchema = function (_a) {
54
54
  };
55
55
  exports.default = GetCarWithLiteralSchema;
56
56
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithLiteralSchema.ts", exports.__query = [], exports.__params = [];
57
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false } };
57
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false, "definitions": {} } };
@@ -54,4 +54,4 @@ var GetCarWithLiteralSchema2 = function (_a) {
54
54
  };
55
55
  exports.default = GetCarWithLiteralSchema2;
56
56
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithLiteralSchema2.ts", exports.__query = [], exports.__params = [];
57
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "properties": { "car": { "type": "object", "properties": { "nestedCar": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["nestedCar"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false } };
57
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "car": { "type": "object", "properties": { "nestedCar": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["nestedCar"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false, "definitions": {} } };
@@ -57,4 +57,4 @@ var GetCarWithSchemaInFile = function (_a) {
57
57
  };
58
58
  exports.default = GetCarWithSchemaInFile;
59
59
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithSchemaInFile.ts", exports.__query = [], exports.__params = [];
60
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "properties": { "model": { "type": "string" } }, "required": ["model"], "additionalProperties": false } };
60
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "model": { "type": "string" } }, "required": ["model"], "additionalProperties": false, "definitions": {} } };
@@ -57,4 +57,4 @@ var GetCarWithSchemaInFile2 = function (_a) {
57
57
  };
58
58
  exports.default = GetCarWithSchemaInFile2;
59
59
  exports.__assumedHttpMethod = "get", exports.__file = "GetCarWithSchemaInFile2.ts", exports.__query = [], exports.__params = [];
60
- exports.__schemas = { reqSchema: undefined, resSchema: { "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false } };
60
+ exports.__schemas = { reqSchema: undefined, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "car": { "type": "object", "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "additionalProperties": false } }, "required": ["car"], "additionalProperties": false, "definitions": {} } };
@@ -53,4 +53,4 @@ var manuallyAddedHandler = function (_a) {
53
53
  };
54
54
  exports.default = manuallyAddedHandler;
55
55
  exports.__assumedHttpMethod = "", exports.__file = "ManuallyAddedHandler.ts", exports.__query = [], exports.__params = [];
56
- exports.__schemas = { reqSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] }, resSchema: undefined };
56
+ exports.__schemas = { reqSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} }, resSchema: undefined };
@@ -55,4 +55,4 @@ var manuallyAddedHandler = function (_a) {
55
55
  };
56
56
  exports.default = manuallyAddedHandler;
57
57
  exports.__assumedHttpMethod = "", exports.__file = "ManuallyAddedHandler2.ts", exports.__query = [], exports.__params = [];
58
- exports.__schemas = { reqSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] }, resSchema: undefined };
58
+ exports.__schemas = { reqSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} }, resSchema: undefined };
@@ -54,4 +54,4 @@ var PostCar = function (_a) {
54
54
  };
55
55
  exports.default = PostCar;
56
56
  exports.__assumedHttpMethod = "post", exports.__file = "PostCar.ts", exports.__query = [], exports.__params = [];
57
- exports.__schemas = { reqSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] }, resSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] } };
57
+ exports.__schemas = { reqSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} }, resSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} } };
@@ -54,4 +54,4 @@ var PutCar = function (_a) {
54
54
  };
55
55
  exports.default = PutCar;
56
56
  exports.__assumedHttpMethod = "put", exports.__file = "PutCar.ts", exports.__query = [], exports.__params = [];
57
- exports.__schemas = { reqSchema: { "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"] }, resSchema: undefined };
57
+ exports.__schemas = { reqSchema: { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "properties": { "model": { "type": "string" }, "metadata": { "type": "object", "properties": { "created": { "type": "string", "format": "date-time" } }, "additionalProperties": false } }, "required": ["model"], "definitions": {} }, resSchema: undefined };
@@ -1,89 +1,7 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
- import { deRefSchema, getJsDocComment } from "../src/utils";
2
+ import { getJsDocComment } from "../src/utils";
3
3
 
4
4
  describe("Utils", () => {
5
- describe("deref", () => {
6
- it("should de-ref json schema", () => {
7
- const dereffedSchema = deRefSchema(jsonSchemas.definitions!.GetCar2_10_ResSchema, jsonSchemas);
8
-
9
- const schema = dereffedSchema as JSONSchema7;
10
-
11
- // @ts-ignore
12
- expect(schema.properties.engine.type).toBe("object");
13
-
14
- // @ts-ignore
15
- expect(schema.properties.model.properties.engine.type).toBe("object");
16
-
17
- // @ts-ignore
18
- expect(schema.properties.tires.items.type).toBe("object");
19
- });
20
-
21
- it("should de-ref json schema (nested prop)", () => {
22
- const dereffedSchema = deRefSchema(jsonSchemas.definitions!.Login, jsonSchemas);
23
-
24
- const schema = dereffedSchema as JSONSchema7;
25
-
26
- // @ts-ignore
27
- expect(schema.properties.user.properties.profile.type).toBe("object");
28
- });
29
-
30
- it("should de-ref json schema which is an array", () => {
31
- const dereffedSchema = deRefSchema(jsonSchemas.definitions!.Cars, jsonSchemas);
32
-
33
- const schema = dereffedSchema as JSONSchema7;
34
-
35
- expect(schema.type).toBe("array");
36
-
37
- // @ts-ignore
38
- expect(schema.items.type).toBe("object");
39
- });
40
-
41
- it("should de-ref json schema which is an array 2", () => {
42
- const dereffedSchema = deRefSchema(jsonSchemas.definitions!.Cars2, jsonSchemas);
43
-
44
- const schema = dereffedSchema as JSONSchema7;
45
-
46
- expect(schema.type).toBe("array");
47
-
48
- // @ts-ignore
49
- expect(schema.items.type).toBe("object");
50
-
51
- // @ts-ignore
52
- expect(schema.items.properties.model.type).toBe("object");
53
- });
54
-
55
- it("should de-ref complex json schema", () => {
56
- const dereffedSchema = deRefSchema(jsonSchemasSet2.definitions!.GetStorages_9_ResSchema, jsonSchemasSet2);
57
-
58
- const schema = dereffedSchema as JSONSchema7;
59
-
60
- expect(schema.type).toBe("object");
61
-
62
- // @ts-ignore
63
- expect(schema.properties.storages.type).toBe("array");
64
-
65
- // @ts-ignore
66
- expect(schema.properties.storages.items.properties.metadata.type).toBe("object");
67
- });
68
-
69
- it("should de-ref with anyOf in array", () => {
70
- const dereffedSchema = deRefSchema(jsonSchemaSet3.definitions!.GetStorages_9_ResSchema, jsonSchemaSet3);
71
-
72
- const schema = dereffedSchema as JSONSchema7;
73
-
74
- expect(schema.type).toBe("object");
75
-
76
- // @ts-ignore
77
- expect(schema.properties.storages.type).toBe("array");
78
-
79
- // @ts-ignore
80
- expect(schema.properties.storages.items.anyOf[0].type).toBe("object");
81
-
82
- // @ts-ignore
83
- expect(schema.properties.storages.items.anyOf[1].type).toBe("object");
84
- });
85
- });
86
-
87
5
  describe("getJsDocComment", () => {
88
6
  it("should strip comment chars and return string", () => {
89
7
  const comment = `
package/src/FlinkApp.ts CHANGED
@@ -162,6 +162,12 @@ export interface FlinkOptions {
162
162
  // */
163
163
  // autoAssignCollection?: string;
164
164
  };
165
+
166
+ /**
167
+ * If true, the HTTP server will be disabled.
168
+ * Only useful when starting a Flink app for testing purposes.
169
+ */
170
+ disableHttpServer?: boolean;
165
171
  }
166
172
 
167
173
  export interface HandlerConfig {
@@ -203,6 +209,7 @@ export class FlinkApp<C extends FlinkContext> {
203
209
  private routingConfigured = false;
204
210
  private jsonOptions?: OptionsJson;
205
211
  private schedulingOptions?: FlinkOptions["scheduling"];
212
+ private disableHttpServer = false;
206
213
 
207
214
  private repos: { [x: string]: FlinkRepo<C> } = {};
208
215
 
@@ -224,6 +231,7 @@ export class FlinkApp<C extends FlinkContext> {
224
231
  this.auth = opts.auth;
225
232
  this.jsonOptions = opts.jsonOptions || { limit: "1mb" };
226
233
  this.schedulingOptions = opts.scheduling;
234
+ this.disableHttpServer = !!opts.disableHttpServer;
227
235
  }
228
236
 
229
237
  get ctx() {
@@ -253,18 +261,22 @@ export class FlinkApp<C extends FlinkContext> {
253
261
 
254
262
  if (this.isSchedulingEnabled) {
255
263
  this.scheduler = new ToadScheduler();
264
+ } else {
265
+ log.info("🚫 Scheduling is disabled");
256
266
  }
257
267
 
258
- this.expressApp = express();
268
+ if (!this.disableHttpServer) {
269
+ this.expressApp = express();
259
270
 
260
- this.expressApp.use(cors(this.corsOpts));
271
+ this.expressApp.use(cors(this.corsOpts));
261
272
 
262
- this.expressApp.use(bodyParser.json(this.jsonOptions));
273
+ this.expressApp.use(bodyParser.json(this.jsonOptions));
263
274
 
264
- this.expressApp.use((req, res, next) => {
265
- req.reqId = v4();
266
- next();
267
- });
275
+ this.expressApp.use((req, res, next) => {
276
+ req.reqId = v4();
277
+ next();
278
+ });
279
+ }
268
280
 
269
281
  // TODO: Add better more fine grained control when plugins are initialized, i.e. in what order
270
282
 
@@ -301,18 +313,24 @@ export class FlinkApp<C extends FlinkContext> {
301
313
  // Register 404 with slight delay to allow all manually added routes to be added
302
314
  // TODO: Is there a better solution to force this handler to always run last?
303
315
  setTimeout(() => {
304
- this.expressApp!.use((req, res, next) => {
305
- res.status(404).json(notFound());
306
- });
316
+ if (!this.disableHttpServer) {
317
+ this.expressApp!.use((req, res, next) => {
318
+ res.status(404).json(notFound());
319
+ });
320
+ }
307
321
 
308
322
  this.routingConfigured = true;
309
323
  });
310
324
 
311
- this.expressApp?.listen(this.port, () => {
312
- log.fontColorLog("magenta", `⚡️ HTTP server '${this.name}' is running and waiting for connections on ${this.port}`);
313
-
325
+ if (this.disableHttpServer) {
326
+ log.info("🚧 HTTP server is disabled, but flink app is running");
314
327
  this.started = true;
315
- });
328
+ } else {
329
+ this.expressApp?.listen(this.port, () => {
330
+ log.fontColorLog("magenta", `⚡️ HTTP server '${this.name}' is running and waiting for connections on ${this.port}`);
331
+ this.started = true;
332
+ });
333
+ }
316
334
 
317
335
  return this;
318
336
  }
@@ -381,7 +399,6 @@ export class FlinkApp<C extends FlinkContext> {
381
399
 
382
400
  const { routeProps, schema = {} } = handlerConfig;
383
401
  const { method } = routeProps;
384
- const app = this.expressApp!;
385
402
 
386
403
  if (!method) {
387
404
  log.error(`Route ${routeProps.path} is missing http method`);
@@ -390,7 +407,11 @@ export class FlinkApp<C extends FlinkContext> {
390
407
  if (method) {
391
408
  const methodAndRoute = `${method.toUpperCase()} ${routeProps.path}`;
392
409
 
393
- app[method](routeProps.path, async (req, res) => {
410
+ if (this.disableHttpServer) {
411
+ return;
412
+ }
413
+
414
+ this.expressApp![method](routeProps.path, async (req, res) => {
394
415
  if (routeProps.permissions) {
395
416
  if (!(await this.authenticate(req, routeProps.permissions))) {
396
417
  return res.status(401).json(unauthorized());
@@ -19,7 +19,7 @@ import {
19
19
  } from "ts-morph";
20
20
  import { writeJsonFile } from "./FsUtils";
21
21
  import { addImports, getDefaultExport, getInterfaceName, getTypeMetadata, getTypesToImport } from "./TypeScriptUtils";
22
- import { deRefSchema, getCollectionNameForRepo, getHttpMethodFromHandlerName, getRepoInstanceName } from "./utils";
22
+ import { getCollectionNameForRepo, getHttpMethodFromHandlerName, getRepoInstanceName } from "./utils";
23
23
 
24
24
  class TypeScriptCompiler {
25
25
  private project: Project;
@@ -438,8 +438,8 @@ import "..${appEntryScript.replace(/\.ts/g, "")}";
438
438
 
439
439
  private initJsonSchemaGenerator() {
440
440
  const conf: Config = {
441
- // expose: "",
442
- // topRef: false,
441
+ expose: "none", // Do not create shared $ref definitions.
442
+ topRef: false, // Removes the wrapper object around the schema.
443
443
  };
444
444
  const formatter = createFormatter(conf);
445
445
  const parser = createParser(this.project.getProgram().compilerObject, conf);
@@ -453,10 +453,10 @@ import "..${appEntryScript.replace(/\.ts/g, "")}";
453
453
 
454
454
  for (const { reqSchemaType, resSchemaType } of schemas) {
455
455
  if (reqSchemaType) {
456
- jsonSchemas.push(this.generateJsonSchema(reqSchemaType));
456
+ jsonSchemas.push({ definitions: { [reqSchemaType]: this.generateJsonSchema(reqSchemaType) } });
457
457
  }
458
458
  if (resSchemaType) {
459
- jsonSchemas.push(this.generateJsonSchema(resSchemaType));
459
+ jsonSchemas.push({ definitions: { [resSchemaType]: this.generateJsonSchema(resSchemaType) } });
460
460
  }
461
461
  }
462
462
 
@@ -594,17 +594,17 @@ ${this.parsedTsSchemas.join("\n\n")}`
594
594
 
595
595
  for (const { sourceFile, reqSchemaType, resSchemaType } of handlers) {
596
596
  if (reqSchemaType && !jsonSchemaDefs[reqSchemaType]) {
597
- console.error(`Handler ${sourceFile.getBaseName} has request schema (${reqSchemaType}) defined, but JSON schema has been generated`);
597
+ console.error(`Handler ${sourceFile.getBaseName()} has request schema (${reqSchemaType}) defined, but no JSON schema has been generated`);
598
598
  continue;
599
599
  }
600
600
 
601
601
  if (resSchemaType && !jsonSchemaDefs[resSchemaType]) {
602
- console.error(`Handler ${sourceFile.getBaseName} has response schema (${resSchemaType}) defined, but JSON schema has been generated`);
602
+ console.error(`Handler ${sourceFile.getBaseName()} has response schema (${resSchemaType}) defined, but no JSON schema has been generated`);
603
603
  continue;
604
604
  }
605
605
 
606
- const reqJsonSchema = JSON.stringify(reqSchemaType ? deRefSchema(jsonSchemaDefs[reqSchemaType], jsonSchemas) : undefined);
607
- const resJsonSchema = JSON.stringify(resSchemaType ? deRefSchema(jsonSchemaDefs[resSchemaType], jsonSchemas) : undefined);
606
+ const reqJsonSchema = JSON.stringify(reqSchemaType ? jsonSchemaDefs[reqSchemaType] : undefined);
607
+ const resJsonSchema = JSON.stringify(resSchemaType ? jsonSchemaDefs[resSchemaType] : undefined);
608
608
 
609
609
  sourceFile.addVariableStatement({
610
610
  declarationKind: VariableDeclarationKind.Const,
package/src/utils.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Request } from "express";
2
- import { JSONSchema7, JSONSchema7Definition } from "json-schema";
3
2
  import { join, sep } from "path";
4
3
  import tinyGlob from "tiny-glob";
5
4
  import { HttpMethod } from "./FlinkHttpHandler";
@@ -78,84 +77,6 @@ export function getHttpMethodFromHandlerName(handlerFilename: string) {
78
77
  if (handlerFilename.startsWith(HttpMethod.delete)) return HttpMethod.delete;
79
78
  }
80
79
 
81
- /**
82
- * Recursively iterates thru json schema properties and replaces any $ref
83
- * with the actual definiton if it exists withing provided `jsonSchemas`.
84
- *
85
- * @param schemaToDeRef
86
- * @param jsonSchemas
87
- * @returns
88
- */
89
- export function deRefSchema(schemaToDeRef: JSONSchema7Definition, jsonSchemas: JSONSchema7) {
90
- if (typeof schemaToDeRef === "boolean") {
91
- return schemaToDeRef;
92
- }
93
-
94
- if (schemaToDeRef.type === "array") {
95
- const items = schemaToDeRef.items as JSONSchema7;
96
-
97
- if (items.$ref) {
98
- const [_0, _1, defKey] = items.$ref.split("/");
99
- const refedSchema = (jsonSchemas.definitions || {})[defKey];
100
-
101
- if (refedSchema) {
102
- schemaToDeRef.items = deRefSchema(refedSchema, jsonSchemas);
103
- } else {
104
- console.warn(`Failed to find deref ${schemaToDeRef.$ref}`);
105
- }
106
- } else {
107
- schemaToDeRef.items = deRefSchema(schemaToDeRef.items as JSONSchema7, jsonSchemas);
108
- }
109
- } else if (schemaToDeRef.properties) {
110
- for (const k in schemaToDeRef.properties) {
111
- let prop = schemaToDeRef.properties[k];
112
-
113
- if (typeof prop === "boolean") {
114
- continue;
115
- }
116
-
117
- if (prop.$ref) {
118
- const [_0, _1, defKey] = prop.$ref.split("/");
119
- const refedSchema = (jsonSchemas.definitions || {})[defKey];
120
- if (refedSchema) {
121
- schemaToDeRef.properties[k] = deRefSchema(refedSchema, jsonSchemas);
122
- } else {
123
- console.warn(`Failed to find deref ${prop.$ref}`);
124
- }
125
- } else if (prop.type === "array" && (prop.items as JSONSchema7).$ref) {
126
- const [_0, _1, defKey] = (prop.items as JSONSchema7).$ref!.split("/");
127
- const refedSchema = (jsonSchemas.definitions || {})[defKey];
128
- if (refedSchema) {
129
- (schemaToDeRef.properties[k] as JSONSchema7).items = deRefSchema(refedSchema, jsonSchemas);
130
- } else {
131
- console.warn(`Failed to find deref ${prop.$ref}`);
132
- }
133
- } else if (prop.type === "object" || prop.type === "array") {
134
- schemaToDeRef.properties[k] = deRefSchema(prop, jsonSchemas);
135
- }
136
- }
137
- } else if (schemaToDeRef.anyOf) {
138
- let i = 0;
139
- for (const anyOf of schemaToDeRef.anyOf) {
140
- const anyOfSchema = anyOf as JSONSchema7;
141
-
142
- if (anyOfSchema.$ref) {
143
- const [_0, _1, defKey] = anyOfSchema.$ref.split("/");
144
- const refedSchema = (jsonSchemas.definitions || {})[defKey];
145
- if (refedSchema) {
146
- schemaToDeRef.anyOf[i] = deRefSchema(refedSchema, jsonSchemas);
147
- } else {
148
- console.warn(`Failed to find deref ${anyOfSchema.$ref}`);
149
- }
150
- }
151
-
152
- i++;
153
- }
154
- }
155
-
156
- return schemaToDeRef;
157
- }
158
-
159
80
  export function getJsDocComment(comment: string) {
160
81
  const rows = comment.split("\n").map((line) => {
161
82
  line = line.trim();