Vue.js 3 & NodeJS/Vue 3

Vue CLI 액시오스 레스트 API 연동 3 - Vue CLI Axios, REST API Connect (POST Method, Promise, asyn, await)

carrotweb 2021. 8. 15. 20:13
728x90
반응형

Vue Axios로 REST API 연동하기

HTTP POST 메서드로 REST API 서버에서 새로운 게시판 내용 생성하기

1. C:\workspaces\nodeserver\testvue\src\views 폴더에서 BoardWrite.vue 파일을 생성합니다.

 

BoardWrite.vue 파일을 오픈하여 기본적인 Vue 컴포넌트로 코딩합니다.

<template>
	<div class="board">
		<h1>This is an board write page</h1>
	</div>
</template>

<script>
export default {
	name : 'BoardWrite'
};
</script>

<style scoped>
.board { width:800px; margin: 20px auto; }
</style>

 

2. C:\workspaces\nodeserver\testvue\src\router 폴더에서 index.js 파일을 오픈하여 const routes에 추가합니다.

{
  path: '/boardwrite',
  name: 'BoardWrite',
  component: () => import('../views/BoardWrite.vue')
}

 

3. BoardList.vue 파일을 오픈하여 새로운 게시판 내용을 입력할 수 있게 <router-link>를 추가하여 <table> 태그 위에 추가합니다.

<div class="buttons">
	<div class="right">
		<router-link to="/boardwrite" class="button blue"><span>쓰기</span></router-link>
	</div>
</div>

 

<style>에 쓰기 버튼 CSS를 추가합니다.

.buttons { position:relative; height:32px; margin-bottom:20px; }
.buttons > div.right { position:absolute; height:32px; right:0; }
.buttons > div > a.button { display:inline-block; min-width:95px; height:32px; line-height:32px; vertical-align:middle; font-size:13px; text-align:center; text-decoration:none; border-radius:20px; }
.buttons > div > .button.blue { color:#fff; border-color:#0099d2 !important; background:#0099d2 !important; }

 

브라우저를 새로고침(F5) 하면 쓰기 버튼이 화면에 나타납니다.

 

쓰기 버튼을 누르면 게시판 등록(BoardWrite.vue)으로 BoardWrite.vue 이동합니다.

 

4. BoardWrite.vue 파일을 오픈하여 게시판 내용 입력을 위해 <script>의 data에 객체를 추가합니다.

data : function() {
	return {
		writer : '',
		subject : '',
		content : ''
	};
}

writer는 작성자, subject는 제목, content는 내용입니다.

<template>에 게시판 내용 입력을 위해 <input> 태그와 <textarea> 태그를 추가하고 v-model로 data에 있는 객체와 연결합니다.

<table>
	<colgroup>
		<col style="width:18.5%">
		<col style="width:auto">
	</colgroup>
	<tbody>
		<tr>
			<th scope="row">작성자</th>
			<td><input type="text" placeholder="아이디를 입력하세요." ref="writerInput" v-model.trim="writer"></td>
		</tr>
		<tr>
			<th scope="row">제목</th>
			<td><input type="text" placeholder="제목을 입력하세요." ref="subjectInput" v-model.trim="subject"></td>
		</tr>
		<tr>
			<th scope="row">내용</th>
			<td><textarea rows="10" placeholder="내용을 입력하세요." ref="contentTextarea" v-model.trim="content"></textarea></td>
		</tr>
	</tbody>
</table>
<div class="buttons">
	<div class="right">
		<button class="button blue" @click="boardSaveClick">등록</button>
		<button class="button" @click="boardCancelClick">취소</button>
	</div>
</div>

v-model는 엘리먼트(<input>, <textarea>)와 데이터를 양방향으로 바인딩해 줍니다.

v-model.trim은 입력되는 데이터나 바인딩되는 데이터에 대해 trim 처리를 해 줍니다.

ref는 레퍼런스 ID로 태그를 DOM으로 접근할 수 있게 해 줍니다.

테이블에 스타일을 적용하기 위하여 <style>에 CSS를 추가합니다.

.board table { width:100%; border-top:2px solid #1d4281; border-spacing:0; }
.board table th { padding:8px 10px 10px 10px; vertical-align:middle; color:#1d4281; font-size:14px; border-bottom:1px solid #ccc; background:#f8f8f8; }
.board table td { padding:7px 20px 9px 20px; text-align:left; vertical-align:middle; border-bottom:1px solid #ccc; font-size:14px; line-heighT:150%; }
.board table td input, .board table td textarea { width:100%; color:#000 !important; } 
.buttons { position:relative; height:32px; margin-top:20px; }
.buttons > div.right { position:absolute; height:32px; right:0; }
.buttons > div > .button { overflow:visible; cursor:pointer; min-width:125px; height:32px; margin:0 2px; padding:0 15px; line-height:32px; font-size:14px; border:1px solid #dfdfdf; background:#fff; border-radius:10px; }
.buttons > div > .button.blue { color:#fff; border-color:#0099d2 !important; background:#0099d2 !important; }

 

저장 버튼을 클릭하면 REST API 서버로 새로운 게시판 내용을 등록하기 위해 axios의 post() 메서드로 호출하는 메서드를 <script>의 methods에 추가합니다. 리턴되는 응답 결과를 확인하기 위해 브라우저 콘솔로 출력합니다.

methods : {
	boardSaveClick() {
		let boardItem = { writer : this.writer, subject : this.subject, content : this.content };
		this.axios.post("http://localhost:9000/boards", boardItem).then((res)=>{
			console.log(res);
		}).catch((err) => {
			console.log(err);
		});
	}
}

입력된 데이터로 게시판 객체를 만들어 전달합니다.

 

취소 버튼을 클릭하면 게시판 리스트(BoardList.vue)로 이동하는 메서드를 <script>의 methods에 추가합니다.

boardCancelClick() {
	this.$router.go(-1);
}

 

동기 처리를 위한 async와 await 사용하기

 

Promise의 then() 대신 async와 await 키워드로 동기 처리할 수 있습니다.

methods : {
	async boardSaveClick() {
		let boardItem = { writer : this.writer, subject : this.subject, content : this.content };
		try {
			let res = await this.axios.post("http://localhost:9000/boards", boardItem);
			console.log(res);
		} catch(err) {
			console.log(err);
		}
	}
}

예외 처리는 try catch를 사용합니다.

 

Promise 이해하기

 

Promise(프로미스)는 JavaScript에서 비동기 처리에 사용되는 객체입니다.

axios는 Promise(프로미스) 기반 HTTP 비동기 통신 라이브러리입니다.

Promise는 resolve나 reject로 리턴합니다.

then() 메서드는 Promise가 리턴하는 resolve와 reject 두 개의 콜백 메서드를 전달받습니다.

첫 번째는 Promise가 이행(resolve)했을 때, 두 번째는 거부(reject)했을 때를 위한 콜백 메서드입니다.

const testPromise = new Promise((resolve) => {
  resolve("프로미스 이행");
});

또는

const testPromise = new Promise((reject) => {
  reject("프로미스 거부");
});

testPromise.then((resolve) => {
	alert(resolve);
},(reject) => {
	alert(reject);
}).catch((error) => {
	console.log(error);
});

두 번째 reject 콜백 메서드를 설정하지 않으면 catch() 메서드로 콜백 메서드가 호출됩니다.

그러나 두 번째 reject 콜백 메서드를 설정되어 있으면 catch() 메서드는 호출되지 않습니다.

위의 boardSaveClick() 메서드를 다음과 같이 변경하여 사용할 수 있습니다.

this.axios.post("http://localhost:9000/boards", boardItem).then((res)=>{
	console.log(res);
},(err)=>{
	console.log(err);
});

 

동기 처리 async와 await 이해하기

async 키워드는 function 앞에 위치합니다.

async 키워드를 붙이면 해당 메서드는 항상 Promise resolve로 반환하게 됩니다.

async testPromise() {
	return "프로미스 테스트";
}

testPromise().then((resolve)=>{alert(resolve);});

async 키워드가 붙은 function는 아래의 Promise를 통해 생성된 것과 같습니다.

const testPromise = new Promise((resolve) => {
	resolve("프로미스 테스트");
});

testPromise.then((resolve)=>{alert(resolve);});

 

await 키워드는 async function 안에서만 동작됩니다.

await 키워드를 만나면 Promise가 처리될 때까지 대기합니다.

async testPromise() {
	let result = await new Promise((resolve) => {
		resolve("프로미스 테스트");
	});
	alert(result);
}

 

 

이어서,

브라우저를 새로고침(F5) 하면 스타일이 적용된 게시판 내용 입력 테이블이 화면에 나타납니다.

 

5. 테스트를 작성자에는 "testid4"를 제목에는 "테스트 제목4"를 내용에는 "테스트 내용4"를 입력하고 등록 버튼을 누릅니다.

콘솔에 응답 객체를 보면 "data"에 "success"가 true인 것을 확인할 수 있습니다.

{
    "data": {
        "success": true
    },
    "status": 200,
    "statusText": "OK",
    "headers": {
        "content-length": "16",
        "content-type": "application/json; charset=utf-8"
    },
    "config": {
        "url": "http://localhost:9000/boards",
        "method": "post",
        "data": "{\"writer\":\"testid4\",\"subject\":\"테스트 제목4\",\"content\":\"테스트 내용4\"}",
        "headers": {
            "Accept": "application/json, text/plain, */*",
            "Content-Type": "application/json;charset=utf-8"
        },
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1
    },
    "request": {}
}

 

취소 버튼을 누르면 게시판 리스트(BoardList.vue)로 이동되고 새로 등록한 게시판 내용이 추가되어 나타납니다.

 

focus와 Validation 처리하기

6. BoardWrite.vue 파일을 오픈하여 BoardWrite 컴포넌트가 로딩이 완료된 후 작성자 입력란으로 포커스가 가도록 <script>의 mounted() 메서드에 추가합니다.

mounted() {
	this.$refs.writerInput.focus();
}

$refs를 사용하면 레퍼런스 ID로 접근할 수 있습니다.

입력란에 내용이 입려 되지 않으면 alert으로 알려주고 입력되지 않은 입력란으로 포커스가 가도록 boardSaveClick() 메서드에 추가합니다.

if (this.writer == "") {
	alert("작성자를 입력하세요.");
	this.$refs.writerInput.focus();
	return;
} else if (this.subject == "") {
	alert("제목을 입력하세요.");
	this.$refs.subjectInput.focus();
	return;
} else if (this.content == "") {
	alert("내용을 입력하세요.");
	this.$refs.contentTextarea.focus();
	return;
}

v-model.trim으로 데이터 양쪽에 있는 공백들은 제거되어 때문에 공백 검사가 가능합니다.

그리고 등록 버튼을 누를 때 confirm으로 확인한 후 처리하게 하고 등록 성공 여부를 alert으로 알려주고 등록이 성공되면 자동으로 게시판 리스트(BoardList.vue)로 이동되게 boardSaveClick() 메서드에 추가합니다.

var result = confirm("등록하시겠습니까?");
if (result) {
	let boardItem = { writer : this.writer, subject : this.subject, content : this.content };
	this.axios.post("http://localhost:9000/boards", boardItem).then((res)=>{
		console.log(res);
		if (res.data.success == true) {
			alert("등록되었습니다.");
			this.$router.push({name : 'BoardList'});
		} else {
			alert("등록되지 않았습니다.");
		}
	}).catch((err) => {
		console.log(err);
		alert("등록되지 않았습니다.");
	});
}
728x90
반응형