728x90
반응형

전 포스트에서 업로드 하는 것까지 구현해보았다.

이번 포스트에서는 클라이언트에서 파일을 조회하는 것을 구현해보겠다.

 

1. 먼저 리스트 항목 등을 클릭했을 경우의 이벤트 함수를 구현해준다. 파라미터는 원하는 값으로 하면 된다.

// 이미 등록된 파일이 있는지 확인
axios.get(`/api/file`, {
    params: {
        file_customer_code: customerKey
    }
}).then(({ data }) => {
    if (data.success) {
        // 파일이 존재할 경우 
    }
})

 

2. 백엔드에서 데이터베이스를 조회하고 있으면 결과값을 반환해주는 라우터를 작성한다.

router.get('/', function (req, res, next) {
    const query = req.query;
    const customer_code = query.file_customer_code

    try {
        File.findOne(
            {
                where: {
                    file_customer_code: customer_code
                }
            }).then((result) => {
                if (result) {
                    res.send({ success: true, result })
                }
                else {
                    res.send({ success: false })
                }
            })
    }
    catch (Err) {
        res.send({ success: false })
    }
})

 

3. 데이터가 존재할 경우 클라이언트의 file State 를 변경해주기 위해 fileReducer를 수정한다.

( 데이터베이스의 값을 불러와 다운로드 할 때 필요한 파라미터들을 클라이언트로 전송 )

function fileReducer(state: any, action: any) {

    switch (action.type) {
        case 'init':
            return initFileState;
        case 'listClick':
            var newState = state;
            Object.keys(newState).map((item: any, index: any) => {
            	if(item === 'file_location') { // 위치로 s3 url을 만들어 다운로드 기능을 구현한다.
                	newState[item] = 'https://  s3 url ' +action.value[item]
                }
                else {
                	newState[item] = action.value[item]
                }
            })
            return newState;
        default:
            return {
                ...state,
                [action.name]: action.value
            }
    }
}

 

4. fileDispatch를 적용해준다. (DB 내용이 state에 잘 들어오게끔)

// 이미 등록된 파일이 있는지 확인
axios.get(`/api/file`, {
    params: {
        file_customer_code: customerKey
    }
}).then(({ data }) => {
    if (data.success) {
        fileDispatch({ type: 'listClick', value: data.result })
    }
})

 

 

이 파일의 key 값인 s3에 저장된 경로가 클라이언트로 넘어오면 클라이언트쪽에서 파일 다운로드 하는 로직을 구현할 수 있다.

 

  1. 리스트 항목같은 데이터를 조회하고자 하는 버튼을 클릭했을 때 해당 데이터에 맞는 파일이 존재하는지 데이터베이스를 조회한다.
  2. 데이터베이스에 없으면 그냥 패스. 만약 있을 경우 데이터베이스에 저장된 내용 중 file_location( s3 file key )를 클라이언트로 가져온다.
  3. 클라이언트에서 s3에 접속하여 다운로드를 한다.
728x90
반응형
728x90
반응형

전 포스트에서 클라이언트에서 백엔드에 데이터를 전송하는 것 까지 구현해보았다.

 

이번 포스트에서는 백엔드에서 s3에 접근하여 파일을 업로드 하는 것까지 구현해보겠다.

 

1. .env 파일을 만들어준다. ( 전에 버킷 생성할 때 key ID 와 secret key 필요 )

S3_ACCESS_KEY='액세스 키'
S3_SECRET_ACCESS_KEY='비밀 액세스 키'
S3_REGION='리전'
S3_BUCKET_NAME='버킷이름'

 

2. 서버 파일에 필요한 것들을 선언하고 라우터를 만들어준다. ( 서버 파일에 body-parser 필요 )

file.js

const multer = require('multer');
const aws = require('aws-sdk');
require('dotenv').config();

const s3 = new aws.S3({
    accessKeyId: process.env.S3_ACCESS_KEY,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
    region: process.env.S3_REGION,
});

let upload = multer({
    limits: { fileSize: 5 * 1024 * 1024 } // 용량 제한
});


router.post("/upload", upload.array("file_object"), function (req, res, next) {
    try {

        var base64data = new Buffer(req.files[0].buffer, 'binary');

        const params = {
            Bucket: process.env.S3_BUCKET_NAME,
            Key: 'sample.png', // file name that you want to save in s3 bucket
            Body: base64data,
            ACL: "public-read",
            ContentType: "image/png"
        }

        s3.upload(params, (err, data) => {
            if (err) {
                console.log("err : ", err)
                res.send({ success: false });
            }
            else {
                console.log("data : ", data)
                res.send({ success: true, result: data })
            }
        });

    }
    catch (ERR) {
        console.log("ERR : ", ERR)
        res.send({ success: false })
    }

});



module.exports = router;

 

params의 key 부분에서 원하는 파일의 이름과 경로를 지정해줄 수 있다.

 

 

추가로 데이터베이스에 파일에 관한 내용을 추가하여 나중에 불러올 때 편하도록 설계하였다.

s3.upload(params, (err, data) => {
            if (err) {
                console.log("err : ", err)
                res.send({ success: false });
            }
            else {
                File.findOne(
                    {
                        where: {
                            file_customer_code: customer_code,
                        }
                    }).then((result) => {
                        if (result) {
                            File.update({
                                file_url: req.body.file_url,
                                file_location: key
                            }, {
                                where: {
                                    file_customer_code: customer_code,
                                }
                            })
                                .then((result) => {
                                    res.send({ success: true, result: data })
                                })

                        }
                        else {
                            File.create({
                                file_customer_code: customer_code,
                                file_url: req.body.file_url,
                                file_location: key
                            })
                                .then((result) => {
                                    res.send({ success: true, result: data })
                                })

                        }
                    })

            }
        });

 

나중에 파일이 존재하는지 확인할 때 데이터베이스 먼저 확인하고 파일에 접근할 수 있도록 했다.

 

  1. fileState, fileDispatch 설정
  2. input을 만들고 파일 선택 후 state에 담기도록 함.
  3. 담긴 데이터들을 formData로 만들어서 백엔드에 전송
  4. 백엔드에서 해당 파일을 s3에 저장함.
  5. 데이터베이스에 저장된 파일에 대한 내용 (경로 , 고유 키값 등)을 저장함

 

@@ 참고로 파일을 삭제하는 메소드는 deleteObject 이다.

ex)

s3.deleteObject({ Bucket: process.env.S3_BUCKET_NAME, Key: result.file_location }, (err, data) => {
    if (err) {
        console.log("err : ", err)
    }
})

 

728x90
반응형
728x90
반응형

1. aws에 접속하여 IAM 사용자를 생성한다

 

 

2. 권한으로 AmazonS3FullAccess를 할당해준다.

 

3. 해당 Access key ID, Secret access key를 알고 있어야 한다.

 

4. aws s3 화면에 접속해서 버킷을 만들어준다.

 

 

5. 퍼블릭 액세스 차단을 해제하고 만들어준다. (차후에 필요하면 수정 가능)

추가로 버킷정책과 CORS까지 설정해주자.

버킷정책

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicListGet",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:List*",
                "s3:Get*"
            ],
            "Resource": [
                "arn:aws:s3:::00nomubucket1",
                "arn:aws:s3:::00nomubucket1/*"
            ]
        }
    ]
}

 

CORS

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "DELETE",
            "GET"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

 

 

이제 버킷까지 만들었으니 node.js 로 파일 입출력 하는 로직을 구성해보자.

 

6. node.js 프로젝트에 필요한 패키지를 설치해준다.

npm i multer aws-sdk --save

 

7. 클라이언트에서 파일 업로드에 필요한 state를 만들어준다.

(file_location은 나중에 받아올 데이터입니다.)

    // ----- 파일 상태값 -----
    const initFileState : any = {
        file_object: "",
        file_url: "",
        file_location: ""
    }

    function fileReducer(state: any, action: any) {

        switch (action.type) {
            default:
                return {
                    ...state,
                    [action.name]: action.value
                }
        }
    }

    const [fileState, fileDispatch] = useReducer(fileReducer, initFileState)

 

8. 클라이언트에 file input을 만들어준다 ( Next.js Mui 사용했으나 일반 input 태그도 가능합니다 )

<WrapperDiv
    kindOf={`input`}
>
    <TextField
        label={`사업자등록증`}
        type='file'
        color='primary'
        size='small'
        InputLabelProps={{
            shrink: true,
        }}
        name={`file_object`}
        onChange={(e: any) => {
            let reader = new FileReader();
            let file = e.target.files[0];
            reader.onloadend = () => {
                fileDispatch({ name: e.target.name, value: file });
                fileDispatch({ name: 'file_url', value: reader.result });
            };
            reader.readAsDataURL(file);
        }}
    />
</WrapperDiv>
{fileState.file_url !== '' &&
    <WrapperDiv>
        <img style={{ width: "100%", height: "100%" }} src={fileState.file_url} />
    </WrapperDiv>
}

 

9. 대충 이런 모습을 볼 수 있다. ( 스타일은 신경쓰지 않아도 됩니다. 아래는 사진 미리보기  )

10. 백엔드에 데이터를 전송하는 로직을 구성해준다. ( 저장하기 버튼 클릭 시 )

const formData = new FormData();

formData.append("file_customer_code", infoState.customer_code); // 파일의 고유 코드 (임의로 지정 가능)
formData.append("file_object", fileState.file_object);
formData.append("file_url", fileState.file_url);

const config = {
    headers: {
        "content-type": "multipart/form-data",
    },
};

axios.post('/api/fileupload', formData, config)
    .then(({ data }) => {
        if (data.success) {
            alert('파일 업로드에 성공하였습니다.')
        }
        else {
            alert('파일 업로드에 실패하였습니다.')
        }
    })

 

클라이언트에서 파일을 업로드하고 백엔드로 데이터를 전송하였다. 다음 포스트에서는 백엔드에서의 파일 저장을 살펴보겠다.

 

728x90
반응형
728x90
반응형

1. 설치

$npm install --save multer

 

2. multer 가져오기 ( 조건문에 따라 파일의 로컬 저장 위치를 변환시킬 수 있음)

const fs = require("fs");
const bodyParser = require("body-parser");
const path = require("path");
router.use("/image_file", express.static("./upload")); // 사용자가 접근할 수 있게 공유
const multer = require("multer");

const uploadCustomer = multer({
    storage: multer.diskStorage({
        destination(req, file, cb) {
            if (!fs.existsSync("../client/public/upload")) {
                fs.mkdirSync("../client/public/upload");
            }

            if (!fs.existsSync("../client/public/upload/customer")) {
                fs.mkdirSync("../client/public/upload/customer");
            }

            if (!fs.existsSync("../client/public/upload/customer/" + file.originalname.split('-')[0])) { // 경로가 존재하지 않을 때
                fs.mkdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0]);

            } else {
                fs.rmdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0], { recursive: true, force: true }); // 기존폴더 및 하위 자료 삭제 
                fs.mkdirSync("../client/public/upload/customer/" + file.originalname.split('-')[0]); // 폴더 생성 
            }
            cb(null, "../client/public/upload/customer/" + file.originalname.split('-')[0]); // 이미지 생성

        },
        filename(req, file, cb) {

            const ext = path.extname(file.originalname);
            cb(null, file.originalname.split('-')[1]);
        },
    }),
    limits: { fileSize: 5 * 1024 * 1024 },
});

 

 

3. upload.single()

router.post('/', upload.single('image'), (req, res) => {
 
    console.log(req.file); 
  // 클라이언트에서 넘어온 파일에 대한 정보가 req.file에 FILE 객체로 저장되어 있습니다. 

})


출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]

 

4. upload.array()

router.post('/', upload.array('photos', 4), (req, res) => { 

console.log(req.files);
console.log(req.files[0]); // 파일의 인덱스로 접근

// 위 single에서와 다르게 req.file이 아닌 req.files에로 넘어옵니다.

})

출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]



// 미발송 근로계약서 이미지 및 서명, 데이터 요청
router.post("/sendLabor", uploadCustomer.array("image_file"), function (req, res, next) {
    const laborCode = req.body.laborCode;

    const state = JSON.parse(req.body.state);
    const 기타입력정보 = state.기타입력정보;
    const 근로자동의 = state.근로자동의;
    const 메인서명 = state.메인서명;

    console.log("req : ", req.files);



    const update_column = [
        "기타입력정보=JSON_OBJECT('근무장소', '" + 기타입력정보.근무장소 + "','담당업무', '" + 기타입력정보.담당업무 + "','주휴요일', '" + 기타입력정보.주휴요일 + "')",
        "근로자동의=JSON_OBJECT('동의여부_1', '" + 근로자동의.동의여부_1 + "','동의여부_2', '" + 근로자동의.동의여부_2 + "','동의여부_3', '" + 근로자동의.동의여부_3 + "','동의여부_4', '" + 근로자동의.동의여부_4 + "','동의여부_5', '" + 근로자동의.동의여부_5 + "','동의여부_6', '" + 근로자동의.동의여부_6 + "','동의여부_7', '" + 근로자동의.동의여부_7 + "','동의여부_8', '" + 근로자동의.동의여부_8 + "')",
        "메인서명=JSON_OBJECT('근로계약서_동의', '" + 메인서명.근로계약서_동의 + "','개인정보_동의', '" + 메인서명.개인정보_동의 + "','사용자_서명', '" + 메인서명.사용자_서명 + "', '근로자_서명', '" + 메인서명.근로자_서명 + "','사용자_서명날짜', '" + 메인서명.사용자_서명날짜 + "','근로자_서명날짜', '" + 메인서명.근로자_서명날짜 + "','사용자서명경로', '" + 'upload/customer/' + laborCode + '/' + "customer.png" + "','근로자서명경로', '" + 메인서명.근로자서명경로 + "')",
    ]

    console.log(update_column);

    const update_data_query = "UPDATE LABOR SET  " + update_column + " WHERE labor_code ='" + laborCode + "'";

    db.sequelize.query(
        update_data_query,
        {
            type: QueryTypes.UPDATE
        }
    ).then((result) => {

        return res.send({ success: true, result });

    })
})

 

5. upload.fields()

router.post('/',
	upload.fields([
    	{ name: 'mainImage', maxCount: 1 },
        { name: 'subImages', maxCount: 5 } ]),
        (req, res) => {
        	console.log(req.files);
            console.log(req.files['접근하려는 fieldname']);
})

출처: https://juhi.tistory.com/10 [주하히의 기술 블로그]
728x90
반응형
728x90
반응형

location.href 메소드를 이용해서 아주 간단하게 전화걸기 기능을 구현할 수 있다.

 

1. 전화걸기

function phoneCall(phoneNumber) {
  location.href = "tel:" + num;
}

phoneCall("01011112222");

 

2. 영상전화걸기 

function phoneCall(phoneNumber) {
  location.href = "tel-av:" + num;
}

phoneCall("01011112222");

 

3. 문자 보내기

function phoneCall(phoneNumber) {
  location.href = "sms:" + num;
}

phoneCall("01011112222");

 

4. 메일 보내기

function phoneCall(phoneNumber) {
  location.href = "mailto:" + num;
}

phoneCall("01011112222");

 

 

이것들은 a 태그 또는 버튼태그로도 사용할 수 있다.

<button onclick="document.location.href='tel:010-1234-5678'"> 

<a href="tel:010-1234-5678">010-1234-5678로 전화걸기</a> </div>
728x90
반응형
728x90
반응형

특정 사이트에서 로그인을 한 뒤 원하는 데이터를 얻어야 될 경우가 생겼다.

api 사이트를 이용할 경우 편하긴 하지만 트랜젝션이 발생 할 때마다의 비용이 발생하기 때문에 

node.js 에서 사용할 수 있는 puppeteer 를 경험해보기로 했다.

 

1. 필요한 npm 패키지를 설치한다.

$npm i puppeteer

 

2. 함수를 구현한다.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch(); // puppeteer 시작
  const page = await browser.newPage(); // 브라우저 실행
  await page.goto('https://www.google.com'); // 해당 페이지로 이동
  // other actions...
  await browser.close();  // 브라우저 종료
})();

 

이러한 함수를 만들어두고 백엔드에서 api 요청이 들어올 때 원하는 사이트에 접속 후 원하는 데이터를 가져올 수 있게끔 구현하면 된다.

 

예시)

var puppeteer = require('puppeteer');

(async () => {

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    const hisnet_id = '히즈넷 아이디';
    const hisnet_pw = '히즈넷 비밀번호';

    //페이지로 가라
    await page.goto('https://hisnet.handong.edu/login/login.php');

    //아이디랑 비밀번호 란에 값을 넣어라
    await page.evaluate((id, pw) => {
    document.querySelector('input[name="id"]').value = id;
    document.querySelector('input[name="password"]').value = pw;
    }, hisnet_id, hisnet_pw);

    //로그인 버튼을 클릭해라
    await page.click('input[src="/2012_images/intro/btn_login.gif"]');

    //로그인 화면이 전환될 때까지 .5초만 기다려라
    await page.waitFor(500);

    //로그인 실패시(화면 전환 실패시)
    if(page.url() === 'https://hisnet.handong.edu/login/_login.php'){
        student_id = 'nope';
        name = 'nope';
    }
    //로그인 성공시
    else{
        //학사 페이지로 가서
        await page.goto('https://hisnet.handong.edu/haksa/hakjuk/HHAK110M.php');
        //학번을 가져오고
        const element1 = await page.$('input[name="hakbun"]');
        student_id = await page.evaluate(element1 => element1.value, element1);
        //이름을 가져와라
        const element2 = await page.$('td[width="240"]');
        name = await page.evaluate(element2 => element2.textContent, element2);
    }
    //브라우저 꺼라
    await browser.close();        
})();

 

 

참조

https://zoomkoding.github.io/web/nodejs/histime/2019/01/24/crawler.html

 

줌코딩의 코딩일기

Zoom in Coding from the Basic.

zoomkoding.github.io

 

728x90
반응형
728x90
반응형

 

var originText = "This is example text.";
console.log("Original : ", originText);

// Base64 Encoding
base64EncodedText = Buffer.from(originText, "utf8").toString('base64');
console.log("Base64 Encoded Text : ", base64EncodedText);

// Base64 Decoding
base64DecodedText = Buffer.from(base64EncodedText, "base64").toString('utf8');
console.log("Base64 Decoded Text : ", base64DecodedText);

 

728x90
반응형
728x90
반응형
// 쿠키 생성
res.cookie('userid', userid); // 응답 객체에 쿠키를 생성한다.

// 쿠키삭제
res.clearCookie('userid'); // 응답 객체에 쿠키를 삭제한다.

// 쿠키 조회
req.cookies["userid"] // 요청 객체에서 쿠키를 조회한다



// 쿠키 생성할 때 옵션 주기
res.cookie('userid', userid, { maxAge: 60*60*1000, httpOnly: true, path:'/' });

//maxAge : 만료 시간을 밀리초 단위로 설정

//expires : 만료 날짜를 시간으로 설정

//path : cookie의 경로 default “/“

//domain : 도메인 네임

//secure : https에서만 cookie 사용

//httpOnly : 웹서버를 통해서만 cookie 접근
728x90
반응형
728x90
반응형

이 포스트는 전 포스트에서 이어집니다.

 

 

 

https://docs.nestjs.kr/middleware

 

네스트JS 한국어 매뉴얼 사이트

네스트JS 한국, 네스트JS Korea 한국어 매뉴얼

docs.nestjs.kr


 

Nest 미들웨어는 기본적으로 express 미들웨어와 동일하다. 

 

  • 모든 코드를 실행하십시오.
  • 요청 및 응답 객체를 변경합니다.
  • 요청-응답주기를 종료합니다.
  • 스택의 next 미들웨어 함수를 호출합니다.
  • 현재 미들웨어 함수가 요청-응답주기를 종료하지 않으면 next()를 호출하여 next 미들웨어 기능에 제어를 전달합니다. 그렇지 않으면 요청이 중단됩니다.

 


Request가 들어올 때 로그로 확인하기 위한 미들웨어를 작성해보자.

 

/src/common/middleware/logger.middleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}

 

 

app.module에서 전 포스트에서 작성한 UserModule을 import하고 다음과 같이 수정하자.

app.module.ts

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { LoggerMiddleware } from './common/middleware/logger.middleware';

@Module({
  imports: [UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('user');
  }
}

 

이제 Swagger에서 요청을 보내보자.

 

 

콘솔을 확인해보면 미들웨어에서 작성한 내용이 잘 뜨는 것을 확인할 수 있다.

 

미들웨어에서 한 번 들어온 데이터를 검증하고 next()로 넘길 수 있다. 

( 토큰이나 쿠키를 확인하는 것 등)

 

 

logger.middleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(req.body)
    next();
  }
}

 

swagger로 요청을 보내보면

 

 

잘 확인되는 것을 볼 수 있다.

 

참고로 이렇게 예외 상황도 만들 수 있다.

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST },
    'cats/(.*)',
  )
  .forRoutes(CatsController);
728x90
반응형

'Back-End > Nest.js' 카테고리의 다른 글

Nest.js | Swagger  (0) 2021.10.28
Nest.js | MongoDB | PATCH and DELETE  (0) 2021.10.06
Nest.js | MongoDB | Create  (0) 2021.10.06
Nest.js | MongoDB | Find  (0) 2021.10.06
Nest.js | MongoDB | Model,Schema,Controller  (0) 2021.10.06
728x90
반응형

swagger에 관한 자세한 사항은 아래 링크

https://docs.nestjs.com/openapi/introduction#bootstrap

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com


 

NestJS에서 swagger를 사용하면 아래와 같이 API를 테스트 할 수 있는 GUI 환경을 제공해준다.

 

 

 

일단 NestJS와 Swagger를 설치한다.

$ npm i -g @nestjs/cli
$ nest new teepo
$ npm install --save @nestjs/swagger swagger-ui-express

 

그다음 main.ts에 swagger를 추가해준다.

main.ts

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('User example')
    .setDescription('The user API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('swagger', app, document);

  await app.listen(3000);
}
bootstrap();

SwaggerModule.setup() 메소드 안에서 Swagger UI를 마운트하는 경로를 설정할 수 있다.

 

 

이제 npm run start:dev를 하고 화면(:3000/swagger)을 확인해보자.

$ npm run start:dev

 

 

정상적으로 출력되었다. 이제 api에 문서화를 진행해보자.

 

임의로 user라는 resource를 만들어보겠다.

$ nest g res user

 

 

간단하게 dto 파일을 작성한다.

create-user.dto.ts

export class CreateUserDto {
    name : string;
    age : number;
}

 

 

userController 파일을 다음과 같이 수정해보자.

user.controller.ts

import { Controller, Response, Get, Post, Body, Patch, Param, Delete, Res, HttpStatus } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { User } from './entities/user.entity';

@Controller('user')
@ApiTags('유저 API')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  @ApiOperation({summary : '유저 생성 API', description: '유저를 생성한다.' })
  @ApiCreatedResponse({description: '유저를 생성한다', type: User})
  async create(@Body() createUserDto: CreateUserDto) {
    const user: User = await this.userService.createUser(createUserDto);
    return user;
  }
}

 

userController에서 쓰일 userService를 정의한다.

user.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  createUser(createUserDto: CreateUserDto) {
    return {
      name : 'teepo',
      age : 28
    };
  }

}

 

 

이제 실행 화면을 보면

 

 

이렇게 우리가 추가한 '유저 API'가 잘 생성된 것을 볼 수 있다. 오른쪽 Try it out 버튼을 클릭하면 테스트 화면이 나온다.

일단 아무것도 입력하지 않고 바로 보내보자.

 

 

결과화면 : 

 

 

Service에 작성했던 정보가 잘 넘어온 것을 확인할 수 있다. 

 

dto와 클래스 또한 Swagger를 사용해 정의할 수 있다. 타입도 지정해주고 확인해주자.

class-validator와 class-transformer를 설치한다.

$ npm i class-validator class-transformer

 

 

dto 파일에 타입과 swagger 데코레이터를 추가한다.

create-user.dto

import {IsString, IsNumber} from 'class-validator'
import { ApiProperty } from '@nestjs/swagger';

export class CreateUserDto {
    @ApiProperty({ description: '이름' })
    @IsString()
    name : string;

    @ApiProperty({ description: '나이' })
    @IsNumber()
    age : number;
}

 

 

main.ts에 파이프를 설정해준다.

main.ts

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('User example')
    .setDescription('The user API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('swagger', app, document);

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist : true, 
      forbidNonWhitelisted : true,
      transform : true
    })
  )

  await app.listen(3000);
}
bootstrap();

 

Service부분에 내가 입력한 값 그대로를 반환하게끔 수정해준다.

user.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  createUser(createUserDto: CreateUserDto) {
    return createUserDto
  }

}

 

 

이제 다시 화면을 보면 DTO에 설정해두었던 타입들이 잘 들어가는 것을 확인할 수 있다.

 

 

 

맨 아래쪽에 스키마 부분도 설명이 잘 되어있다.

 

 

 

이번엔 타입과 다른 값을 보내보자. name에 string대신 number를 보내줄 것이다.

 

 

 

결과를 확인해보면

 

 

"name must be a string" 이라는 문구를 확인할 수 있다.

728x90
반응형

'Back-End > Nest.js' 카테고리의 다른 글

Nest.js | Middleware  (0) 2021.10.28
Nest.js | MongoDB | PATCH and DELETE  (0) 2021.10.06
Nest.js | MongoDB | Create  (0) 2021.10.06
Nest.js | MongoDB | Find  (0) 2021.10.06
Nest.js | MongoDB | Model,Schema,Controller  (0) 2021.10.06

+ Recent posts