Add API monorepo
Change-Id: I39aa1707744bb86c4bc9113157bbf815bb3fe33a
This commit is contained in:
parent
b87cff043a
commit
5246efb027
56 changed files with 251 additions and 22 deletions
|
@ -6,7 +6,7 @@ Seedling is a project generator for @prokyon libraries.
|
|||
|
||||
1. Create file `.npmrc`
|
||||
2. Paste content to file `@toolkit:registry=https://npm.romanjaros.dev`
|
||||
3. Use `pnpm dlx @toolkit/seedling --name hello-world --port 90 --monorepo T ./app`
|
||||
3. Use `pnpm dlx @toolkit/seedling --name hello-world --port 90 ./app`
|
||||
- instead of `./app` use can use curent folder, `.` or `./`
|
||||
4. Use `pnpm dev` to start
|
||||
|
||||
|
@ -20,10 +20,6 @@ Seedling is a project generator for @prokyon libraries.
|
|||
- define port for application when is deployed
|
||||
- number
|
||||
|
||||
### monorepo
|
||||
- define if generated structure will be for monorepo
|
||||
- value `T` = `true` or `F` = `false`
|
||||
|
||||
### context
|
||||
- last parameter is folder as destination of generated code
|
||||
- string
|
25
create.js
25
create.js
|
@ -6,7 +6,6 @@ const argv = require('minimist')(process.argv.slice(2));
|
|||
// questions
|
||||
const appName = argv.name ?? 'app';
|
||||
const appPort = argv.port ?? '0';
|
||||
const isMonorepo = argv.monorepo === 'T';
|
||||
|
||||
const defaultContextDir = './';
|
||||
const rootDir = __dirname;
|
||||
|
@ -14,18 +13,19 @@ const contextDir = `${argv._[0]}/` ?? defaultContextDir;
|
|||
|
||||
// create app folder
|
||||
const appsDir = `${contextDir}/apps`;
|
||||
const appDir = isMonorepo ? `${contextDir}/apps/${appName}-fe` : `${contextDir}/`;
|
||||
const uiDir = `${contextDir}/apps/${appName}-ui`;
|
||||
const apiDir = `${contextDir}/apps/${appName}-api`;
|
||||
|
||||
// prepare structure folders
|
||||
if (!fs.existsSync(appDir)) {
|
||||
if (!fs.existsSync(uiDir)) {
|
||||
if (!fs.existsSync(contextDir)) {
|
||||
fs.mkdirSync(contextDir);
|
||||
}
|
||||
if (isMonorepo) {
|
||||
fs.mkdirSync(appsDir);
|
||||
}
|
||||
fs.mkdirSync(appDir);
|
||||
fs.mkdirSync(`${appDir}/src`);
|
||||
fs.mkdirSync(appsDir);
|
||||
fs.mkdirSync(uiDir);
|
||||
fs.mkdirSync(`${uiDir}/src`);
|
||||
fs.mkdirSync(apiDir);
|
||||
fs.mkdirSync(`${apiDir}/src`);
|
||||
}
|
||||
|
||||
// copy folder content
|
||||
|
@ -34,7 +34,11 @@ try {
|
|||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
fs.cpSync(`${rootDir}/source/app/`, appDir, {
|
||||
fs.cpSync(`${rootDir}/source/ui/`, uiDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
fs.cpSync(`${rootDir}/source/api/`, apiDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
|
@ -50,7 +54,8 @@ fs.renameSync(`${contextDir}/npmrc`, `${contextDir}/.npmrc`);
|
|||
fs.renameSync(`${contextDir}/gitignore`, `${contextDir}/.gitignore`);
|
||||
fs.renameSync(`${contextDir}/prettierrc`, `${contextDir}/.prettierrc`);
|
||||
fs.renameSync(`${contextDir}/.tsconfig.json`, `${contextDir}/tsconfig.json`);
|
||||
fs.renameSync(`${appDir}/.tsconfig.json`, `${appDir}/tsconfig.json`);
|
||||
fs.renameSync(`${uiDir}/.tsconfig.json`, `${uiDir}/tsconfig.json`);
|
||||
fs.renameSync(`${apiDir}/.tsconfig.json`, `${apiDir}/tsconfig.json`);
|
||||
|
||||
// replace in files
|
||||
replaceInFiles.sync({
|
||||
|
|
42
source/api/.tsconfig.json
Normal file
42
source/api/.tsconfig.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"strict": false,
|
||||
"outDir": "dist",
|
||||
"rootDir": "./",
|
||||
"baseUrl": "./",
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
"config/*": [
|
||||
"./src/config/*"
|
||||
],
|
||||
"database/*": [
|
||||
"./src/database/*"
|
||||
],
|
||||
"model/*": [
|
||||
"./src/model/*"
|
||||
],
|
||||
"controllers/*": [
|
||||
"./src/controllers/*"
|
||||
],
|
||||
"utils/*": [
|
||||
"./src/utils/*"
|
||||
],
|
||||
"types/*": [
|
||||
"./src/types/*"
|
||||
],
|
||||
"plugins/*": [
|
||||
"./src/plugins/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./**/*.ts",
|
||||
"./**/*.tsx",
|
||||
"./src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
5
source/api/nodemon.json
Normal file
5
source/api/nodemon.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"ignore": [
|
||||
"README"
|
||||
]
|
||||
}
|
38
source/api/package.json
Normal file
38
source/api/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "$(appName)-api",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"author": "Roman Jaroš <hello@romanjaros.dev>",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"dev": "nodemon --exec ts-node -r tsconfig-paths/register src/index.ts",
|
||||
"build": "rimraf dist && tsc -p tsconfig.json && tsc-alias -p tsconfig.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/hapi": "18.0.10",
|
||||
"@types/hapi__nes": "11.0.7",
|
||||
"@types/ramda": "0.28.0",
|
||||
"@types/validator": "13.11.1",
|
||||
"copyfiles": "2.4.1",
|
||||
"nodemon": "3.0.1",
|
||||
"rimraf": "5.0.1",
|
||||
"ts-node": "10.9.1",
|
||||
"tsc-alias": "1.8.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hapi/boom": "10.0.1",
|
||||
"@hapi/nes": "13.0.1",
|
||||
"@hapi/hapi": "21.3.2",
|
||||
"@hapi/inert": "7.1.0",
|
||||
"@hapi/vision": "7.0.3",
|
||||
"@prokyon/utils": "1.0.31",
|
||||
"hapi-swagger": "17.1.0",
|
||||
"joi": "17.10.1",
|
||||
"typeorm": "0.3.17",
|
||||
"sqlite3": "5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ramda": "0.28.0",
|
||||
"typescript": "5.2.2"
|
||||
}
|
||||
}
|
4
source/api/src/config/server.json
Normal file
4
source/api/src/config/server.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"host": "localhost",
|
||||
"port": 3000
|
||||
}
|
18
source/api/src/controllers/hey.ts
Normal file
18
source/api/src/controllers/hey.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
// @ts-nocheck
|
||||
import { Request, ResponseToolkit, ServerRoute } from '@hapi/hapi';
|
||||
|
||||
const routers: ServerRoute[] = [
|
||||
{
|
||||
path: '/hey',
|
||||
method: 'GET',
|
||||
options: {
|
||||
description: 'Are u alive?',
|
||||
tags: ['api'],
|
||||
},
|
||||
handler: (request: Request, h: ResponseToolkit) => {
|
||||
return h.response('I am here !').type('html/text').code(200);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default routers;
|
13
source/api/src/database/db.ts
Normal file
13
source/api/src/database/db.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
// @ts-nocheck
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
export const dbConnect = async () => {
|
||||
const AppDataSource = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: `database.sqlite`,
|
||||
entities: [],
|
||||
synchronize: true,
|
||||
logging: ['query'],
|
||||
});
|
||||
return await AppDataSource.initialize();
|
||||
};
|
51
source/api/src/index.ts
Normal file
51
source/api/src/index.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
// @ts-nocheck
|
||||
import hapi from '@hapi/hapi';
|
||||
import nes from '@hapi/nes';
|
||||
|
||||
import { host, port } from 'config/server.json';
|
||||
import { dbConnect } from 'database/db';
|
||||
|
||||
import swagger from 'plugins/swagger';
|
||||
|
||||
const server: hapi.Server = new hapi.Server({
|
||||
host: host,
|
||||
port: port,
|
||||
debug: {
|
||||
log: ['error'],
|
||||
request: ['error'],
|
||||
},
|
||||
routes: {
|
||||
validate: {
|
||||
failAction: (request, h, err) => {
|
||||
throw err;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const start = async (): Promise<void> => {
|
||||
await swagger(server);
|
||||
await server.register(nes);
|
||||
|
||||
// v1 endpoints
|
||||
await server.register(require('./plugins/controllers'), { routes: { prefix: '/api/v1' } });
|
||||
|
||||
// connect to database
|
||||
await dbConnect()
|
||||
.then(() => {
|
||||
console.log('Data Source has been initialized!');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error during Data Source initialization', err);
|
||||
});
|
||||
|
||||
await server.start();
|
||||
console.info(`Server running: ${server.info.uri}`);
|
||||
};
|
||||
|
||||
process.on('unhandledRejection', (err) => {
|
||||
console.info(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
start();
|
11
source/api/src/plugins/controllers.ts
Normal file
11
source/api/src/plugins/controllers.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// @ts-nocheck
|
||||
import { Server } from '@hapi/hapi';
|
||||
|
||||
import hey from 'controllers/hey';
|
||||
|
||||
export const plugin = {
|
||||
name: 'Controllers',
|
||||
register: async (server: Server) => {
|
||||
server.route(hey);
|
||||
},
|
||||
};
|
26
source/api/src/plugins/swagger.ts
Normal file
26
source/api/src/plugins/swagger.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
// @ts-nocheck
|
||||
import { Server } from '@hapi/hapi';
|
||||
|
||||
const version = require('../../package.json').version;
|
||||
|
||||
export default async (server: Server) => {
|
||||
return server.register([
|
||||
require('@hapi/inert'),
|
||||
require('@hapi/vision'),
|
||||
{
|
||||
plugin: require('hapi-swagger'),
|
||||
options: {
|
||||
info: {
|
||||
title: 'Many API',
|
||||
version,
|
||||
},
|
||||
swaggerUI: true,
|
||||
documentationPage: true,
|
||||
documentationPath: '/swagger',
|
||||
pathPrefixSize: 3,
|
||||
basePath: '/api/v1',
|
||||
reuseDefinitions: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
};
|
23
source/api/src/utils/params.ts
Normal file
23
source/api/src/utils/params.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// @ts-nocheck
|
||||
import { Request } from '@hapi/hapi';
|
||||
|
||||
export type RequestParams = Record<string, string | null>;
|
||||
|
||||
export const getParam =
|
||||
(request: Request) =>
|
||||
(name: string): string | null => {
|
||||
const params: RequestParams = {
|
||||
...(request.params as object),
|
||||
...(request.payload as object),
|
||||
...(request.query as object),
|
||||
};
|
||||
const filteredParams: RequestParams = {} as any;
|
||||
Object.keys(params).map((key) => {
|
||||
const value = params[key];
|
||||
if (['undefined', 'null'].includes(value as string)) {
|
||||
filteredParams[key] = null;
|
||||
}
|
||||
filteredParams[key] = value;
|
||||
});
|
||||
return filteredParams[name] ?? null;
|
||||
};
|
|
@ -16,10 +16,6 @@
|
|||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"jsx": "react",
|
||||
"types": [
|
||||
"jest",
|
||||
],
|
||||
},
|
||||
"exclude": [
|
||||
"./node_modules",
|
||||
|
|
|
@ -36,9 +36,10 @@
|
|||
]
|
||||
},
|
||||
"types": [
|
||||
"./src/types/yup",
|
||||
"node"
|
||||
],
|
||||
"node",
|
||||
"jest",
|
||||
"./src/types/yup"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
0
source/ui/src/types/global.ts
Normal file
0
source/ui/src/types/global.ts
Normal file
Loading…
Add table
Reference in a new issue