Working server with example graphql
parent
90cafe042a
commit
f097bc12ea
@ -0,0 +1,8 @@
|
|||||||
|
.nyc_output/
|
||||||
|
coverage/
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
test/*.log
|
||||||
|
dist
|
||||||
|
.idea
|
||||||
|
config.yaml
|
@ -0,0 +1,39 @@
|
|||||||
|
const {src, dest, watch, series, task} = require('gulp');
|
||||||
|
const ts = require('gulp-typescript');
|
||||||
|
const del = require('delete');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the dist folder by deleting all files inside.
|
||||||
|
* @param cb
|
||||||
|
*/
|
||||||
|
function clearDist(cb) {
|
||||||
|
del('dist/*', cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typescript compilation task.
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function compileTypescript() {
|
||||||
|
let tsProject = ts.createProject('tsconfig.json');
|
||||||
|
let tsResult = tsProject.src().pipe(tsProject());
|
||||||
|
return tsResult
|
||||||
|
//.pipe(minify())
|
||||||
|
.pipe(dest('dist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for moving all remaining file from source to dist that don't need procession.
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function moveRemaining() {
|
||||||
|
return src(['src/**/*', '!src/**/*.ts'])
|
||||||
|
.pipe(dest('dist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
task('default', series(clearDist, compileTypescript, moveRemaining));
|
||||||
|
|
||||||
|
task('watch', () => {
|
||||||
|
watch('**/*.ts', compileTypescript);
|
||||||
|
watch(['src/**/*', '!src/**/*.ts'], moveRemaining());
|
||||||
|
});
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "typescript-graphql-server-template",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Template for express graphql servers",
|
||||||
|
"main": "./dist",
|
||||||
|
"dependencies": {
|
||||||
|
"compression": "^1.7.4",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-graphql": "^0.9.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"graphql": "^14.5.8",
|
||||||
|
"graphql-import": "^0.7.1",
|
||||||
|
"http-status": "^1.3.2",
|
||||||
|
"js-yaml": "^3.13.1",
|
||||||
|
"winston": "^3.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/compression": "^1.0.1",
|
||||||
|
"@types/express": "^4.17.1",
|
||||||
|
"@types/fs-extra": "^8.0.0",
|
||||||
|
"@types/http-status": "^0.2.30",
|
||||||
|
"@types/js-yaml": "^3.12.1",
|
||||||
|
"delete": "^1.1.0",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-typescript": "^5.0.1",
|
||||||
|
"tsc": "^1.20150623.0",
|
||||||
|
"tslint": "^5.20.0",
|
||||||
|
"typescript": "^3.6.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"Template",
|
||||||
|
"Graphql",
|
||||||
|
"Typescript",
|
||||||
|
"Express",
|
||||||
|
"Nodejs"
|
||||||
|
],
|
||||||
|
"author": "Trivernis",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
import * as compression from "compression";
|
||||||
|
import * as express from "express";
|
||||||
|
import * as graphqlHTTP from "express-graphql";
|
||||||
|
import {buildSchema} from "graphql";
|
||||||
|
import {importSchema} from "graphql-import";
|
||||||
|
import * as http from "http";
|
||||||
|
import * as path from "path";
|
||||||
|
import globals from "./lib/globals";
|
||||||
|
import {resolvers} from "./graphql/resolvers";
|
||||||
|
|
||||||
|
const logger = globals.logger;
|
||||||
|
const config = globals.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main class of the application server.
|
||||||
|
*/
|
||||||
|
class App {
|
||||||
|
public app: express.Application;
|
||||||
|
public server: http.Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* creates a new app and server for the app.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.app = express();
|
||||||
|
this.server = new http.Server(this.app);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes everything that needs to be initialized (can be asynchronous).
|
||||||
|
* If database connections need to be established you would handle that here.
|
||||||
|
*/
|
||||||
|
public async init() {
|
||||||
|
this.app.set("trust proxy", 1);
|
||||||
|
|
||||||
|
this.app.use(compression());
|
||||||
|
this.app.use(express.json());
|
||||||
|
this.app.use(express.urlencoded({extended: false}));
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
logger.verbose(`${req.method} ${req.url}`);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
this.app.use("/graphql", graphqlHTTP((request, response) => {
|
||||||
|
return {
|
||||||
|
graphiql: config.graphql.graphiql,
|
||||||
|
rootValue: resolvers(request, response),
|
||||||
|
schema: buildSchema(importSchema(path.join(__dirname, "./graphql/schema.graphql"))),
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the web server.
|
||||||
|
*/
|
||||||
|
public start() {
|
||||||
|
if (config.server.port) {
|
||||||
|
logger.info(`Starting server...`);
|
||||||
|
this.app.listen(config.server.port);
|
||||||
|
logger.info(`Server running on port ${config.server.port}`);
|
||||||
|
} else {
|
||||||
|
logger.error("No port specified in the config." +
|
||||||
|
"Please configure a port in the config.yaml.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,11 @@
|
|||||||
|
# http server configuration
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
# graphql configuration
|
||||||
|
graphql:
|
||||||
|
graphiql: true
|
||||||
|
|
||||||
|
# logging configuration
|
||||||
|
logging:
|
||||||
|
loglevel: debug
|
@ -0,0 +1,20 @@
|
|||||||
|
import * as http from "http";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for graphql resolvers.
|
||||||
|
* This function provides additional access to the request and response object.
|
||||||
|
* Each field defined in the schema should be resolved by a function or static value here.
|
||||||
|
* More information: {@link https://graphql.org/graphql-js/running-an-express-graphql-server/}
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
export function resolvers(req: http.IncomingMessage, res: http.OutgoingMessage) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Example resolver for the example time query field.
|
||||||
|
*/
|
||||||
|
time() {
|
||||||
|
return (new Date()).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
# Provide the graphql schema in this file.
|
||||||
|
|
||||||
|
# The query entry type.
|
||||||
|
type Query {
|
||||||
|
time: String
|
||||||
|
}
|
||||||
|
|
||||||
|
# The mutation entry type.
|
||||||
|
# type Mutation {
|
||||||
|
# }
|
@ -0,0 +1,10 @@
|
|||||||
|
import App from "./app";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async main function wrapper.
|
||||||
|
*/
|
||||||
|
(async () => {
|
||||||
|
const app = new App();
|
||||||
|
await app.init();
|
||||||
|
app.start();
|
||||||
|
})();
|
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* @author Trivernis
|
||||||
|
* @remarks
|
||||||
|
*
|
||||||
|
* Partly taken from {@link https://github.com/Trivernis/whooshy}#
|
||||||
|
*
|
||||||
|
* Provides global variables that are used in the whole project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fsx from "fs-extra";
|
||||||
|
import * as yaml from "js-yaml";
|
||||||
|
import * as winston from "winston";
|
||||||
|
|
||||||
|
const configPath = "config.yaml";
|
||||||
|
const defaultConfig = __dirname + "/../default-config.yaml";
|
||||||
|
|
||||||
|
// ensure that the config exists by copying the default config.
|
||||||
|
if (!(fsx.pathExistsSync(configPath))) {
|
||||||
|
fsx.copySync(defaultConfig, configPath);
|
||||||
|
} else {
|
||||||
|
const conf = yaml.safeLoad(fsx.readFileSync(configPath, "utf-8"));
|
||||||
|
const defConf = yaml.safeLoad(fsx.readFileSync(defaultConfig, "utf-8"));
|
||||||
|
fsx.writeFileSync(configPath, yaml.safeDump(Object.assign(defConf, conf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines global variables to be used.
|
||||||
|
*/
|
||||||
|
namespace globals {
|
||||||
|
export const config = yaml.safeLoad(fsx.readFileSync("config.yaml", "utf-8"));
|
||||||
|
export const logger = winston.createLogger({
|
||||||
|
transports: [
|
||||||
|
new winston.transports.Console({
|
||||||
|
format: winston.format.combine(
|
||||||
|
winston.format.timestamp(),
|
||||||
|
winston.format.colorize(),
|
||||||
|
winston.format.printf(({ level, message, timestamp }) => {
|
||||||
|
return `${timestamp} ${level}: ${message}`;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
level: config.logging.loglevel,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default globals;
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compileOnSave": true,
|
||||||
|
"compilerOptions": {
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"sourceMap": true,
|
||||||
|
"target": "es2018",
|
||||||
|
"allowJs": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"module": "commonjs"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"extends": "tslint:recommended",
|
||||||
|
"rulesDirectory": [],
|
||||||
|
"rules": {
|
||||||
|
"max-line-length": {
|
||||||
|
"options": [120]
|
||||||
|
},
|
||||||
|
"new-parens": true,
|
||||||
|
"no-arg": true,
|
||||||
|
"no-bitwise": true,
|
||||||
|
"no-conditional-assignment": true,
|
||||||
|
"no-consecutive-blank-lines": false,
|
||||||
|
"cyclomatic-complexity": true,
|
||||||
|
"brace-style": "1tbs",
|
||||||
|
"semicolon": true,
|
||||||
|
"indent": [true, "spaces", 4],
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-console": {
|
||||||
|
"severity": "warning",
|
||||||
|
"options": ["debug", "info", "log", "time", "timeEnd", "trace"]
|
||||||
|
},
|
||||||
|
"no-namespace": false,
|
||||||
|
"no-internal-module": false,
|
||||||
|
"max-classes-per-file": false
|
||||||
|
},
|
||||||
|
"jsRules": {
|
||||||
|
"max-line-length": {
|
||||||
|
"options": [120]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue