Initial commit
This commit is contained in:
6
.babelrc
Normal file
6
.babelrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
["@babel/preset-env", {"targets": {"node": "current"}}],
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
]
|
||||||
|
}
|
8
.env.example
Normal file
8
.env.example
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ENVIRONMENT Defauld production
|
||||||
|
ENV=
|
||||||
|
#WHITELIST URLS Default to http://localhost
|
||||||
|
WHITELIST_URLS=
|
||||||
|
#PLAYGROUND GRAPHQL Default to "false"
|
||||||
|
PLAYGROUND_GRAPHQL=
|
||||||
|
# PORT EXPOSE APP Default to 4000
|
||||||
|
PORT=
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/build
|
||||||
|
.env
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
|
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Alejandro Lembke Barrientos
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
11
PRNameGenerator.ts
Normal file
11
PRNameGenerator.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const PRName = function () {
|
||||||
|
let ID = '';
|
||||||
|
// let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
const characters = '0123456789';
|
||||||
|
for ( let i = 0; i < 6; i++ ) {
|
||||||
|
ID += characters.charAt(Math.floor(Math.random() * 10));
|
||||||
|
}
|
||||||
|
return 'PR-'+ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(PRName());
|
75
README.md
Normal file
75
README.md
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Create Node TS GraphQL Server
|
||||||
|
|
||||||
|
This project aims to have a starter kit for creating a new Node with typescript, GraphQL server and tools that generally go along with it.
|
||||||
|
|
||||||
|
Tech(Library or Framework) | Version |
|
||||||
|
--- | --- |
|
||||||
|
Jest (Testing) | 29.7.0
|
||||||
|
Typescript | 5.6.2
|
||||||
|
GraphQL | 16.9.0
|
||||||
|
Type GraphQL | 2.0.0-rc.2
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
To create a new project run in the terminal:
|
||||||
|
```
|
||||||
|
npx @aleleba/create-node-ts-graphql-server server-app-name
|
||||||
|
```
|
||||||
|
Then run:
|
||||||
|
```
|
||||||
|
cd server-app-name
|
||||||
|
```
|
||||||
|
You will need to create a new .env file at the root of the project for global config.
|
||||||
|
This is an example of config.
|
||||||
|
```
|
||||||
|
#ENVIRONMENT Defauld production
|
||||||
|
ENVIRONMENT=development
|
||||||
|
#WHITELIST URLS Default to http://localhost
|
||||||
|
WHITELIST_URLS=https://someurl.com
|
||||||
|
#PLAYGROUND GRAPHQL Default to "false"
|
||||||
|
PLAYGROUND_GRAPHQL=true
|
||||||
|
# PORT EXPOSE APP Default to 4000
|
||||||
|
PORT=4000
|
||||||
|
```
|
||||||
|
The default environment is production, the server-app port defauld is 4000, the default whitelist is http://localhost and the default graphiql is false.
|
||||||
|
|
||||||
|
### For Development
|
||||||
|
In the terminal run:
|
||||||
|
```
|
||||||
|
npm run start:dev
|
||||||
|
```
|
||||||
|
The ENV enviroment variable should be "development" and choose the port of your preference with the enviroment variable PORT.
|
||||||
|
|
||||||
|
You will find the controllers on:
|
||||||
|
```
|
||||||
|
scr/controllers/
|
||||||
|
```
|
||||||
|
You will find the models on:
|
||||||
|
```
|
||||||
|
scr/models
|
||||||
|
```
|
||||||
|
You will find the GraphQL server, resolvers and schema definition on:
|
||||||
|
```
|
||||||
|
scr/GraphQL
|
||||||
|
```
|
||||||
|
|
||||||
|
The manage of the routes for custom API you should find on:
|
||||||
|
```
|
||||||
|
scr/routes
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start the app in development mode, also use nodemon and webpack to real time coding!
|
||||||
|
Enjoy coding!
|
||||||
|
|
||||||
|
### For Production
|
||||||
|
In the terminal run:
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
It will create a build folder and run:
|
||||||
|
```
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
This will start the app.
|
||||||
|
|
||||||
|
## Cheers
|
||||||
|
Hope you enjoy this proyect! Sincerely Alejandro Lembke Barrientos.
|
17
config/index.ts
Normal file
17
config/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
export const deFaultValues = {
|
||||||
|
ENV: 'production',
|
||||||
|
PLAYGROUND_GRAPHQL: 'false',
|
||||||
|
WHITELIST_URLS: 'http://localhost',
|
||||||
|
PORT: '4000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
ENV: process.env.ENV,
|
||||||
|
PLAYGROUND_GRAPHQL: process.env.PLAYGROUND_GRAPHQL === 'true' ? true : false,
|
||||||
|
WHITELIST_URLS: process.env.WHITELIST_URLS ? process.env.WHITELIST_URLS.split(',') : deFaultValues.WHITELIST_URLS,
|
||||||
|
PORT: process.env.PORT,
|
||||||
|
};
|
55
eslint.config.js
Normal file
55
eslint.config.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import globals from 'globals';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import js from '@eslint/js';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// Ignorar archivos y carpetas especificados en el antiguo .eslintignore
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
'.eslintrc.js', // Aunque se eliminará, es bueno mantenerlo por si acaso
|
||||||
|
'build/',
|
||||||
|
'webpack.config.ts',
|
||||||
|
'webpack.config.dev.ts',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configuración recomendada por ESLint
|
||||||
|
js.configs.recommended,
|
||||||
|
|
||||||
|
// Configuraciones recomendadas por typescript-eslint
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
|
||||||
|
// Configuración personalizada
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2021,
|
||||||
|
sourceType: 'module',
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
// El parser ya está configurado por tseslint.configs.recommended
|
||||||
|
},
|
||||||
|
// Los plugins ya están configurados por tseslint.configs.recommended
|
||||||
|
rules: {
|
||||||
|
// Reglas personalizadas del antiguo .eslintrc.js
|
||||||
|
'indent': [
|
||||||
|
'error',
|
||||||
|
'tab'
|
||||||
|
],
|
||||||
|
'linebreak-style': [
|
||||||
|
'error',
|
||||||
|
'unix'
|
||||||
|
],
|
||||||
|
'quotes': [
|
||||||
|
'error',
|
||||||
|
'single'
|
||||||
|
],
|
||||||
|
'semi': [
|
||||||
|
'error',
|
||||||
|
'always'
|
||||||
|
],
|
||||||
|
// Puedes añadir o sobrescribir reglas de las configuraciones recomendadas aquí si es necesario
|
||||||
|
},
|
||||||
|
}
|
||||||
|
];
|
15
jest.config.js
Normal file
15
jest.config.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const { pathsToModuleNameMapper } = require('ts-jest');
|
||||||
|
const { compilerOptions } = require('./tsconfig');
|
||||||
|
|
||||||
|
const aliases = pathsToModuleNameMapper(compilerOptions.paths, {
|
||||||
|
prefix: '<rootDir>'
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
testEnvironment: 'node',
|
||||||
|
transform: {
|
||||||
|
"^.+\\.ts$": "ts-jest"
|
||||||
|
},moduleNameMapper: {
|
||||||
|
...aliases,
|
||||||
|
},
|
||||||
|
};
|
21924
package-lock.json
generated
Normal file
21924
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
90
package.json
Normal file
90
package.json
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"name": "drawio-cline-mcp-server",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Node with Typescript and GraphQL Server",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node build/index.js",
|
||||||
|
"start:dev": "webpack-cli --config webpack.config.dev.ts",
|
||||||
|
"start:nodemon": "nodemon build/index.js",
|
||||||
|
"build": "webpack-cli --config webpack.config.ts",
|
||||||
|
"lint": "eslint ./ --ext .js --ext .ts",
|
||||||
|
"lint:fix": "eslint ./ --ext .js --ext .ts --fix",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"check-updates": "npx npm-check-updates -u && npm i --legacy-peer-deps"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/aleleba/node-ts-graphql-server.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node",
|
||||||
|
"express",
|
||||||
|
"typescript",
|
||||||
|
"graphql",
|
||||||
|
"server"
|
||||||
|
],
|
||||||
|
"author": "Alejandro Lembke Barrientos",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/aleleba/node-ts-graphql-server/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/aleleba/node-ts-graphql-server#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"@graphql-tools/schema": "^10.0.25",
|
||||||
|
"body-parser": "^2.2.0",
|
||||||
|
"class-validator": "^0.14.2",
|
||||||
|
"cookie-parse": "^0.4.0",
|
||||||
|
"cookie-parser": "^1.4.7",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^17.2.0",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"graphql": "^16.11.0",
|
||||||
|
"graphql-http": "^1.22.4",
|
||||||
|
"graphql-playground-middleware-express": "^1.7.23",
|
||||||
|
"graphql-scalars": "^1.24.2",
|
||||||
|
"graphql-subscriptions": "^3.0.0",
|
||||||
|
"graphql-tools": "^9.0.20",
|
||||||
|
"graphql-ws": "^6.0.6",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"type-graphql": "^2.0.0-rc.2",
|
||||||
|
"web-push": "^3.6.7",
|
||||||
|
"ws": "^8.18.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.28.0",
|
||||||
|
"@babel/preset-env": "^7.28.0",
|
||||||
|
"@babel/preset-typescript": "^7.27.1",
|
||||||
|
"@babel/register": "^7.27.1",
|
||||||
|
"@types/body-parser": "^1.19.6",
|
||||||
|
"@types/cookie-parser": "^1.4.9",
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/express": "^5.0.3",
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/node": "^24.0.15",
|
||||||
|
"@types/supertest": "^6.0.3",
|
||||||
|
"@types/webpack": "^5.28.5",
|
||||||
|
"@types/webpack-node-externals": "^3.0.4",
|
||||||
|
"@types/ws": "^8.18.1",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||||
|
"@typescript-eslint/parser": "^8.38.0",
|
||||||
|
"babel-loader": "^10.0.0",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
|
"eslint": "^9.31.0",
|
||||||
|
"eslint-webpack-plugin": "^5.0.2",
|
||||||
|
"jest": "^30.0.4",
|
||||||
|
"nodemon": "^3.1.10",
|
||||||
|
"resolve-ts-aliases": "^1.0.1",
|
||||||
|
"supertest": "^7.1.3",
|
||||||
|
"ts-jest": "^29.4.0",
|
||||||
|
"ts-loader": "^9.5.2",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"webpack": "^5.100.2",
|
||||||
|
"webpack-cli": "^6.0.1",
|
||||||
|
"webpack-manifest-plugin": "^5.0.1",
|
||||||
|
"webpack-node-externals": "^3.0.0",
|
||||||
|
"webpack-shell-plugin-next": "^2.3.2"
|
||||||
|
}
|
||||||
|
}
|
20
schema.gql
Normal file
20
schema.gql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -----------------------------------------------
|
||||||
|
# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
|
||||||
|
# !!! DO NOT MODIFY THIS FILE BY YOURSELF !!!
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
testMutation: TestMutation!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
test: Test!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test {
|
||||||
|
text: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestMutation {
|
||||||
|
text(text: String!): String!
|
||||||
|
}
|
20
schema.graphql
Normal file
20
schema.graphql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -----------------------------------------------
|
||||||
|
# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
|
||||||
|
# !!! DO NOT MODIFY THIS FILE BY YOURSELF !!!
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type Mutation {
|
||||||
|
testMutation: TestMutation!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
test: Test!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test {
|
||||||
|
text: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestMutation {
|
||||||
|
text(text: String!): String!
|
||||||
|
}
|
14
src/@types/custom.d.ts
vendored
Normal file
14
src/@types/custom.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// index.d.ts
|
||||||
|
declare module "*.gql" {
|
||||||
|
const content: any;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'cookie-parse' {
|
||||||
|
const content: any;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'graphql-ws/use/ws' {
|
||||||
|
export * from 'graphql-ws/dist/use/ws';
|
||||||
|
}
|
1
src/GraphQL/resolvers/index.ts
Normal file
1
src/GraphQL/resolvers/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './test.resolver';
|
33
src/GraphQL/resolvers/test.resolver.ts
Normal file
33
src/GraphQL/resolvers/test.resolver.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { Query, Resolver, Mutation, FieldResolver, Root, Arg } from 'type-graphql';
|
||||||
|
import { Test, TestMutation } from '@GraphQL/schema';
|
||||||
|
import { getTest, addText } from '@controllerGraphQL';
|
||||||
|
|
||||||
|
@Resolver(() => Test)
|
||||||
|
export class TestResolverQuery {
|
||||||
|
@Query(() => Test)
|
||||||
|
async test() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver(() => String)
|
||||||
|
async text() {
|
||||||
|
return await getTest({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resolver(() => TestMutation)
|
||||||
|
export class TestResolverMutation {
|
||||||
|
@Mutation(() => TestMutation)
|
||||||
|
async testMutation() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldResolver(() => String)
|
||||||
|
async text(@Arg('text') text?: string){
|
||||||
|
return await addText({text});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
src/GraphQL/schema/index.ts
Normal file
18
src/GraphQL/schema/index.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
import { buildSchemaSync } from "type-graphql"
|
||||||
|
import {
|
||||||
|
TestResolverQuery,
|
||||||
|
TestResolverMutation
|
||||||
|
} from "@GraphQL/resolvers";
|
||||||
|
|
||||||
|
export * from './test.schema'
|
||||||
|
|
||||||
|
const schema = buildSchemaSync({
|
||||||
|
resolvers: [
|
||||||
|
TestResolverQuery,
|
||||||
|
TestResolverMutation,
|
||||||
|
],
|
||||||
|
emitSchemaFile: true,
|
||||||
|
})
|
||||||
|
export default schema
|
16
src/GraphQL/schema/test.schema.ts
Normal file
16
src/GraphQL/schema/test.schema.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { Field, ObjectType } from 'type-graphql';
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class Test {
|
||||||
|
@Field(() => String)
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class TestMutation {
|
||||||
|
@Field(() => String)
|
||||||
|
text?: string;
|
||||||
|
}
|
30
src/GraphQL/server.ts
Normal file
30
src/GraphQL/server.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import express from 'express'; //express
|
||||||
|
import { createHandler } from 'graphql-http/lib/use/express';
|
||||||
|
import schema from '@src/GraphQL/schema';
|
||||||
|
|
||||||
|
|
||||||
|
const server = express.Router();//Router de Express
|
||||||
|
|
||||||
|
server.use(
|
||||||
|
'/',
|
||||||
|
createHandler({
|
||||||
|
schema,
|
||||||
|
context(req) {
|
||||||
|
const res = req.context.res
|
||||||
|
return {req, res};
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// DO NOT DO app.listen() unless we're testing this directly
|
||||||
|
if (require.main === module) {
|
||||||
|
const app = express();
|
||||||
|
app.listen((process.env.PORT || 4000), () => {
|
||||||
|
console.log(`Iniciando Express en el puerto 4000`); /*${app.get('port')}*/
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead do export the app:
|
||||||
|
export default server;
|
13
src/controllers/controllerGraphQL/index.ts
Normal file
13
src/controllers/controllerGraphQL/index.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { getTestModel, addTextModel } from '@models';
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export const getTest = async ({}) => {
|
||||||
|
return getTestModel();
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export const addText = async ({ text }: {text?: string}) => {
|
||||||
|
return addTextModel({ text });
|
||||||
|
};
|
91
src/index.ts
Normal file
91
src/index.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import 'reflect-metadata';
|
||||||
|
import ws from 'ws'; // yarn add ws
|
||||||
|
import express from 'express'; //express
|
||||||
|
import cors from 'cors';
|
||||||
|
import cookieParser from 'cookie-parser';
|
||||||
|
import { useServer } from 'graphql-ws/use/ws';
|
||||||
|
import { execute, subscribe } from 'graphql';
|
||||||
|
import GraphQLserver from '@GraphQL/server';// Server of GraphQL,
|
||||||
|
import expressPlayground from 'graphql-playground-middleware-express';
|
||||||
|
import schema from '@GraphQL/schema';
|
||||||
|
import { config } from '@config';
|
||||||
|
import apiRouter from '@routes';
|
||||||
|
|
||||||
|
const app = express(), //creating app
|
||||||
|
whitelist = config.WHITELIST_URLS,
|
||||||
|
corsOptions = {
|
||||||
|
origin: function (origin: string | undefined, callback: (arg0: Error | null, arg1?: boolean) => void) {
|
||||||
|
if (whitelist.indexOf(origin as string) !== -1 || !origin) {
|
||||||
|
callback(null, true);
|
||||||
|
} else {
|
||||||
|
callback(new Error('Not allowed by CORS'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
credentials: true
|
||||||
|
};
|
||||||
|
|
||||||
|
//Inicialization of services of express
|
||||||
|
app
|
||||||
|
.use(cookieParser())
|
||||||
|
.use(express.urlencoded({limit: '500mb', extended: true}))
|
||||||
|
.use(express.json({limit: '500mb'}))
|
||||||
|
.use(cors(corsOptions))
|
||||||
|
.use(apiRouter)//Routes de App
|
||||||
|
.use('/graphql', GraphQLserver);//Server of Graphql
|
||||||
|
|
||||||
|
if(config.PLAYGROUND_GRAPHQL === true){
|
||||||
|
app.get('/playground', expressPlayground({
|
||||||
|
endpoint: '/graphql',
|
||||||
|
subscriptionEndpoint: '/graphql',
|
||||||
|
settings: {
|
||||||
|
'request.credentials': 'include', //Include Credentials for playground
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO NOT DO app.listen() unless we're testing this directly
|
||||||
|
if (require.main === module) {
|
||||||
|
|
||||||
|
const server = app.listen(config.PORT, () => {
|
||||||
|
// create and use the websocket server
|
||||||
|
const wsServer = new ws.Server({
|
||||||
|
server,
|
||||||
|
path: '/graphql',
|
||||||
|
});
|
||||||
|
|
||||||
|
useServer({
|
||||||
|
schema,
|
||||||
|
execute,
|
||||||
|
subscribe,
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onConnect: (ctx) => {
|
||||||
|
//console.log('Connect');
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onSubscribe: (ctx, msg) => {
|
||||||
|
//console.log('Subscribe');
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onNext: (ctx, msg, args, result) => {
|
||||||
|
//console.debug('Next');
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onError: (ctx, msg, errors) => {
|
||||||
|
//console.error('Error');
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line
|
||||||
|
onComplete: (ctx, msg) => {
|
||||||
|
//console.log('Complete');
|
||||||
|
},
|
||||||
|
}, wsServer);
|
||||||
|
|
||||||
|
console.log(`Starting Express on port ${config.PORT} and iniciating server of web sockets`);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead do export the app:
|
||||||
|
export default app;
|
9
src/models/index.ts
Normal file
9
src/models/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
export const getTestModel = async () => {
|
||||||
|
return 'This is the text response for Test Query from a model';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addTextModel = async ({ text }: {text?: string}) => {
|
||||||
|
return `Simulate to insert some text: ${text} from a model`;
|
||||||
|
};
|
13
src/routes/index.ts
Normal file
13
src/routes/index.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// use this to set API REST
|
||||||
|
import express from 'express';
|
||||||
|
import bodyParser from 'body-parser';//bodyParser conversionde Api REST,
|
||||||
|
|
||||||
|
const apiRouter = express.Router();//Router de Express
|
||||||
|
|
||||||
|
apiRouter
|
||||||
|
.use(bodyParser.json())
|
||||||
|
.use(bodyParser.urlencoded({extended: false}));
|
||||||
|
|
||||||
|
export default apiRouter;
|
41
src/tests/server/index.test.ts
Normal file
41
src/tests/server/index.test.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import server from '@src';
|
||||||
|
import supertest from 'supertest';
|
||||||
|
describe('global server tests', () => {
|
||||||
|
let request: supertest.SuperTest<supertest.Test>;
|
||||||
|
beforeEach( async () => {
|
||||||
|
request = await supertest(server) as unknown as supertest.SuperTest<supertest.Test>;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return Test data from test Query', async () => {
|
||||||
|
const bodyResponse = {
|
||||||
|
data: {
|
||||||
|
test: {
|
||||||
|
text: 'This is the text response for Test Query from a model'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await request.get('/graphql?query=%7B%0A%20%20test%7B%0A%20%20%20%20text%0A%20%20%7D%0A%7D')
|
||||||
|
.set('Accept', 'application/json');
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.body).toEqual(bodyResponse);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return Test data from test Mutation', async () => {
|
||||||
|
const bodyResponse = {
|
||||||
|
data: {
|
||||||
|
testMutation: {
|
||||||
|
text: 'Simulate to insert some text: testing text from a model'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const response = await request.post('/graphql')
|
||||||
|
.send({'query': `mutation{
|
||||||
|
testMutation{
|
||||||
|
text(text: "testing text")
|
||||||
|
}
|
||||||
|
}`})
|
||||||
|
.set('Accept', 'application/json');
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.body).toEqual(bodyResponse);
|
||||||
|
});
|
||||||
|
});
|
32
tsconfig.json
Normal file
32
tsconfig.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "es2021",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"sourceMap": true,
|
||||||
|
"typeRoots" : ["./src/@types", "./node_modules/@types"],
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@src/*": ["src/*"],
|
||||||
|
"@src": ["src"],
|
||||||
|
"@routes*": ["src/routes/*"],
|
||||||
|
"@routes": ["src/routes"],
|
||||||
|
"@controllers/*": ["src/controllers/*"],
|
||||||
|
"@controllers": ["src/controllers"],
|
||||||
|
"@models/*": ["src/models/*"],
|
||||||
|
"@models": ["src/models"],
|
||||||
|
"@controllerGraphQL/*": ["src/controllers/controllerGraphQL/*"],
|
||||||
|
"@controllerGraphQL": ["src/controllers/controllerGraphQL"],
|
||||||
|
"@GraphQL/*": ["src/GraphQL/*"],
|
||||||
|
"@GraphQL": ["src/GraphQL"],
|
||||||
|
"@config/*": ["config/*"],
|
||||||
|
"@config": ["config"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lib": ["es2018", "esnext.asynciterable"]
|
||||||
|
}
|
60
webpack.config.dev.ts
Normal file
60
webpack.config.dev.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
||||||
|
import ESLintPlugin from 'eslint-webpack-plugin';
|
||||||
|
import nodeExternals from 'webpack-node-externals';
|
||||||
|
import WebpackShellPluginNext from 'webpack-shell-plugin-next';
|
||||||
|
import { resolveTsAliases } from 'resolve-ts-aliases';
|
||||||
|
import { deFaultValues } from './config';
|
||||||
|
|
||||||
|
const ROOT_DIR = path.resolve(__dirname);
|
||||||
|
const resolvePath = (...args: string[]) => path.resolve(ROOT_DIR, ...args);
|
||||||
|
const BUILD_DIR = resolvePath('build');
|
||||||
|
const alias = resolveTsAliases(path.resolve('tsconfig.json'));
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
entry: './src/index.ts',
|
||||||
|
target: 'node',
|
||||||
|
watch: true,
|
||||||
|
externals: [nodeExternals()],
|
||||||
|
output: {
|
||||||
|
path: BUILD_DIR,
|
||||||
|
filename: 'index.js',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.ts', '.json', '.gql'],
|
||||||
|
alias,
|
||||||
|
},
|
||||||
|
mode: 'development',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(js|ts|mjs|gql)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ts)$/, loader: "ts-loader",
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new ESLintPlugin(),
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
...deFaultValues
|
||||||
|
}),
|
||||||
|
new WebpackShellPluginNext({
|
||||||
|
onBuildEnd: {
|
||||||
|
scripts: ['nodemon build/index.js'],
|
||||||
|
blocking: false,
|
||||||
|
parallel: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
58
webpack.config.ts
Normal file
58
webpack.config.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import webpack from 'webpack';
|
||||||
|
import TerserPlugin from 'terser-webpack-plugin';
|
||||||
|
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
||||||
|
import ESLintPlugin from 'eslint-webpack-plugin';
|
||||||
|
import nodeExternals from 'webpack-node-externals';
|
||||||
|
import { resolveTsAliases } from 'resolve-ts-aliases';
|
||||||
|
import { deFaultValues } from './config';
|
||||||
|
|
||||||
|
const ROOT_DIR = path.resolve(__dirname);
|
||||||
|
const resolvePath = (...args: string[]) => path.resolve(ROOT_DIR, ...args);
|
||||||
|
const BUILD_DIR = resolvePath('build');
|
||||||
|
const alias = resolveTsAliases(path.resolve('tsconfig.json'));
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
entry: './src/index.ts',
|
||||||
|
target: 'node',
|
||||||
|
externals: [nodeExternals()],
|
||||||
|
output: {
|
||||||
|
path: BUILD_DIR,
|
||||||
|
filename: 'index.js',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.ts', '.json', '.gql'],
|
||||||
|
alias,
|
||||||
|
},
|
||||||
|
mode: 'production',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(js|ts|mjs|gql)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(ts)$/, loader: "ts-loader",
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new ESLintPlugin(),
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
...deFaultValues
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
Reference in New Issue
Block a user