├── .env.example ├── .gitignore ├── README.md ├── package.json ├── source └── user │ ├── application │ └── userUseCase.ts │ ├── domain │ ├── user.entity.ts │ ├── user.repository.ts │ └── user.value.ts │ ├── infrastructure │ ├── controller │ │ └── user.ctrl.ts │ ├── db │ │ └── mongo.ts │ ├── model │ │ └── user.shchema.ts │ ├── repository │ │ ├── mock.repository.ts │ │ ├── mongo.repository.ts │ │ └── mysql.repository.ts │ └── route │ │ └── user.route.ts │ └── user.app.ts ├── src ├── app.ts ├── controller │ └── user.ctrl.ts ├── db │ └── mongo.ts ├── model │ └── user.schema.ts ├── route │ └── user.route.ts ├── services │ └── user.service.ts └── types │ └── user.type.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leifermendez/node-api-ddd-test/953545dbc0688105f827582cf54668e5c4c1f557/.env.example -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### MVC 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yt-node-api-ts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev":"nodemon ./src/app.ts", 8 | "dev:ddd":"nodemon ./source/user/user.app.ts", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.0.1", 17 | "express": "^4.18.1", 18 | "mongoose": "^6.5.0", 19 | "uuid": "^8.3.2", 20 | "inversify": "^6.0.1", 21 | "reflect-metadata": "^0.1.13" 22 | }, 23 | "devDependencies": { 24 | "@types/cors": "^2.8.12", 25 | "@types/dotenv": "^8.2.0", 26 | "@types/express": "^4.17.13", 27 | "@types/inversify": "^2.0.33", 28 | "@types/jest": "^28.1.6", 29 | "@types/mongoose": "^5.11.97", 30 | "@types/uuid": "^8.3.4", 31 | "jest": "^28.1.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /source/user/application/userUseCase.ts: -------------------------------------------------------------------------------- 1 | import { UserRepository } from "../domain/user.repository"; 2 | import { UserValue } from "../domain/user.value"; 3 | 4 | export class UserUseCase { 5 | constructor(private readonly userRepository: UserRepository) {} 6 | 7 | public registerUser = async ({ name, email, description }) => { 8 | const userValue = new UserValue({ name, email }); 9 | const userCreated = await this.userRepository.registerUser(userValue); 10 | return userCreated 11 | } 12 | 13 | public getDetailUSer = async (uuid:string) => { 14 | const user = await this.userRepository.findUserById(uuid) 15 | return user 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /source/user/domain/user.entity.ts: -------------------------------------------------------------------------------- 1 | export interface UserEntity { 2 | uuid:string; 3 | name:string; 4 | email:string; 5 | description:string 6 | } -------------------------------------------------------------------------------- /source/user/domain/user.repository.ts: -------------------------------------------------------------------------------- 1 | import { UserEntity } from "./user.entity"; 2 | 3 | export interface UserRepository { 4 | findUserById(uuid: string): Promise; 5 | registerUser(user:UserEntity): Promise; 6 | listUser(): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /source/user/domain/user.value.ts: -------------------------------------------------------------------------------- 1 | import { v4 as uuid } from "uuid"; 2 | import { UserEntity } from "./user.entity"; 3 | 4 | export class UserValue implements UserEntity { 5 | uuid: string; 6 | name: string; 7 | email: string; 8 | description: string; 9 | 10 | constructor({ name, email, description }: { name: string; email: string, description?:string }) { 11 | this.uuid = uuid(); 12 | this.name = name; 13 | this.email = email; 14 | this.description = description ?? "default"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /source/user/infrastructure/controller/user.ctrl.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { UserUseCase } from "../../application/userUseCase"; 3 | 4 | export class UserController { 5 | constructor(private userUseCase: UserUseCase) { 6 | this.insertCtrl = this.insertCtrl.bind(this) 7 | this.getCtrl = this.getCtrl.bind(this) 8 | } 9 | 10 | public async getCtrl({ query }: Request, res: Response) { 11 | const { uuid = '' } = query; 12 | const user = await this.userUseCase.getDetailUSer(`${uuid}`); 13 | res.send({ user }); 14 | } 15 | 16 | public async insertCtrl({ body }: Request, res: Response) { 17 | const user = await this.userUseCase.registerUser(body); 18 | res.send({ user }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /source/user/infrastructure/db/mongo.ts: -------------------------------------------------------------------------------- 1 | import { connect } from "mongoose"; 2 | 3 | const DB_URI = `${process.env.DB_URI}` 4 | 5 | const dbInit = async () => { 6 | await connect(DB_URI) 7 | console.log('Estamos ready?') 8 | } 9 | 10 | export default dbInit -------------------------------------------------------------------------------- /source/user/infrastructure/model/user.shchema.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from "mongoose"; 2 | 3 | const UserSchema = new Schema( 4 | { 5 | name: { 6 | type: String, 7 | }, 8 | email: { 9 | type: String, 10 | unique: true, 11 | }, 12 | uuid: { 13 | type: String, 14 | unique: true, 15 | }, 16 | description: { 17 | type: String, 18 | }, 19 | }, 20 | { 21 | timestamps: true, 22 | } 23 | ); 24 | 25 | const UserModel = model("users", UserSchema) 26 | 27 | export default UserModel 28 | -------------------------------------------------------------------------------- /source/user/infrastructure/repository/mock.repository.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Infra! Mongo 🙌 3 | */ 4 | import { UserEntity } from "../../domain/user.entity"; 5 | import { UserRepository } from "../../domain/user.repository"; 6 | /** 7 | * MOCK! 8 | */ 9 | 10 | const MOCK_USER = { 11 | name: "Leifer", 12 | description: "hola", 13 | uuid: "000-000", 14 | }; 15 | 16 | export class MockRepository implements UserRepository { 17 | async findUserById(uuid: string): Promise { 18 | const user = MOCK_USER 19 | return user; 20 | } 21 | async registerUser(userIn: UserEntity): Promise { 22 | const user = MOCK_USER 23 | return user; 24 | } 25 | async listUser(): Promise { 26 | const users = [MOCK_USER, MOCK_USER, MOCK_USER] 27 | return users; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /source/user/infrastructure/repository/mongo.repository.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Infra! Mongo 🙌 3 | */ 4 | import { UserEntity } from "../../domain/user.entity"; 5 | import { UserRepository } from "../../domain/user.repository"; 6 | import UserModel from "../model/user.shchema" 7 | /** 8 | * Mongo! 9 | */ 10 | export class MongoRepository implements UserRepository { 11 | async findUserById(uuid: string): Promise { 12 | const user = await UserModel.findOne({uuid}) 13 | return user 14 | } 15 | async registerUser(userIn: UserEntity): Promise { 16 | const user = await UserModel.create(userIn) 17 | return user 18 | } 19 | async listUser(): Promise { 20 | const user = await UserModel.find() 21 | return user 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /source/user/infrastructure/repository/mysql.repository.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Infra! Mongo 🙌 3 | */ 4 | import { UserEntity } from "../../domain/user.entity"; 5 | import { UserRepository } from "../../domain/user.repository"; 6 | import UserModel from "../model/user.shchema" 7 | /** 8 | * Mysql! 9 | */ 10 | export class MySqlRepository implements UserRepository { 11 | async findUserById(uuid: string): Promise { 12 | const user = await UserModel.findOne({uuid}) 13 | return user 14 | } 15 | async registerUser(userIn: UserEntity): Promise { 16 | const user = await UserModel.create(userIn) 17 | return user 18 | } 19 | async listUser(): Promise { 20 | const user = await UserModel.find() 21 | return user 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /source/user/infrastructure/route/user.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { UserUseCase } from "../../application/userUseCase"; 3 | import { UserController } from "../controller/user.ctrl"; 4 | import { MockRepository } from "../repository/mock.repository"; 5 | import { MongoRepository } from "../repository/mongo.repository"; 6 | 7 | const route = Router() 8 | /** 9 | * Iniciar Repository 10 | */ 11 | const userRepo = new MongoRepository() 12 | 13 | /** 14 | * Iniciamos casos de uso 15 | */ 16 | 17 | const userUseCase = new UserUseCase(userRepo) 18 | 19 | /** 20 | * Iniciar User Controller 21 | */ 22 | 23 | const userCtrl = new UserController(userUseCase) 24 | 25 | /** 26 | * 27 | */ 28 | 29 | route.post(`/user`, userCtrl.insertCtrl) 30 | route.get(`/user`, userCtrl.getCtrl) 31 | 32 | export default route -------------------------------------------------------------------------------- /source/user/user.app.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import express from "express"; 3 | import cors from "express"; 4 | import userRoute from "./infrastructure/route/user.route"; 5 | import dbInit from "./infrastructure/db/mongo"; 6 | 7 | const app = express(); 8 | app.use(cors()); 9 | app.use(express.json()); 10 | 11 | const port = process.env.PORT || 3001; 12 | 13 | app.use(userRoute); 14 | dbInit().then(); 15 | app.listen(port, () => console.log(`USER, Listo por el puerto ${port}`)); 16 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import express from "express"; 3 | import cors from "express"; 4 | import userRoute from "./route/user.route"; 5 | import dbInit from "./db/mongo"; 6 | 7 | const app = express(); 8 | app.use(cors()); 9 | app.use(express.json()); 10 | 11 | const port = process.env.PORT || 3001; 12 | 13 | app.use(userRoute); 14 | dbInit().then(); 15 | app.listen(port, () => console.log(`Listo por el puerto ${port}`)); 16 | -------------------------------------------------------------------------------- /src/controller/user.ctrl.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { registerUser, getDetailUser } from "../services/user.service"; 3 | 4 | const insertUser = async ({ body }: Request, res: Response) => { 5 | const user = await registerUser(body); 6 | res.send({ user }); 7 | }; 8 | 9 | const getUser = async ({ query }: Request, res: Response) => { 10 | const { email = '' } = query; 11 | const user = await getDetailUser(`${email}`); 12 | res.send({ user }); 13 | }; 14 | 15 | export { insertUser, getUser }; 16 | -------------------------------------------------------------------------------- /src/db/mongo.ts: -------------------------------------------------------------------------------- 1 | import { connect } from "mongoose"; 2 | 3 | const DB_URI = `${process.env.DB_URI}` 4 | 5 | const dbInit = async () => { 6 | await connect(DB_URI) 7 | console.log('Estamos ready?') 8 | } 9 | 10 | export default dbInit -------------------------------------------------------------------------------- /src/model/user.schema.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model } from "mongoose"; 2 | 3 | const UserSchema = new Schema( 4 | { 5 | name: { 6 | type: String, 7 | }, 8 | email: { 9 | type: String, 10 | unique: true, 11 | }, 12 | description: { 13 | type: String, 14 | }, 15 | }, 16 | { 17 | timestamps: true, 18 | } 19 | ); 20 | 21 | const UserModel = model("users", UserSchema) 22 | 23 | export default UserModel 24 | -------------------------------------------------------------------------------- /src/route/user.route.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import {insertUser, getUser} from "../controller/user.ctrl" 3 | 4 | const route = Router() 5 | /** 6 | * Aqui ruta POST HTTP 7 | */ 8 | route.post(`/user`, insertUser) 9 | /** 10 | * Ruta de GET detail 11 | */ 12 | route.get(`/user`, getUser) 13 | 14 | export default route -------------------------------------------------------------------------------- /src/services/user.service.ts: -------------------------------------------------------------------------------- 1 | import UserModel from "../model/user.schema"; 2 | import { UserInterface } from "../types/user.type"; 3 | 4 | /** 5 | * Registrar usuario 6 | * @param user 7 | * @returns 8 | */ 9 | const registerUser = async (user: UserInterface) => { 10 | const response = await UserModel.create(user); //TODO 🔴 11 | return response; 12 | }; 13 | 14 | /** 15 | * Consultar usuario 16 | * @param email 17 | * @returns 18 | */ 19 | const getDetailUser = async (email: string) => { 20 | const response = await UserModel.findOne({ email }); //TODO 🔴 21 | return response; 22 | }; 23 | 24 | export { registerUser, getDetailUser }; 25 | -------------------------------------------------------------------------------- /src/types/user.type.ts: -------------------------------------------------------------------------------- 1 | export interface UserInterface { 2 | name: string; 3 | email: string; 4 | description?: string; 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6"], 5 | "types": ["reflect-metadata"], 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "esModuleInterop": true 11 | }, 12 | "include": ["./src/*"] 13 | } --------------------------------------------------------------------------------