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