Working server with example graphql

pull/1/head
Trivernis 5 years ago
parent 90cafe042a
commit f097bc12ea

8
.gitignore vendored

@ -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());
});

4918
package-lock.json generated

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…
Cancel
Save