Skip to content

Commit

Permalink
Refactoring is on going
Browse files Browse the repository at this point in the history
  • Loading branch information
samchon committed Nov 13, 2023
1 parent d50fad8 commit 95f749b
Show file tree
Hide file tree
Showing 68 changed files with 2,144 additions and 2,323 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
bin/
lib/
node_modules/
src/migrations

*.DS_Store
package-lock.json
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
dist
bin
lib

node_modules
packages
src/api/functional
src/api/module.ts

README.md
tsconfig.json
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"editor.tabSize": 4,
"editor.tabSize": 2,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
Expand Down
50 changes: 22 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ After those replacements, you should specialize the [`src/Configuration.ts`](src
### 1.3. Directories
This template project has categorized directories like below.

As you can see from the below, all of the TypeScript source files are placed into the [src](src/) directory. When you build the TypeScript source files, compiled files would be placed into the `bin` directory following the [tsconfig.json](tsconfig.json) configuration. Otherwise you build client [SDK](#32-sdk) library or ORM models for the private npm module publishing, their compiled files would be placed into the [packages](packages) directory.
As you can see from the below, all of the TypeScript source files are placed into the [src](src/) directory. When you build the TypeScript source files, compiled files would be placed into the `bin` directory following the [tsconfig.json](tsconfig.json) configuration. Otherwise you build client [SDK](#32-software-development-kit) library or ORM models for the private npm module publishing, their compiled files would be placed into the [packages](packages) directory.

If you want to customize configurations of the [Github Action](#52-github-action) or debugging who can be started by the pressing the `F5` key, edit the [.github/workflows/build.yml](.github/workflows/build.yml) or [.vscode/launch.json](.vscode/launch.json) file. Default of their configurations are using the [3.3. Test Automation Program](#33-test-automation-program) without any special argument.

Expand All @@ -60,14 +60,14 @@ When you're planning to deploy the backend server, read the [INFRASTRUCTURE.md](
- [.github/workflows/build.yml](.github/workflows/build.yml): Configuration file of the [Github Action](#52-github-action)
- [.vscode/launch.json](.vscode/launch.json): Configuration for debugging
- [packages/](packages/): Packages to publish as private npm modules
- [packages/api/](packages/api): Client [SDK](#32-sdk) library for the client developers
- [packages/api/](packages/api): Client [SDK](#32-software-development-kit) library for the client developers
- [packages/models/](packages/models): ORM library for the DB developers
- [src/](src/): TypeScript Source directory
- [src/api/](src/api/): Client SDK that would be published to the `@ORGANIZATION/PROJECT-api`
- [**src/api/functional/**](src/api/functional/): API functions generated by the [`nestia`](https://github.com/samchon/nestia)
- [**src/api/structures/**](src/api/structures/): DTO structures
- [src/controllers/](src/controllers/): Controller classes of the Main Program
- [src/providers/](src/providers/): Conversion between ORM Models and DTO Structures
- [src/providers/](src/providers/): Service providers (bridge between DB and controllers)
- [src/executable/](src/executable/): Executable programs
- backend server itself
- update program for the user
Expand Down Expand Up @@ -181,37 +181,37 @@ However, [@samchon](https://github.com/samchon) does not recommend to writing co

Therefore, if you want to add a new feature in the API level, define the matched data entity in the [src/models](src/models) and [src/api/structures](src/api/structures) directories. After the data entity definition, declare function header in the matched API controller class in the [src/controllers](src/controllers). Note that, it's only the declaration, header only, not meaning to implement the function body.

After those declarations, build the client [SDK](#32-sdk) through the `npm run build:api` command and implement the [Test Automation Program](#33-test-automation-program) using the [SDK](#32-sdk) with use case scenarios. Development of the [Main Program](#34-main-program) should be started after those preparations are all being ready. Of course, the [Main Program](#34-main-program) can be verified with the pre-developed [Test Automation Program](#33-test-automation-program) in everytime.
After those declarations, build the client [SDK](#32-software-development-kit) through the `npm run build:api` command and implement the [Test Automation Program](#33-test-automation-program) using the [SDK](#32-software-development-kit) with use case scenarios. Development of the [Main Program](#34-main-program) should be started after those preparations are all being ready. Of course, the [Main Program](#34-main-program) can be verified with the pre-developed [Test Automation Program](#33-test-automation-program) in everytime.

- Declare data entity
- Declare API function header
- Build the client [SDK](32-sdk)
- Build the client [SDK](#32-software-development-kit)
- Implement the [Test Automation Program](#33-test-automation-program)
- Develop the [Main Program](#34-main-program)
- Validate the [Main Program](#34-main-program) through the [Test Automation Program](#33-test-automation-program)
- Deploy to the Dev and Real servers.

### 3.2. SDK
### 3.2. Software Development Kit
[`@ORGANIZATION/PROJECT`](https://github.com/samchon/backend) provides SDK (Software Development Kit) for convenience.

For the client developers who are connecting to this backend server, [`@ORGANIZATION/PROJECT`](https://github.com/samchon/backend) provides not API documents like the Swagger, but provides the API interaction library, one of the typical SDK (Software Development Kit) for the convenience.

With the SDK, client developers never need to re-define the duplicated API interfaces. Just utilize the provided interfaces and asynchronous functions defined in the SDK. It would be much convenient than any other Rest API solutions.
With the SDK, client developers never need to re-define the duplicated API interfaces, by reading Swagger Documents. Just utilize the provided interfaces and asynchronous functions defined in the SDK. It would be much convenient than any other Rest API solutions.

To build the SDK, just type the `npm run build:api` command. The SDK would be generated by [`nestia`](https://github.com/samchon/nestia), by analyzing source code of the [controller](src/controllers) classes in the compilation level, automatically. After the SDK building, you can publish the SDK through the `npm run package:api` command.
To build the SDK in local, just type the `npm run build:sdk` command. The SDK would be generated by [`nestia`](https://github.com/samchon/nestia), by analyzing source code of the [controller](src/controllers) classes in the compilation level, automatically. Otherwise you want to publish the SDK .ibrary, run the `npm run package:api` command instead.

```bash
# BUILD SDK AND PUBLISH IT
npm run build:api
npm run package:api
# BUILD SDK IN LOCAL
npm run build:sdk

# BUILDING SWAGGER IS ALSO POSSIBLE,
# BUT NOT RECOMMENDED
npm run build:swagger
# BUILD SDK AND PUBLISH IT TO THE NPM
npm run package:api
```

When the SDK has been published, client programmers can interact with this backend server very easily. Just let them to install the SDK and call the SDK functions with the `await` symbol like below.

![nestia-sdk-demo](https://user-images.githubusercontent.com/13158709/215004990-368c589d-7101-404e-b81b-fbc936382f05.gif)

```typescript
import api from "@samchon/bbs-api";

Expand Down Expand Up @@ -284,7 +284,7 @@ async function main(): Promise<void>
### 3.3. Test Automation Program
> TDD (Test Driven Development)
After the [Definition](#31-definition) and client [SDK](#32-sdk) generation, you've to design the use-case scenario and implement a test automation program who represents the use-case scenario and guarantees the [Main Program](#34-main-program).
After the [Definition](#31-definition) and client [SDK](#32-software-development-kit) generation, you've to design the use-case scenario and implement a test automation program who represents the use-case scenario and guarantees the [Main Program](#34-main-program).

To add a new test function in the Test Automation Program, create a new TS file under the [test/features](test/features) directory following the below category and implement the test scenario function with representative function name and `export` symbol. I think many all of the ordinary files wrote in the [test/features](test/features) directory would be good sample for you. Therefore, I will not describe how the make the test function detaily.

Expand All @@ -293,28 +293,22 @@ Anyway, you've to remind that, the Test Automation Program resets the DB schema
Also, the Test Automation Program runs all of the test functions placed into the [test/features](test/features) directory. However, those full testing may consume too much time. Therefore, if you want to reduce the testing time by specializing some test functions, use the `include` option like below.

- supported options
- `mode`: mode of the target server
- *local*
- *dev*
- ~~*real*~~
- `include`: test only restricted functions who is containing the special keyword.
- `exclude`: exclude some functions who is containing the special keyword.
- `skipReset`: do not reset the DB
- `reset`: do not reset the DB

```bash
# test in the dev server
npm run test -- --mode=dev

# test without db reset
npm run test -- --skipReset
npm run test -- --reset false

# test only restricted functions whose name contain the "something" keyword
# do not reset db
npm run test -- --include=something --skipReset
# include or exclude some features
npm run test -- --include something
npm run test -- --include cart order issue
npm run test -- --include cart order issue --exclude index deposit
```

### 3.4. Main Program
After [Definition](#31-definition), client [SDK](#32-sdk) building and [Test Automation Program](#33-test-automation-program) are all prepared, finally you can develop the Main Program. Also, when you complete the Main Program implementation, it would better to validate the implementation through the pre-built [SDK](#32-sdk) and [Test Automation Program](#33-test-automation-program).
After [Definition](#31-definition), client [SDK](#32-software-development-kit) building and [Test Automation Program](#33-test-automation-program) are all prepared, finally you can develop the Main Program. Also, when you complete the Main Program implementation, it would better to validate the implementation through the pre-built [SDK](#32-software-development-kit) and [Test Automation Program](#33-test-automation-program).

However, do not commit a mistake that writing source codes only in the [controller](src/controllers) classes. The API Controller must have a role that only intermediation. The main source code should be write down separately following the directory categorizing. For example, source code about DB I/O should be written into the [src/providers](src/providers) directory.

Expand Down
2 changes: 1 addition & 1 deletion nestia.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NestFactory } from "@nestjs/core";
import { MyModule } from "./src/MyModule";

export const NESTIA_CONFIG: INestiaConfig = {
input: async () => NestFactory.create(await MyModule()),
input: () => NestFactory.create(MyModule),
output: "src/api",
swagger: {
output: "packages/api/swagger.json",
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"homepage": "https://github.com/samchon/backend",
"devDependencies": {
"@nestia/e2e": "^0.3.7",
"@nestia/sdk": "^2.3.4",
"@nestia/sdk": "^2.3.9",
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"@types/cli": "^0.11.19",
"@types/inquirer": "^8.2.5",
Expand All @@ -77,7 +77,7 @@
"typescript-transform-paths": "^3.4.6"
},
"dependencies": {
"@nestia/core": "^2.3.4",
"@nestia/core": "^2.3.9",
"@prisma/client": "^5.3.1",
"dotenv": "^16.3.1",
"dotenv-expand": "^10.0.0",
Expand All @@ -87,7 +87,7 @@
"prisma": "^5.3.1",
"source-map-support": "^0.5.19",
"tstl": "^2.5.13",
"typia": "^5.2.4"
"typia": "^5.2.6"
},
"private": true
}
4 changes: 2 additions & 2 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
},
"homepage": "https://github.com/samchon/backend#readme",
"dependencies": {
"@nestia/fetcher": "^2.3.4",
"typia": "^5.2.4"
"@nestia/fetcher": "^2.3.9",
"typia": "^5.2.6"
},
"include": [
"lib",
Expand Down
2 changes: 1 addition & 1 deletion prettier.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
parser: "typescript",
printWidth: 80,
semi: true,
tabWidth: 4,
tabWidth: 2,
trailingComma: "all",
importOrder: [
"<THIRD_PARTY_MODULES>",
Expand Down
88 changes: 44 additions & 44 deletions src/MyBackend.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,55 @@
import { NestFactory } from "@nestjs/core";
import {
FastifyAdapter,
NestFastifyApplication,
FastifyAdapter,
NestFastifyApplication,
} from "@nestjs/platform-fastify";

import { MyConfiguration } from "./MyConfiguration";
import { MyGlobal } from "./MyGlobal";
import { MyModule } from "./MyModule";

export class MyBackend {
private application_?: NestFastifyApplication;

public async open(): Promise<void> {
//----
// OPEN THE BACKEND SERVER
//----
// MOUNT CONTROLLERS
this.application_ = await NestFactory.create(
await MyModule(),
new FastifyAdapter(),
{ logger: false },
);

// DO OPEN
this.application_.enableCors();
await this.application_.listen(MyConfiguration.API_PORT());

//----
// POST-PROCESSES
//----
// INFORM TO THE PM2
if (process.send) process.send("ready");

// WHEN KILL COMMAND COMES
process.on("SIGINT", async () => {
await this.close();
process.exit(0);
});
}

public async close(): Promise<void> {
if (this.application_ === undefined) return;

// DO CLOSE
await this.application_.close();
delete this.application_;

// EXIT FROM THE CRITICAL-SERVER
if ((await MyGlobal.critical.is_loaded()) === true) {
const critical = await MyGlobal.critical.get();
await critical.close();
}
private application_?: NestFastifyApplication;

public async open(): Promise<void> {
//----
// OPEN THE BACKEND SERVER
//----
// MOUNT CONTROLLERS
this.application_ = await NestFactory.create(
MyModule,
new FastifyAdapter(),
{ logger: false },
);

// DO OPEN
this.application_.enableCors();
await this.application_.listen(MyConfiguration.API_PORT());

//----
// POST-PROCESSES
//----
// INFORM TO THE PM2
if (process.send) process.send("ready");

// WHEN KILL COMMAND COMES
process.on("SIGINT", async () => {
await this.close();
process.exit(0);
});
}

public async close(): Promise<void> {
if (this.application_ === undefined) return;

// DO CLOSE
await this.application_.close();
delete this.application_;

// EXIT FROM THE CRITICAL-SERVER
if ((await MyGlobal.critical.is_loaded()) === true) {
const critical = await MyGlobal.critical.get();
await critical.close();
}
}
}
46 changes: 23 additions & 23 deletions src/MyConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,31 @@ const EXTENSION = __filename.substr(-2);
if (EXTENSION === "js") require("source-map-support").install();

export namespace MyConfiguration {
export const ROOT = (() => {
const splitted: string[] = __dirname.split(path.sep);
return splitted.at(-1) === "src" && splitted.at(-2) === "bin"
? path.resolve(__dirname + "/../..")
: path.resolve(__dirname + "/..");
})();
export const ROOT = (() => {
const splitted: string[] = __dirname.split(path.sep);
return splitted.at(-1) === "src" && splitted.at(-2) === "bin"
? path.resolve(__dirname + "/../..")
: path.resolve(__dirname + "/..");
})();

export const API_PORT = () => Number(MyGlobal.env.API_PORT);
export const UPDATOR_PORT = () => Number(MyGlobal.env.UPDATOR_PORT);
export const MASTER_IP = () =>
MyGlobal.mode === "local"
? "127.0.0.1"
: MyGlobal.mode === "dev"
? "your-dev-server-ip"
: "your-real-server-master-ip";
export const SYSTEM_PASSWORD = () => MyGlobal.env.SYSTEM_PASSWORD;
export const API_PORT = () => Number(MyGlobal.env.API_PORT);
export const UPDATOR_PORT = () => Number(MyGlobal.env.UPDATOR_PORT);
export const MASTER_IP = () =>
MyGlobal.mode === "local"
? "127.0.0.1"
: MyGlobal.mode === "dev"
? "your-dev-server-ip"
: "your-real-server-master-ip";
export const SYSTEM_PASSWORD = () => MyGlobal.env.SYSTEM_PASSWORD;
}

ExceptionManager.insert(PrismaClientKnownRequestError, (exp) => {
switch (exp.code) {
case "P2025":
return ErrorProvider.notFound(exp.message);
case "P2002": // UNIQUE CONSTRAINT
return ErrorProvider.conflict(exp.message);
default:
return ErrorProvider.internal(exp.message);
}
switch (exp.code) {
case "P2025":
return ErrorProvider.notFound(exp.message);
case "P2002": // UNIQUE CONSTRAINT
return ErrorProvider.conflict(exp.message);
default:
return ErrorProvider.internal(exp.message);
}
});
Loading

0 comments on commit 95f749b

Please sign in to comment.