npm init -y
npm i express dotenv
npm i -D typescript
npm i -D @types/node @types/express @types/dotenv
npm i -D ts-node-dev
tsc --init
{
// include : 컴파일할 파일 경로를 설정합니다. [ src폴더 하위의 모든 .ts 확장자를 가진 파일 ]
"include": ["src/**/*.ts"],
"compilerOptions": {
"lib": ["ES2021","DOM"],
// esModuleInterop 속성이 위의 코드 처럼 true로 설정될 경우, ES6 모듈 사양을 준수하여 CommonJS 모듈을 가져올 수 있게 됩니다.
// e.g. typescript-test.ts => import express from "express"
"esModuleInterop": true,
// 타입스크립트가 모듈을 찾는방법을 지정
"moduleResolution":"NodeNext",
"target": "ES2021",
// rootDir : 컴파일될 타입스크립트 코드들의 위치를 명시합니다.
// "rootDir": "src",
// outDir : 컴파일 후 생성되는 js파일이 생성될 폴더명
"outDir": "dist",
// strictNullChecks
"strictNullChecks": true,
// 암시적 any 타입을 허용하지 않는다
"noImplicitAny": true
}
}
ts-node-dev : nodemon 같은 것, 파일이 변경되면 자동으로 변경된 ts파일을 실행시켜준다!
• --transpile-only: 타입스트립트의 빠른 트랜스파일 모듈 사용.
• src/index.ts: 엔트리파일 지정.
"dev": "ts-node-dev --transpile-only src/index.ts"
PORT=6600
// Required External Modules - 모듈
import dotenv from "dotenv";
import express, { Request, Response } from "express";
dotenv.config();
// App Variables - 앱 변수 선언
//포트가 없으면 프로그램 종료
if (!process.env.PORT) {
process.exit(1);
}
const PORT: number = parseInt(process.env.PORT as string, 10);
const app = express();
// App Configuration - JSON 형식으로 데이터를 전달받기위해서
app.use(express.json());
// Server Activation - 서버 활성화
app.get("/", (req: Request, res: Response) => {
res.send("Hi");
});
app.listen(PORT, () => {
console.log(`Listening on port http://localhost:${PORT}`);
});
기본이 되는 BaseItem 인터페이스와
BaseItem을 상속받을 Item 인터페이스를 만든다.Item ⇒ 특정한 값을 검색하거나 삭제할때 사용
BaseItem ⇒ 아이템을 수정, 등록 할때 사용
export interface BaseItem {
name: string;
price: number;
description: string;
image: string;
}
export interface Item extends BaseItem {
id: number;
}
아이템들을 합치기위한 items 인터페이스 생성
item.interface 로부터 Item을 가져와서 Items 인터페이스 생성 후 내보냄
import { Item } from "./item.interface";
export interface Items {
[key: number]: Item;
}
[key: number]: Item;
이러한 부분을 타입스크립트에서 인덱스 시그니처 라고 합니다.
=> 이런 형식
Items = {
1: { id: 1, name: "item1", price: 100, description: "This is item1", image: "item1.jpg" },
2: { id: 2, name: "item2", price: 200, description: "This is item2", image: "item2.jpg" },
3: { id: 3, name: "item3", price: 300, description: "This is item3", image: "item3.jpg" },
};
// 인터페이스 불러오기
import { BaseItem, Item } from "./item.interface";
import { Items } from "./items.interface";
// 메모리에 데이터 저장
let items: Items = {
1: {
id: 1,
name: "Burger",
price: 599,
description: "Tasty",
image: "https://cdn.auth0.com/blog/whatabyte/burger-sm.png",
},
2: {
id: 2,
name: "Pizza",
price: 299,
description: "Cheesy",
image: "https://cdn.auth0.com/blog/whatabyte/pizza-sm.png",
},
3: {
id: 3,
name: "Tea",
price: 199,
description: "Informative",
image: "https://cdn.auth0.com/blog/whatabyte/tea-sm.png",
},
};
// Service Methods - findAll, find, create, update, remove
export const findAll = async (): Promise<Item[]> => Object.values(items);
export const find = async (id: number): Promise<Item> => items[id];
export const create = async (newItem: BaseItem): Promise<Item> => {
const id = new Date().valueOf();
items[id] = {
id,
...newItem,
};
return items[id];
};
export const update = async (
id: number,
itemUpdate: BaseItem
): Promise<Item | null> => {
const item = await find(id);
if (!item) {
return null;
}
items[id] = { id, ...itemUpdate };
return items[id];
};
export const remove = async (id: number): Promise<null | void> => {
const item = await find(id);
if (!item) {
return null;
}
delete items[id];
};
Object.values(items)
: items의 value를 배열로 보여줌
[{id:~, name:~}, {id:~, name:~}, {id:~, name:~}] 이런식
valueOf() : 원시값 반환
# get all items - findAll
GET /api/menu/items
# get a single item using an id parameter - find
GET /api/menu/items/:id
# create an item
POST /api/menu/items
# update an item using an id parameter
PUT /api/menu/items/:id
# remove an item using an id parameter
DELETE /api/menu/items/:id
// 외부 모듈 및 인터페이스 불러오기
import express, { Request, Response } from "express";
import * as ItemService from "./items.service";
import { BaseItem, Item } from "./item.interface";
// 라우터 정의
export const itemsRouter = express.Router();
// 컨트롤러 구현
// GET items - findAll
itemsRouter.get("/", async (req: Request, res: Response) => {
try {
const items: Item[] = await ItemService.findAll();
res.status(200).send(items);
} catch (e) {
res.status(500).send(e.message);
}
});
// GET items/:id - find
itemsRouter.get("/:id", async (req: Request, res: Response) => {
try {
const id: number = parseInt(req.params.id, 10);
const item: Item = await ItemService.find(id);
if (item) {
return res.status(200).send(item);
}
res.status(404).send("item not found");
} catch (e) {
res.status(500).send(e.message);
}
});
// POST items - create
itemsRouter.post("/", async (req: Request, res: Response) => {
try {
const item: BaseItem = req.body;
const newItem: Item = await ItemService.create(item);
res.status(201).json(newItem);
} catch (e) {
res.status(500).send(e.message);
}
});
// PUT items/:id - update
itemsRouter.put("/:id", async (req: Request, res: Response) => {
try {
const id: number = parseInt(req.params.id, 10);
const itemUpdate: Item = req.body;
const existingItem: Item = await ItemService.find(id);
if (existingItem) {
const updatedItem = await ItemService.update(id, itemUpdate);
return res.status(200).json(updatedItem);
}
const newItem = await ItemService.create(itemUpdate);
res.status(201).json(newItem);
} catch (e) {
res.status(500).send(e.message);
}
});
// DELETE items/:id - remove
itemsRouter.delete("/:id", async (req: Request, res: Response) => {
try {
const id: number = parseInt(req.params.id, 10);
const result: void | null = await ItemService.remove(id);
if (result === null) {
return res.status(404).send("item not found");
}
res.sendStatus(204);
} catch (e) {
res.status(500).send(e.message);
}
});
import { itemsRouter } from "./items/items.router";
app.use("/api/menu/items", itemsRouter);