initial commit
This commit is contained in:
parent
cfb30180b5
commit
8acf2b454c
8
api/README.md
Normal file
8
api/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# ToDo
|
||||
Interfaces in here should be generated based on the Modules in pages.
|
||||
|
||||
## Create frontend
|
||||
|
||||
- Using `openapi-generator`:
|
||||
`npx openapi-generator generate -i http://localhost:3000/api/api-docs -g typescript-inversify -o ./dist/generated`
|
||||
|
51
api/helloWorldService.ts
Normal file
51
api/helloWorldService.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { Operation } from "express-openapi";
|
||||
|
||||
// ./api-v1/paths/worlds.js
|
||||
export default function () {
|
||||
let operations = {
|
||||
POST
|
||||
};
|
||||
|
||||
// Define the Action.
|
||||
async function POST(req, res, next) {
|
||||
res.status(200).json('HELLO ' + req.body.greeter);
|
||||
}
|
||||
|
||||
// Define the apiDoc for this specific Funtion
|
||||
POST.apiDoc = {
|
||||
summary: 'Says Hello to the greater',
|
||||
operationId: 'getHello',
|
||||
parameters: [
|
||||
{
|
||||
name: "body",
|
||||
in: "body",
|
||||
description: "Body of the Message",
|
||||
required: true,
|
||||
schema: {
|
||||
description: "The Body. Containing The Greeter Object",
|
||||
properties: {
|
||||
greeter: {
|
||||
type: "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'The Greeting Message',
|
||||
schema: {
|
||||
type: 'string',
|
||||
}
|
||||
},
|
||||
default: {
|
||||
description: 'An error occurred',
|
||||
schema: {
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
}
|
||||
} as Operation;
|
||||
|
||||
return operations;
|
||||
}
|
12
helpers/generateFrontendInterfaces.ts
Normal file
12
helpers/generateFrontendInterfaces.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import {generate} from 'openapi-typescript-codegen';
|
||||
import { startBackend } from '../src/startBackend';
|
||||
|
||||
// Start the Backend
|
||||
const result = startBackend({port: 3001});
|
||||
|
||||
generate({
|
||||
input: 'http://localhost:3001' + result.definitionUri,
|
||||
output: './pages/interface'
|
||||
});
|
||||
|
||||
result.close()
|
2
next-env.d.ts
vendored
Normal file
2
next-env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
6861
package-lock.json
generated
Normal file
6861
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
49
package.json
Normal file
49
package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "nope-backend",
|
||||
"version": "1.0.0",
|
||||
"description": "Nodejs Backend, combining nextjs with openapi",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"generate-frontend-interfaces": "openapi --input http://localhost:3000/api/api-docs --output ./pages/interfaces",
|
||||
"compile-backend": "tsc -p ./tsconfigBackend.json",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/anti-held-333/nope-backend.git"
|
||||
},
|
||||
"keywords": [
|
||||
"nextjs",
|
||||
"openapi"
|
||||
],
|
||||
"author": "anti-held-333",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/anti-held-333/nope-backend/issues"
|
||||
},
|
||||
"homepage": "https://github.com/anti-held-333/nope-backend#readme",
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.5.2",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"express-openapi": "^7.0.0",
|
||||
"inversify": "^5.0.1",
|
||||
"lodash": "^4.17.20",
|
||||
"next": "^9.5.2",
|
||||
"react": "^16.13.1",
|
||||
"react-bootstrap": "^1.3.0",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openapitools/openapi-generator-cli": "^1.0.15-4.3.1",
|
||||
"@types/express": "^4.17.7",
|
||||
"@types/lodash": "^4.14.159",
|
||||
"@types/node": "^14.6.0",
|
||||
"@types/react": "^16.9.46",
|
||||
"openapi-typescript-codegen": "^0.4.10",
|
||||
"typescript": "^3.9.7"
|
||||
}
|
||||
}
|
5
pages/_app.tsx
Normal file
5
pages/_app.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
6
pages/index.tsx
Normal file
6
pages/index.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
export default function Home(){
|
||||
|
||||
return (
|
||||
<h1>Welcome</h1>
|
||||
)
|
||||
}
|
25
specs/apiDoc.ts
Normal file
25
specs/apiDoc.ts
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
/**
|
||||
* Function to generate the Base Api Documentation
|
||||
* @param title The Title of the API
|
||||
* @param version The Version
|
||||
* @param basePath A Basepath for the API
|
||||
*/
|
||||
export function apiDoc(title: string, version: string, basePath: string){
|
||||
// Default API Doc
|
||||
const apiDoc = {
|
||||
swagger: '2.0',
|
||||
basePath: basePath || '/v1',
|
||||
info: {
|
||||
title,
|
||||
version
|
||||
},
|
||||
definitions: {
|
||||
},
|
||||
paths: {}
|
||||
};
|
||||
|
||||
return apiDoc;
|
||||
}
|
||||
|
||||
export default apiDoc;
|
4
specs/enrichDoc.ts
Normal file
4
specs/enrichDoc.ts
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
export function addService(){
|
||||
|
||||
}
|
50
src/getBackendAccessors.ts
Normal file
50
src/getBackendAccessors.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { runMiddleware } from './runMiddleware';
|
||||
import { Application } from 'express';
|
||||
import { assignIn } from 'lodash';
|
||||
|
||||
export interface ICallOptions {
|
||||
method: "post",
|
||||
headers?: { 'Content-Type': 'application/json' },
|
||||
|
||||
body: {
|
||||
[index: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that will generate an async accessor Function.
|
||||
* @param app the provided Express App.
|
||||
*/
|
||||
export function getBackendAccesors(app: Application){
|
||||
// Create a Run-Middle-Ware
|
||||
runMiddleware(app);
|
||||
|
||||
// Define a apiCall Function, which could be used to perform internal
|
||||
// Request on the API.
|
||||
function apiCall<T>(url: string, options: ICallOptions){
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
|
||||
// Define the Default Options
|
||||
const defaults: Partial<ICallOptions> = {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}
|
||||
// Mix the Options.
|
||||
const opts: ICallOptions = assignIn(defaults, options);
|
||||
|
||||
// Perform the Call
|
||||
(app as any).runMiddleware(url,opts,(responseCode: number,body: T) => {
|
||||
// Based on the Response code, decide whether the call was a Fail or not.
|
||||
if (responseCode === 200){
|
||||
// If everything is fine,
|
||||
// Just return the body.
|
||||
return resolve(body);
|
||||
} else {
|
||||
const error = new Error('Call Ended with responseCode = ' + responseCode.toString());
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return apiCall;
|
||||
}
|
3
src/index.ts
Normal file
3
src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { startBackend } from "./startBackend";
|
||||
|
||||
startBackend({port: 3001});
|
109
src/runMiddleware.ts
Normal file
109
src/runMiddleware.ts
Normal file
@ -0,0 +1,109 @@
|
||||
// Adapted File from 'run-middleware'
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export function runMiddleware(app) {
|
||||
app.use((req, res, next) => {
|
||||
req.runMiddleware = (path, options, callback) => {
|
||||
if (_.isFunction(options)) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
options.original_req = req;
|
||||
options.original_res = res;
|
||||
app.runMiddleware(path, options, callback);
|
||||
};
|
||||
next();
|
||||
});
|
||||
if (app.runMiddleware) return; // Do not able to add us twice
|
||||
|
||||
app.runMiddleware = function (path, options, callback) {
|
||||
if (callback) callback = _.once(callback);
|
||||
if (typeof options == "function") {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
options = options || {};
|
||||
options.url = path;
|
||||
var new_req, new_res;
|
||||
if (options.original_req) {
|
||||
new_req = options.original_req;
|
||||
for (var i in options) {
|
||||
if (i == "original_req") continue;
|
||||
new_req[i] = options[i];
|
||||
}
|
||||
} else {
|
||||
new_req = createReq(path, options);
|
||||
}
|
||||
new_res = createRes(callback);
|
||||
app(new_req, new_res);
|
||||
};
|
||||
|
||||
/* end - APP.runMiddleware*/
|
||||
};
|
||||
|
||||
function createReq(path, options) {
|
||||
if (!options) options = {};
|
||||
var req = _.extend(
|
||||
{
|
||||
method: "GET",
|
||||
host: "",
|
||||
cookies: {},
|
||||
query: {},
|
||||
url: path,
|
||||
headers: {},
|
||||
},
|
||||
options
|
||||
);
|
||||
req.method = req.method.toUpperCase();
|
||||
// req.connection=_req.connection
|
||||
return req;
|
||||
}
|
||||
function createRes(callback) {
|
||||
var res: any = {
|
||||
_removedHeader: {},
|
||||
};
|
||||
// res=_.extend(res,require('express/lib/response'));
|
||||
|
||||
var headers = {};
|
||||
var code = 200;
|
||||
res.set = res.header = function (x, y){
|
||||
if (arguments.length === 2) {
|
||||
res.setHeader(x, y);
|
||||
} else {
|
||||
for (var key in x) {
|
||||
res.setHeader(key, x[key]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
res.setHeader = function (x, y) {
|
||||
headers[x] = y;
|
||||
headers[x.toLowerCase()] = y;
|
||||
return res;
|
||||
};
|
||||
res.get = function (x) {
|
||||
return headers[x]
|
||||
}
|
||||
res.redirect = function (_code, url) {
|
||||
if (!_.isNumber(_code)) {
|
||||
code = 301;
|
||||
url = _code;
|
||||
} else {
|
||||
code = _code;
|
||||
}
|
||||
res.setHeader("Location", url);
|
||||
res.end();
|
||||
// callback(code,url)
|
||||
};
|
||||
res.status = function (number) {
|
||||
code = number;
|
||||
return res;
|
||||
};
|
||||
res.end = res.send = res.write = function (data) {
|
||||
if (callback) callback(code, data, headers);
|
||||
// else if (!options.quiet){
|
||||
// _res.send(data)
|
||||
// }
|
||||
};
|
||||
return res;
|
||||
}
|
51
src/startBackend.ts
Normal file
51
src/startBackend.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { apiDoc } from '../specs/apiDoc';
|
||||
import * as express from "express";
|
||||
import * as bodyParser from "body-parser";
|
||||
import { initialize } from "express-openapi";
|
||||
import { getBackendAccesors } from './getBackendAccessors';
|
||||
import { assignIn } from 'lodash';
|
||||
|
||||
export function startBackend(options: {
|
||||
port?: number,
|
||||
basePath?: string,
|
||||
}= {}) {
|
||||
const app: express.Application = (express as any)();
|
||||
|
||||
// Define the Default Options
|
||||
const defaults = {
|
||||
port: 3001,
|
||||
basePath: '/api'
|
||||
}
|
||||
// Mix the Options.
|
||||
const opts = assignIn(defaults, options);
|
||||
|
||||
app.use(bodyParser.json());
|
||||
|
||||
initialize({
|
||||
apiDoc: apiDoc('Test API', '0.0.1', opts.basePath),
|
||||
app,
|
||||
paths: './dist/api',
|
||||
routesGlob: '**/*.{ts,js}',
|
||||
routesIndexFileRegExp: /(?:index)?\.[tj]s$/
|
||||
});
|
||||
|
||||
app.use(((err, req, res, next) => {
|
||||
res.status(err.status).json(err);
|
||||
}) as express.ErrorRequestHandler);
|
||||
|
||||
const server = app.listen(opts.port);
|
||||
|
||||
const accessor = getBackendAccesors(app);
|
||||
|
||||
return {
|
||||
app,
|
||||
// Accessor for the Server
|
||||
accessor,
|
||||
// Function to extract the Definitions.
|
||||
definitionUri: opts.basePath + '/api-docs',
|
||||
// Function to Close the Server
|
||||
close() {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
}
|
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
35
tsconfigBackend.json
Normal file
35
tsconfigBackend.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"allowUnusedLabels": true,
|
||||
"charset": "utf-8",
|
||||
"experimentalDecorators": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noImplicitReturns": true,
|
||||
"outDir": "./dist",
|
||||
"pretty": false,
|
||||
"removeComments": true,
|
||||
"rootDir": "./",
|
||||
"stripInternal": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"helpers",
|
||||
"api",
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"pages",
|
||||
".next"
|
||||
]
|
||||
}
|
3
types/IJSONSchema.ts
Normal file
3
types/IJSONSchema.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface IJSONSchema {
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user