Skip to content

Commit dffe6c5

Browse files
committed
first commit
0 parents  commit dffe6c5

15 files changed

+587
-0
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build
2+
node_modules
3+
package-lock.json

Diff for: README.md

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Node.js Typescript Rest API with MySQL example
2+
Building Node.js Typescript Express and MySQL: CRUD Rest API example.
3+
4+
| Methods | Urls | Actions
5+
| -------- | ------- | ------- |
6+
| GET | api/tutorials | get all Tutorials
7+
| GET | api/tutorials/:id | get Tutorial by id
8+
| POST | api/tutorials | add new Tutorial
9+
| PUT | api/tutorials/:id | update Tutorial by id
10+
| DELETE | api/tutorials/:id | remove Tutorial by id
11+
12+
For more detail, please visit:
13+
> [Node.js Typescript with MySQL example](https://www.bezkoder.com/node-js-typescript-mysql/)
14+
15+
> [Express Typescript example](https://www.bezkoder.com/express-typescript-example/)
16+
17+
> [TypeScript ORM with MySQL example](https://www.bezkoder.com/typescript-orm-mysql/)
18+
19+
## Project setup
20+
```
21+
npm install
22+
```
23+
24+
### Run
25+
```
26+
npm run start
27+
```
28+
29+
Front-end that works well with this Back-end
30+
> [Axios Client](https://www.bezkoder.com/axios-request/)
31+
32+
> [Angular 8](https://www.bezkoder.com/angular-crud-app/) / [Angular 10](https://www.bezkoder.com/angular-10-crud-app/) / [Angular 11](https://www.bezkoder.com/angular-11-crud-app/) / [Angular 12](https://www.bezkoder.com/angular-12-crud-app/) / [Angular 13](https://www.bezkoder.com/angular-13-crud-example/) / [Angular 14](https://www.bezkoder.com/angular-14-crud-example/) / [Angular 15](https://www.bezkoder.com/angular-15-crud-example/) / [Angular 16 Client](https://www.bezkoder.com/angular-16-crud-example/)
33+
34+
> [Vue 2 Client](https://www.bezkoder.com/vue-typescript-crud/) / [Vue 3 Client](https://www.bezkoder.com/vue-3-typescript-axios/)
35+
36+
> [React Client](https://www.bezkoder.com/react-typescript-api-call/)
37+
38+
## More Practice
39+
40+
> [Node.js Express File Upload Rest API example](https://www.bezkoder.com/node-js-express-file-upload/)
41+
42+
> [Server side Pagination in Node.js with Sequelize and MySQL](https://www.bezkoder.com/node-js-sequelize-pagination-mysql/)
43+
44+
> [Deploying/Hosting Node.js app on Heroku with MySQL database](https://www.bezkoder.com/deploy-node-js-app-heroku-cleardb-mysql/)
45+
46+
Security:
47+
> [Node.js Express: JWT example | Token Based Authentication & Authorization](https://www.bezkoder.com/node-js-jwt-authentication-mysql/)
48+
49+
Associations:
50+
> [Sequelize Associations: One-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-one-to-many/)
51+
52+
> [Sequelize Associations: Many-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-many-to-many/)
53+
54+
Fullstack:
55+
> [Vue.js + Node.js + Express + MySQL example](https://www.bezkoder.com/vue-js-node-js-express-mysql-crud-example/)
56+
57+
> [Vue.js + Node.js + Express + MongoDB example](https://www.bezkoder.com/vue-node-express-mongodb-mevn-crud/)
58+
59+
> [Angular 8 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-node-express-mysql/)
60+
61+
> [Angular 10 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-10-node-js-express-mysql/)
62+
63+
> [Angular 11 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-11-node-js-express-mysql/)
64+
65+
> [Angular 12 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-12-node-js-express-mysql/)
66+
67+
> [Angular 13 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-13-node-js-express-mysql/)
68+
69+
> [Angular 14 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-14-node-js-express-mysql/)
70+
71+
> [Angular 15 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-15-node-js-express-mysql/)
72+
73+
> [Angular 16 + Node.js + Express + MySQL example](https://www.bezkoder.com/angular-16-node-js-express-mysql/)
74+
75+
> [React + Node.js + Express + MySQL example](https://www.bezkoder.com/react-node-express-mysql/)
76+
77+
Integration (run back-end & front-end on same server/port)
78+
> [Integrate React with Node.js Restful Services](https://www.bezkoder.com/integrate-react-express-same-server-port/)
79+
80+
> [Integrate Angular with Node.js Restful Services](https://www.bezkoder.com/integrate-angular-10-node-js/)
81+
82+
> [Integrate Vue with Node.js Restful Services](https://www.bezkoder.com/serve-vue-app-express/)

Diff for: package.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "node-js-typescript-mysql-rest-api",
3+
"version": "1.0.0",
4+
"description": "Rest API using Node.js, TypeScript, Express, Mysql",
5+
"main": "server.ts",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"build": "tsc",
9+
"dev": "node ./build/server.js",
10+
"start": "tsc && npm run dev"
11+
},
12+
"keywords": [
13+
"nodejs",
14+
"typescript",
15+
"express",
16+
"mysql",
17+
"mysql2",
18+
"restapi",
19+
"rest",
20+
"api",
21+
"crud"
22+
],
23+
"author": "bezkoder",
24+
"license": "ISC",
25+
"devDependencies": {
26+
"@types/cors": "^2.8.13",
27+
"@types/express": "^4.17.17",
28+
"@types/node": "^20.3.3",
29+
"ts-node": "^10.9.1",
30+
"typescript": "^5.1.6"
31+
},
32+
"dependencies": {
33+
"cors": "^2.8.5",
34+
"express": "^4.18.2",
35+
"mysql2": "^3.4.3"
36+
}
37+
}

Diff for: server.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import express, { Application } from "express";
2+
import Server from "./src/index";
3+
4+
const app: Application = express();
5+
const server: Server = new Server(app);
6+
const PORT: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080;
7+
8+
app
9+
.listen(PORT, "localhost", function () {
10+
console.log(`Server is running on port ${PORT}.`);
11+
})
12+
.on("error", (err: any) => {
13+
if (err.code === "EADDRINUSE") {
14+
console.log("Error: address already in use");
15+
} else {
16+
console.log(err);
17+
}
18+
});

Diff for: src/config/db.config.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
HOST: "localhost",
3+
USER: "root",
4+
PASSWORD: "123456",
5+
DB: "testdb"
6+
};

Diff for: src/controllers/home.controller.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Request, Response } from "express";
2+
3+
export function welcome(req: Request, res: Response): Response {
4+
return res.json({ message: "Welcome to bezkoder application." });
5+
}

Diff for: src/controllers/tutorial.controller.ts

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { Request, Response } from "express";
2+
import Tutorial from "../models/tutorial.model";
3+
import tutorialRepository from "../repositories/tutorial.repository";
4+
5+
export default class TutorialController {
6+
async create(req: Request, res: Response) {
7+
if (!req.body.title) {
8+
res.status(400).send({
9+
message: "Content can not be empty!"
10+
});
11+
return;
12+
}
13+
14+
try {
15+
const tutorial: Tutorial = req.body;
16+
const savedTutorial = await tutorialRepository.save(tutorial);
17+
18+
res.status(201).send(savedTutorial);
19+
} catch (err) {
20+
res.status(500).send({
21+
message: "Some error occurred while retrieving tutorials."
22+
});
23+
}
24+
}
25+
26+
async findAll(req: Request, res: Response) {
27+
const title = typeof req.query.title === "string" ? req.query.title : "";
28+
29+
try {
30+
const tutorials = await tutorialRepository.retrieveAll({ title: title });
31+
32+
res.status(200).send(tutorials);
33+
} catch (err) {
34+
res.status(500).send({
35+
message: "Some error occurred while retrieving tutorials."
36+
});
37+
}
38+
}
39+
40+
async findOne(req: Request, res: Response) {
41+
const id: number = parseInt(req.params.id);
42+
43+
try {
44+
const tutorial = await tutorialRepository.retrieveById(id);
45+
46+
if (tutorial) res.status(200).send(tutorial);
47+
else
48+
res.status(404).send({
49+
message: `Cannot find Tutorial with id=${id}.`
50+
});
51+
} catch (err) {
52+
res.status(500).send({
53+
message: `Error retrieving Tutorial with id=${id}.`
54+
});
55+
}
56+
}
57+
58+
async update(req: Request, res: Response) {
59+
let tutorial: Tutorial = req.body;
60+
tutorial.id = parseInt(req.params.id);
61+
62+
try {
63+
const num = await tutorialRepository.update(tutorial);
64+
65+
if (num == 1) {
66+
res.send({
67+
message: "Tutorial was updated successfully."
68+
});
69+
} else {
70+
res.send({
71+
message: `Cannot update Tutorial with id=${tutorial.id}. Maybe Tutorial was not found or req.body is empty!`
72+
});
73+
}
74+
} catch (err) {
75+
res.status(500).send({
76+
message: `Error updating Tutorial with id=${tutorial.id}.`
77+
});
78+
}
79+
}
80+
81+
async delete(req: Request, res: Response) {
82+
const id: number = parseInt(req.params.id);
83+
84+
try {
85+
const num = await tutorialRepository.delete(id);
86+
87+
if (num == 1) {
88+
res.send({
89+
message: "Tutorial was deleted successfully!"
90+
});
91+
} else {
92+
res.send({
93+
message: `Cannot delete Tutorial with id=${id}. Maybe Tutorial was not found!`,
94+
});
95+
}
96+
} catch (err) {
97+
res.status(500).send({
98+
message: `Could not delete Tutorial with id==${id}.`
99+
});
100+
}
101+
}
102+
103+
async deleteAll(req: Request, res: Response) {
104+
try {
105+
const num = await tutorialRepository.deleteAll();
106+
107+
res.send({ message: `${num} Tutorials were deleted successfully!` });
108+
} catch (err) {
109+
res.status(500).send({
110+
message: "Some error occurred while removing all tutorials."
111+
});
112+
}
113+
}
114+
115+
async findAllPublished(req: Request, res: Response) {
116+
try {
117+
const tutorials = await tutorialRepository.retrieveAll({ published: true });
118+
119+
res.status(200).send(tutorials);
120+
} catch (err) {
121+
res.status(500).send({
122+
message: "Some error occurred while retrieving tutorials."
123+
});
124+
}
125+
}
126+
}

Diff for: src/db/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import mysql from "mysql2";
2+
import dbConfig from "../config/db.config";
3+
4+
export default mysql.createConnection({
5+
host: dbConfig.HOST,
6+
user: dbConfig.USER,
7+
password: dbConfig.PASSWORD,
8+
database: dbConfig.DB
9+
});

Diff for: src/index.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import express, { Application } from "express";
2+
import cors, { CorsOptions } from "cors";
3+
import Routes from './routes';
4+
5+
export default class Server {
6+
constructor(app: Application) {
7+
this.config(app);
8+
new Routes(app);
9+
}
10+
11+
private config(app: Application): void {
12+
const corsOptions: CorsOptions = {
13+
origin: "http://localhost:8081"
14+
};
15+
16+
app.use(cors(corsOptions));
17+
app.use(express.json());
18+
app.use(express.urlencoded({ extended: true }));
19+
}
20+
}

Diff for: src/models/tutorial.model.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { RowDataPacket } from "mysql2"
2+
3+
export default interface Tutorial extends RowDataPacket {
4+
id?: number;
5+
title?: string;
6+
description?: string;
7+
published?: boolean;
8+
}

0 commit comments

Comments
 (0)