컴포넌트 교환

페이지 구성 시, 공통적으로 사용되는 컴포넌트를 부모가 관리하고 상호 간 교류하는 방법을 기술.

순서: 컴포넌트 파일 생성→ 부모 컴포넌트에서 등록→ 실행

  • src/components에 컴포넌트 파일 생성
  • src/view폴더에 부모 컴포넌트 파일 생성
    • example
      • components 디렉토리에 "PageTitle" 이름의 파일 생성
      • 태그 생성, import, 컴포넌트 등록
1
2
3
4
5
6
7
8
9
10
11
<template>
    <div>
        <PageTitle />  //html에서는 import한 컴포넌트 이름을 이용해 태그 생성
    </div>
</template>
<script>
import PageTitle from '../components/PageTitle'// import
export default {
    components:{PageTitle}  //현재 파일에서 사용할 컴포넌트 등록
}
</script>
cs
  1. 부모→ 자식 컴포넌트
    • 데이터 전달 format
1
2
3
4
5
6
7
8
9
10
11
<template>
<h2> {{title}}</h2> //아래에서 전달받은 값 출력
</template>
export default {
    props:{
        title:{
            type:String,
            default:"페이지 제목"
        }
    }
}
cs
  • props인자를 사용하여 부모로부터 전달받을 데이터를 받음
  • default는 부모로부터 데이터를 전달받지 않았을 때의 기본 값
1
2
3
4
5
6
7
8
9
10
11
12
<template>
    <div>
        <PageTitle title="데이터 전달"/>
    </div>
</template>
<script>
import PageTitle from '../components/PageTitle';
export default {
    components:{PageTitle}
     
}
</script>
cs

또한 부모 파일의 prop에 v-bind를 이용하여 동적인 값을 전달할 수 있음.

목록: 숫자형, 논리형, 배열, 객체, 속성 등

2. 부모→ 자식 컴포넌트(이벤트 호출)

  • format
1
2
3
4
5
6
7
8
9
10
11
12
<template>
    <button type="button" @click="childFunc" ref="btn">click</button>
</template>
<script>
export default {
    methods:{
        childFunc(){
            console.log('이벤트 작성문');
        }
    }
}
</script>
cs
1
2
3
4
5
6
7
8
9
10
11
12
<template>
    <childComponent @send-message="sendMessage" ref="childComponent" />
</template>
<script>
import childComponent from './childComponent';
export default {
 components: {childComponent},
 mounted() {
    this.$refs.childComponent.$refs.btn.click();
 }
}
</script>
cs
  • 자식 컴포넌트 객체에 "ref"속성으로 접근할 수 있음. (html의 id와 유사)

3. 부모→ 자식 컴포넌트(데이터 변경)

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<h1>{{msg}}</h1>
</template>
<script>
export default {
 data() {
   return {
     msg: ''
   };
 }
}
</script>
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
 <childComponent @send-message="sendMessage" ref="childComponent" />
 <button type="button" @click="changeChildData">Change Child Data</button>
</template>
<script>
import childComponent from './childComponent';
export default {
 components: {childComponent},
 methods: {
   changeChildData() {
     this.$refs.childComponent.msg = "부모 컴포넌트가 변경한 데이터";
   }
 }
}
</script>
cs

2. 자식 컴포넌트→ 부모

  • 이벤트/데이터 전달
  • format
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div></div>
</template>
<script>
export default {
 data() {
   return {
     msg: '자식 컴포넌트로부터 보내는 메시지'
   };
 },
 mounted() {
   this.$emit('send-message'this.msg)
 }
}
</script>
cs
  • 자식이 부모로 데이터를 전달할 때는 emit인자를 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
 <childComponent @send-message="sendMessage" />
</template>
<script>
import childComponent from './childComponent';
export default {
 components: {childComponent},
 methods: {
   sendMessage(data) {
     console.log(data);
   }
 }
}
</script>
cs

Provide/Inject

위처럼 계층 구조가 복잡한 경우 부모↔ 자식 간 컴포넌트 교환이 어렵기 때문에 provide/inject옵션을 지원하여 이벤트/데이터 전달을 한번에 처리할 수 있음.

  • 부모가 값을 전달할 때 provide함수 이용
  • 자식이 값을 전달 받을 때는 inject인자 사용
  • 사용이 권장되진 않음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <ProvideInjectChild />
  </div>
</template>
<script>
import ProvideInjectChild from './ProvideInjectChild';
export default {
  components: {ProvideInjectChild},
  data() {
    return {
      items: ['A','B']
    };
  },
  provide() {
    return {
      itemLength: this.items.length
    };
  }
}
</script>
cs

 

  • Provide 옵션 사용 말고는 일반적인 컴포넌트 교환 방식과 동일.
  • 위 example에서는 자식 컴포넌트로 전달하려는 데이터를 provide에 정의.(배열 길이)
1
2
3
4
5
6
7
8
9
10
11
<template>
<div></div>
</template>
<script>
export default {
  inject: ['itemLength'],
  mounted() {
    console.log(this.itemLength);
  }
}
</script>
cs
  • 부모 컴포넌트로부터 전달받을 데이터와 동일한 이름으로 inject에 '문자열 배열'로 정의.

Vuex

Vue js 애플리케이션을 위한 상태관리 패턴+라이브러리로, 데이터를 store에 저장하고 프로젝트 전체에서 사용하는 등, 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 함.

즉, 단일 객체에 변수를 선언하고 모든 컴포넌트에서 사용할 수 있음

→ props/emit 등 복잡한 컴포넌트 관리를 대체해줌.

 

설치: npm install vuex@next --save

Store: 애플리케이션 상태를 저장하고 있는 컨테이너(전역 저장소)

속성

  • State: 프로젝트 전체에서 공통으로 사용할 변수를 정의하는 곳(한번만 정의하여 모든곳에서 사용

→ 변경 여부를 감시하는 computed와 함께 자주 사용됨.

  • Getters: 어떤 값들을 저장소의 state에 관리할 때, getters를 정의하여 쉽게 가져올 수 있음.
  • Mutations: 기본적으로 state에 정의된 변수를 변경할 수 없고, mutations을 이용해서 변경해야함.
  • Actions: mutations과 유사하지만 actions함수 안에서는 여러개의 mutations을 실행 시킬 수 있고 서버로부터 데이터 fetch등 비동기 처리 로직을 관리할 수 있게 해줌.

Vuex 사이클

Component에서 비동기 호출(Actions) → 데이터 조작(Mutations)→ 데이터 저장(state)

사용 예: 회원가입 시 사용자 인증, 토큰 처리 등과 관련된 정보들을 서버뿐만 아니라 vue에서(front-end) 관리하여 이벤트 처리를 하고싶을 때

데이터 바인딩 템플릿 문법

Vue js는 양방향 데이터를 지원하기 때문에 모델에서 데이터를 정의한 후 뷰와 연결하면 어느 한쪽에 변경이 일어났을 때 다른 한쪽에 자동으로 반영이 됨.

Model에서 정의한 데이터를 View에서 이중 중괄호를 이용하여 데이터 바인딩

1. 문자열 데이터 바인딩

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
    <h1> hello, {{title}}!</h1>
</template>
 
<script>
export default {
    data(){
        return{
            title:'world'
        };
    }
}
</script>
cs

2. HTML 태그 바인딩

HTML 태그를 바인딩 할 때는 문자열 바인딩처럼 이중 중괄호를 사용하면 텍스트로 인식하기 때문에 HTML로 출력되기 위해서는 "v-html" 디렉티브를 사용해야 함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
    <div>
        <div>{{htmlString}}</div>
        <div v-html="htmlString"></div>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
            htmlString:'<p style="color:red;">This is a red String</p>'
        };
    }
}
</script> 
cs

3. Form 입력 데이터 바인딩

Input type, Textarea, Select, checkbox, radio 등의 Form Element 필드는 "v-model" 디렉티브를 사용하여 양방향 데이터 바인딩을 생성할 수 있음.

  • input type="text" : HTML에서 입력받은 데이터는 value에 저장되는데, "v-model"은 내부적으로 이 value 속성을 사용하여 data와 value속성을 바인딩 시킴.
  • input type="number" : 숫자를 입력할 시에는 "v-model.number" 디렉티브를 사용할 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
    <div>
       <input type="text" v-model="valueModel"/><br>
       <input type="number" v-model.number="numberModel"/>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
            valueModel:'South Korea',
            numberModel: 38
        };
    }
}
</script>
cs
  • Textarea: Textarea 속성은 "v-model"을 사용하여 바인딩 함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
    <div>
        <textarea v-model="message"></textarea>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
            message:"텍스트 입력 창입니다."
        };
    }
}
</script>
cs
  • Select : input type=text와 동일하게 "v-model"은 내부적으로 select의 value속성을 사용하여 양방향 데이터 바인딩.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
    <div>
        <select v-model="city">
            <option value="02">서울</option>
            <option value="031">경기</option>
            <option value="064">제주</option>
        </select>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
            city:"064"
        };
    }
}
</script>
cs
  • input type="checkbox" : input type=text, select와 다르게 v-model은 내부적으로 체크박스의 value속성이 아닌 checked속성을 사용하므로 value속성에 데이터 바인딩 시 "v-bind:value"를 사용함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
    <div>
        <label><input type="checkbox" value="서울" v-model="checked">서울</label>
        <label><input type="checkbox" value="부산" v-model="checked">부산</label>
        <label><input type="checkbox" value="제주" v-model="checked">제주</label>
        <br>
        <span>체크한 지역:{{checked}}</span>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
            checked:[]
        };
    }
}
</script>
cs
  • input type="radio" : 체크박스와 마찬가지로 v-model이 내부적으로 checked속성과 바인딩이 이루어지므로, value속성에 바인딩을 하려면 "v-bind:value"를 사용함.

4.  HTML 속성 바인딩

value을 제외한 HTML 객체 속성에 데이터를 바인딩 하기 위해서 "v-bind:" 디렉티브를 사용함. "v-bind"를 생략하고 ':' (콜론)으로 단독 사용할 수도 있음.

  • Img객체의 src : 제품 이미지, 사용자 프로필 사진처럼 이미지의 주소를 img객체의 src에 바인딩 할 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
    <div>
       <img v-bind:src="imgSrc"/>
    </div>
</template>
 
<script>
export default {
    data(){
        return{
           imgSrc:"https://kr.vuejs.org/images/logo.png"
        };
    }
}
</script>
cs

 

  • 버튼 객체의 disabled : 버튼에서 disabled 속성이 true로 되어 있으면 버튼은 비활성화 되고 클릭 이벤트가 발생 되지 않음. "v-model"는 내부적으로 value 속성과 바인딩이 이루어지고 "v-bind"는  disabled속성과 바인딩이 이루어짐.

5. 클래스 바인딩

HTML에서 사용하는 방식처럼 class 속성에 클래스 명을 입력하여 사용할 수 있고, 조건에 따라 바인딩 할 경우 "v-bind:class"를 이용해서 추가적으로 정의해서 사용할 수 있음.

앞서 살펴본 HTML속성 바인딩과 다르게 클래스 바인딩은 아래와 같이 기본 클래스와 데이터 바인딩 처리를 하는 클래스를 공존해서 사용할 수 있음.

  • 배열을 사용한 클래스 바인딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
    <div class="container" v-bind:class="[
        activeClass,errorClass]">Class Binding
    </div>
 
</template>
 
<script>
export default {
    data(){
        return{
           activeClass:'active',
           errorClass:'text-red'
        };
    }
}
</script>
<style scoped>
.container{
    width: 100%;
    height: 500px;
}
.active{
    background-color: yellow;
    font-weight:bold;
}
.text-red{
    color:red;
}
</style>
cs

  • 인라인 스타일 클래스 바인딩: 데이터를 오브젝트로 선언해서 바인딩할 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div v-bind:style="styleObject">인라인 스타일 바인딩</div>
</template>
<script>
export default {
data() {
  return {
     styleObject: {
       color: 'red',
       fontSize: '13px'
     }
  };
}
}
</script>  
cs

 

리스트 랜더링(v-for)

v-for 디렉티브를 사용하여 반복적으로 다중 데이터들을 처리할 수 있음. v-for="(item, index) in items 형식을 사용하며 items는 배열을 의미하고 v-for을 통해 배열을 하나씩 읽어와서 배열의 각 아이템을item으로, 배열의 현재 index를 index로 반환해 줌.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<template>
<div>
  <table>
    <thead>
      <tr>
        <th>제품명</th>
        <th>가격</th>
        <th>카테고리</th>
        <th>배송료</th>
      </tr>
    </thead>
    <tbody>
      <tr :key="i" v-for="(product,i) in productList">
        <td>{{product.product_name}}</td>
        <td>{{product.price}}</td>
        <td>{{product.category}}</td>
        <td>{{product.delivery_price}}</td>
      </tr>
    </tbody>
  </table>
</div>
</template>
<script>
export default {
 data() {
   return {
      productList: [
        {"product_name":"기계식키보드","price":25000,"category":"노트북/태블릿","delivery_price":5000},
        {"product_name":"무선마우스","price":12000,"category":"노트북/태블릿","delivery_price":5000},
        {"product_name":"아이패드","price":725000,"category":"노트북/태블릿","delivery_price":5000},
        {"product_name":"태블릿거치대","price":32000,"category":"노트북/태블릿","delivery_price":5000},
        {"product_name":"무선충전기","price":42000,"category":"노트북/태블릿","delivery_price":5000}
      ]
   };
 }
}
</script>
<style scoped>
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 50%;
}
td, th {
  border: 1px solid #dddddd;
  text-align: left;
  padding: 8px;
}
</style>
cs

조건부 랜더링

Vue 컴포넌트에서 조건에 따라 랜더링을 하는 방법은 v-if 디렉티브와 v-show 디렉티브를 사용하는 방법이 있음.

  • v-if
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
 <h1 v-if="type=='A'">A</h1>
 <h1 v-else-if="type=='B'">B</h1>
 <h1 v-else>C</h1>
</div>
</template>
<script>
export default {
 data() {
   return {
     type: 'A'
   };
 }
}
</script>
cs
  • v-show: v-if 대신에 v-show를 사용하면 되고 else if, else는 지원 하지 않음
  • v-if와 v-show의 차이점
    • v-if는 조건을 만족하면 그 순간에 html 블록이 생성되고, 조건에 만족하지 않으면 html블록은 삭제됨.
    • v-show는 조건 만족 여부에 상관없이 무조건 랜더링 되어 DOM에 남아있게 됨. 조건 만족 시 css의 display CSS속성을 이용해 화면에 보여지고, 조건을 만족하지 않으면 화면에서 숨기도록 처리됨.
    • html 블록이 화면 내에서 자주 toggle되면 v-show를 사용하고, toggle이 일어나는 빈도가 적으면 v-if를 사용하는 것이 좋음.

이벤트 처리

  • 클릭 이벤트: vue컴포넌트에서 이벤트를 처리할 때 "v-on" 디렉티브를 사용하고, "v-on:"을 '@'로 대체할 수 있음. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
 <button type="button" @click="increaseCounter">Add 1</button>
 <p>The counter is : {{counter}} </p>
</div>
</template>
<script>
export default {
 data() {
   return {
     counter: 0
   };
 },
 methods: {
   increaseCounter(){
     this.counter = this.counter + 1;
   }
 }
}
</script>
cs

  • Change 이벤트: select속성에서 자주 사용되며 사용자가 select에서 옵션을 바꿀 때 마다 change이벤트가 발생.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<select v-model="selectedValue" @change="changeSelect">
   <option value="서울">서울</option>
   <option value="부산">부산</option>
   <option value="제주">제주</option>
 </select>
</template>
<script>
export default {
 data() {
   return {
     selectedValue: ''
   };
  },
  methods: {
    changeSelect(){
      alert(this.selectedValue);
    }
  }
}
cs
 

Computed와 Watch

Computed와 Watch 둘 다 Vue 인스턴스 내의 정의된 데이터 값에 변경이 일어나는지를 감시하고 , 변경될 때 마다 정의된 함수가 실행되는 속성

  • Computed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<h1>Full Name:{{fullName}}</h1>
</template>
<script>
export default {
 data() {
   return {
     firstName:'JeongHwan',
     lastName:'Kim'
   };
  },
  computed: {
    fullName(){
        return this.firstName+' '+this.lastName;
    }
    }
  }
 
</script>
cs

 

Computed는 Vue 인스턴스 내에 정의된 데이터 값과 연관된 새 데이터를 정의해서 사용할 수 있도록 해줌.

위 코드에서 함수 이름인 fullName은 함수이자 동시에 Vue 인스턴스의 데이터(새로 정의된)를 의미함. fullName함수가 실행되면 데이터 fullName에 firstName과 lastName을 합친 값이 할당되고 두 값 중 하나라도 변경이 일어나면 fullName함수가 자동으로 실행되고 값이 갱신됨.

-> Computed는 함수이자 Vue 인스턴스의 데이터

  • Watch: Computed처럼 vue 인스턴스에 정의된 데이터 값에 변경이 일어나는지를 감시하고 변경이 일어나면 지정된 함수를 실행시킬 수 있는 점은 같지만 다음과 같은 차이가 있음.
  • Computed: 기존에 정의된 데이터 값을 기반으로 새로운 데이터 값을 활용하기 위해 사용됨.
  • Watch는 Watch에 정의된 데이터 값 하나만을 감시하기 위한 용도로 사용되고 Computed와 다르게 실제 데이터 변경이 일어나기 전까지 함수가 실행되지 않고 반드시 초기 값이 변경되어야 실행됨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
<div>
<h1>Full Name:{{fullName}}</h1>
<button type="button" @click="changeName">변경</button>
</div>
</template>
<script>
export default {
 data() {
   return {
     firstName:'JeongHwan',
     lastName:'Kim',
     fullName:''
   };
  },
 watch:{
   firstName(){
     this.fullName=this.firstName+this.lastName;
   },
   lastName(){
     this.fullName=this.firstName+this.lastName;
   }
 },
 methods:{
  changeName(){
    this.firstName='kevin';
  }
 }
  }
 
</script>
cs
  • firstName과 lastName의 각각의 상태변화를 감시하기 위해 watch구문에 2개의 함수를 정의.
  • 버튼 클릭 전 까지는 값에 변동이 없으므로 출력되지 않음→ changeName()함수가 실행되면(초기 firstName과 같으면 출력X) 변경 값이 출력됨.

 

Vue js

웹 개발을 단순화하고 사용자 인터페이스 개발을 위해 탄생한 자바스크립트 프론트엔드 프레임워크.

Javascript기반의 라이브러리/프레임워크인 React의 데이터 바인딩과 Angular의 가상 DOM 동작 등의 장점들을 모두 반영.

특히, Vue js는 View와 Model 간 단방향 데이터 바인딩을 지원하는 React와 다르게 양방향 데이터 바인딩을 지원함.

 

Vue의 특징

  1. MVVM패턴(Model View View Model):  Front-end와 Back-end 로직을 분리하여 코드를 구성하는 디자인 패턴
    • 사용자에게 보이는 View와 화면 요소의 로직을 제어하는 Model을 분리하여 개발함으로써 효율성을 높임.
    • View model이란 View를 추상화한 개념으로 실제 논리 및 데이터 흐름을 담당.(→ 돔 리스너와 데이터 바인딩)
    • 돔(Dom) : html 문서에 들어가는 요소(tag, class, attributes..)의 정보를 담고있는 데이터 트리로써, 웹 페이지에 대한 인터페이스를 의미함.
    •  리스너(DOM Listener) : 돔 변경 내역에 따라 즉각 반영하여 로직 수행
  2. 가상 Dom 랜더링: 실제 DOM을 추상화하여 변화가 많은 View를 DOM에서 직접 처리하지 않고 가상DOM을 생성하여 메모리에서 처리 후 실제 DOM과 동기화
    • 기존의 웹앱에서는 자바스크립트로 DOM을 조작할 때마다 상태 변경이 발생하지 않은 부분까지도 렌더링이 발생하여 성능 저하를 일으킴.
    • Vue js에서는 상태 변경이 발생한 부분을 가상 DOM에서 수정하고, 메인 DOM과 비교해서 변경된 부분만 적용하여 랜더링 횟수를 최소화 함 → 성능 부하가 줄고 빠른 동작
  3. 양방향 데이터 바인딩: 뷰와 모델을 하나로 연결하여 어느 한 쪽에서 변경 사항이 생기면 다른 한쪽도 동기화시켜 양쪽 모두에 반영
    • 코드의 길이를 줄고 유지 보수가 용이
    • 이벤트 처리를 위한 별도의 로직 불필요
  4. 컴포넌트 기반 Framework: 화면 구성을 위한 기능을 작은 단위 요소들로 구성하여 개발
    • 화면의 구조를 직관적으로 파악할 수 있음.
    • 코드 재사용 및 가독성이 좋아짐.
  5. SPA: SPA(Single Page Application)방식으로 웹 사이트를 개발하여 웹 사이트 최초 접속 시 서버로부터 모든 웹 자원(HTML, css, image ..)들을 받아 온 뒤 로딩을 하게 됨.

 

개발 환경 구성

    1. Vue CLI설치: 터미널에 npm install -g @vue/cli 입력
    2. 프로젝트 생성: vue create project_name (vue 3버전 설치)
    3. 프로젝트 실행: cd project_name → npm run serve(서버가 시작되며 http://localhost:8080으로 실행됨)
    4. Vue Router설정
      • SPA의 경우 페이지를 이동할 때 마다 서버에 요청해서 페이지를 갱신하는 것이 아닌 미리 구성해놓은 페이지를 라우팅을 이용하여 화면을 갱신.
      • Vue JS에서 라우팅은 클라이언트에서 url 주소에 따라 페이지가 전환되는 개념으로, vue-router를 설치하여 라우팅을 구현.
      • Vue Router 설치 및 Default 설정: 터미널에서 vue add router 입력→ src폴더에 router, views 폴더/파일이 생성됨.
      • 생성된 Router폴더의 index.js 파일에서 라우팅 설정할 페이지 설정 
      • Path: 브라우저에서 접속하는 url주소
      • name: 라우트 설정 이름
      • component: 지정된 Path로 접속했을 때 보여줄 vue 컴포넌트(구현할 vue 파일)
      • component 파일 import 시 2, 8번 째 라인 or 16번 째 라인 처럼 구성할 수 있음
      • 코드 설명

Vue js LifeCycle Hooks

  1. 모든 Vue 애플리케이션은 CreateAPP함수를 이용하여 새로운 인스턴스를 생성하여 시작됨.(랜더링의 시작점)
  2. beforeCreate: 인스턴스가 초기화 된 후 컴포넌트가 생성되기 직전에 이루어지는 hook. (데이터 접근 권한이 없는 상태)
  3. Created: data와 events가 활성화되어 접근할 수 있지만 여전히 가상돔은 마운트 및 랜더링되지 않은 상태의 hook.
  4. beforeMount: 마운트/랜더링 되기 직전에 호출되는 hook.(화면 요소에 vue 인스턴스를 연결하기 전에 진행됨.)
  5. mounted: 화면 요소에 인스턴스가 연결되고 랜더링 된 후 호출되는 hook.
  6. updated: 데이터가 변경되어 가상 DOM이 다시 랜더링된 후 호출되는 hook.
  7. beforeUnmount: 컴포넌트 인스턴스가 마운트 해제(unmounted) 되기 직전에 호출되는 hook. (인스턴스는 여전히 정상 동작)
  8. unmounted: 컴포넌트 인스턴스가 마운트 해제된 후 호출되는 hook. (데이터 바인딩이 해제되며 모든 이벤트 리스너가 제거 됨)

 

Reference

https://v3.ko.vuejs.org/api/options-lifecycle-hooks.html#deactivated

http://www.yes24.com/Product/Goods/101926719

 

한국투자 저축은행 IT직무 최종 합격!

'취준&이직' 카테고리의 다른 글

기업 면접 질문 &답변  (12) 2022.03.03
취준 끝  (8) 2021.12.11
취준 현황 (12.8 기준)  (4) 2021.12.08
서류는 합격했지만 면접 포기한 기업 list  (0) 2021.11.30
취준현황 !!(11/17 기준..)  (2) 2021.11.17

알람 경보 설정(CPU, Memory, Disk)

하드웨어의 각 리스소 사용량이 설정 기준치를 넘었을 시 대쉬보드를 통한 시각적 경보 효과 및 이메일, Slack을 통한 알람을 구현하는 과정을 정리한다.

  • 경보 환경 세팅
    • window/ubuntu 서버 모두 다양한 방법으로 하드웨어 부하를 테스트 할 수 있고, 그 중 가장 확인하기 쉬운 ubuntu서버에서 cpu부하를 통해 테스트 환경 설정.
      우분투 서버에서(ec2 인스턴스 원격 연결된) sudo yum install stress -y 명령어로 테스트 패키지 설치.
      그 다음 grep -c processor /proc/cpuinfo 명령어로 인스턴스의 cpu 코어 갯수 확인
    • 그 다음 아래 명령어 양식대로 cpu 부하 설정을 위한 코어 갯수 및 부하 기간 설정
      stress --cpu 코어갯수 --timeout 시간(초)
    • top 명령어를 통해 cpu 사용량이 100%까지 올라간 것을 확인.

cpu코어 수
20분동안 cpu util 100%부하
cpu사용량이 100%에 근접

  • 경보 위젯 확인
    • 데이터가 기준치를 넘었을 시 경보 목록과 대쉬보드 페이지에 경보가 생성됨.

 

 Email을 통한 알람 설정

  • SNS topic/subscription 설정: 이메일/Slack 채널 알람을 위해 sns 주제/구독 설정
  • 이메일 알람 확인: cloudwatch 콘솔 -> 경보 탭 '모든 경보' -> 경보 생성
  • 경보 생성 지표를 생성 후 지표 탭에서 경보 확인 기간을 설정(20분)
  • 참고) 기간은 경보를 생성하기 위해 지표를 평가하는 기간으로, 20분으로 설정 시 경보가 20분 당 한 번씩 평가함.(경보가 지속되는 상황에서는 최초 한번의 알람만 울림)
  • 이메일 경보 설정 예시

  • 그리고 경보 -> 조건 탭에서 경보 이벤트를 설정할 데이터 기준치를 설정

5분마다 한번씩 확인

 

cpu사용량이 60%이상일 때 알람설정

  • 추가 구성 탭 에서는 경보를 알릴 데이터 포인트를 설정하는데, default는 1/1로 되어있음.

왼쪽은 데이터 포인트 체크 횟수, 오른쪽은 기간*횟수를 의미함.

 

  • 실제 테스트 결과, 5분에 한 번 꼴로 알람이 울림.
    참고) https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html
  • 그리고 그림에서 볼 수 있듯, 데이터 누락에 관한 경보도 설정할 수 있는데,
    다음-> 알림 탭에서 경보상태 트리거를 설정 및 알림 전송 엔드포인트(아까 생성한 SNS토픽 이름)선택-> 경보 이름, 설명 저장 후 경보 생성 완료-> 경보 환경 세팅 후 이메일 확인
  • 예시

Slack 알림 메시지 설정
이메일을 통한 알람 수신은 매우 번거롭고 확인하기 힘들기 때문에 팀에서 사용 중인 slack채널을 통해 빠르게 알람 수신할 수 있도록 설정할 수 있음.

특히 이메일 알람의 경우 기본 format을 편집할 수 없어서 불필요한 정보도 함께 전달되며, 즉각적으로 확인할 수 없음.
Slack알람 순서: 알림 받을 slack 채널 생성-> 수신 webhook 설정-> SNS 주제, 구독 생성-> lambda 함수 설정-> 동작 확인

  • 알람 수신용 채널 생성 및 설정경보 알림 전용 채널을 새로 생성(본인에게 알람 수신 원할 시 별도 생성은 필요하지 않음)

  • 해당 채널로 입장-> 상단 더보기-> 앱 클릭-> 'incoming webhooks' 검색 및 추가

  • 해당 채널의 웹훅 URL(aws에서 이벤트 발생 시 슬랙채널로 알림을 보낼 때 사용하는 주소)이 생성되고, 경보를 수신할 채널 이름, 사용자 지정 후 설정 저장
  • AWS Lambda의 알람 설정 함수가 해당 URL로 알람 전송->slack에서 확인

  • 설정 후 채널에 알림 문구가 도착한 것을 확인

  • 이제 aws sns topic/subscription를 설정해야 하는데, 그 전에 lambda에서 알림 전송용 함수를 생성함.(ARN 주소를 사용하기 위해 람다를 생성해야하므로 함수만 만들어놓고 topic생성하러 가기)

  • 람다 함수의 언어를 선택하고, 본인이 원하는 알람 포맷으로 코딩하여 테스트 진행하고 함수 ARN를 복사 후 새 탭을 열어서 aws sns 페이지로 이동.(python, node js 예제가 많이 있습니다.) 그다음 환경 변수에서 channel이름과 slack채널의 webhook URL을 입력
  • 앞서 진행 했듯 aws sns 주제/구독을 생성하되 구독 생성 시 프로토콜을 lambda로, 엔드포인트를 방금 생성한 lambda 함수 ARN을 입력.
    • 주의) 최초 topic생성의 경우 새 topic를 생성하지만, 앞서 이미 이메일 알람을 위한 topic 생성이 완료된 경우는 subscription만 생성.

  • 설정이 완료된 lambda상태

→ SNS topic인 HW_resource_alarm 트리거가 생성되어있음.

  • aws sns 구독 상태
    • 현재 이메일/slack 알람을 위한 두개의 엔드포인트가 등록되어 있음.

마찬가지로 경보를 생성하고 cpu 부하를 테스트한 뒤 60%가 넘어가면 아래와 같이 슬랙에 알림이 전송됨.

이메일 알람과 slack알람 비교

  • 이메일: 가독성 떨어지고 즉각 수신이 불가, 이메일 format변경 불가
  • 슬랙: 즉각 알람 가능, 알람현황 및 대시보드 공유url을 추가하여 바로 모니터링 할 수 있음.
  • 전체 Flow

내가 사용한 슬랙 알람 Lambda 함수 코드

직접 실습해 보실 수 있도록 제가 사용했던 lambda코드를 첨부합니다.(물론 구글링이 90%..)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// 구성 -> 환경변수로 webhook을 받도록 합니다.
const ENV = process.env
if (!ENV.webhook) throw new Error('Missing environment variable: webhook')
 
const webhook = ENV.webhook;
const https = require('https')
 
const statusColorsAndMessage = {
    ALARM: {"color""danger""message":"위험"},
    INSUFFICIENT_DATA: {"color""warning""message":"데이터 부족"},
    OK: {"color""good""message":"정상"}
}
 
const comparisonOperator = {
    "GreaterThanOrEqualToThreshold"">=",
    "GreaterThanThreshold"">",
    "LowerThanOrEqualToThreshold""<=",
    "LessThanThreshold""<",
}
 
exports.handler = async (event=> {
    await exports.processEvent(event);
}
 
exports.processEvent = async (event=> {
    console.log('Event:', JSON.stringify(event))
    const snsMessage = event.Records[0].Sns.Message;
    console.log('SNS Message:', snsMessage);
    const postData = exports.buildSlackMessage(JSON.parse(snsMessage))
    await exports.postSlack(postData, webhook);
}
 
exports.buildSlackMessage = (data) => {
    const newState = statusColorsAndMessage[data.NewStateValue];
    const oldState = statusColorsAndMessage[data.OldStateValue];
    const executeTime = exports.toYyyymmddhhmmss(data.StateChangeTime);
    const description = data.AlarmDescription;
    //const cause = exports.getCause(data);
 
    return {
        attachments: [
            {
                title: `[${data.AlarmName}]`,
                color: newState.color,
                fields: [
                    {
                        title: '시간',
                        value: executeTime
                    },
                    {
                        title: '설명',
                        value: description
                    },
                    // {
                    //     title: '원인',
                    //     value: cause
                    // },
                    {
                        title: '이전 상태',
                        value: oldState.message,
                        shorttrue
                    },
                    {
                        title: '현재 상태',
                        value: `*${newState.message}*`,
                        
                        shorttrue
                    },
                    {
                        //title: '바로가기',
                        title: '알람설정 현황',
                        value: exports.createLink(data)
                    },
                    {
                        title:'대시보드 현황',
                        value: exports.create1Link(data)
                    }
                ]
            }
        ]
    }
}
 
// CloudWatch 알람 바로 가기 링크
exports.createLink = (data) => {
    return `알람 세부 현황 url`;
}
exports.create1Link = (data) => {
    return ` 대시보드 url`;
}
 
exports.exportRegionCode = (arn) => {
    return  arn.replace("arn:aws:cloudwatch:""").split(":")[0];
}
 
 
 
// 이상 지표 중 Band를 벗어나는 경우
exports.buildAnomalyDetectionBand = (data, evaluationPeriods, minutes) => {
    const metrics = data.Trigger.Metrics;
    const metric = metrics.find(metric => metric.Id === 'm1').MetricStat.Metric.MetricName;
    const expression = metrics.find(metric => metric.Id === 'ad1').Expression;
    const width = expression.split(',')[1].replace(')''').trim();
 
    return `${evaluationPeriods * minutes} 분 동안 ${evaluationPeriods} 회 ${metric} 지표가 범위(약 ${width}배)를 벗어났습니다.`;
}
 
// // 이상 지표 중 Threshold 벗어나는 경우 
// exports.buildThresholdMessage = (data, evaluationPeriods, minutes) => {
//     const trigger = data.Trigger;
//     const threshold = trigger.Threshold;
//     const metric = trigger.MetricName;
//     const operator = comparisonOperator[trigger.ComparisonOperator];
//     return `${evaluationPeriods * minutes}분 동안 ${evaluationPeriods}회 이상 ${metric} ${operator} ${threshold}`;
    
// }
 
// 타임존 UTC -> KST
exports.toYyyymmddhhmmss = (timeString) => {
 
    if(!timeString){
        return '';
    }
 
    const kstDate = new Date(new Date(timeString).getTime() + 32400000);
 
    function pad2(n) { return n < 10 ? '0' + n : n }
 
    return kstDate.getFullYear().toString()
        + '-'+ pad2(kstDate.getMonth() + 1)
        + '-'+ pad2(kstDate.getDate())
        + ' '+ pad2(kstDate.getHours())
        + ':'+ pad2(kstDate.getMinutes())
        + ':'+ pad2(kstDate.getSeconds());
}
 
exports.postSlack = async (message, slackUrl) => {
    return await request(exports.options(slackUrl), message);
}
 
exports.options = (slackUrl) => {
    const {host, pathname} = new URL(slackUrl);
    return {
        hostname: host,
        path: pathname,
        method: 'POST',
        headers: {
            'Content-Type''application/json'
        },
    };
}
 
function request(options, data) {
 
    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            res.setEncoding('utf8');
            let responseBody = '';
 
            res.on('data', (chunk) => {
                responseBody += chunk;
            });
 
            res.on('end', () => {
                resolve(responseBody);
            });
        });
 
        req.on('error', (err) => {
            console.error(err);
            reject(err);
        });
 
        req.write(JSON.stringify(data));
        req.end();
    });
    
}
 
 
 
cs

 

Reference

https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html

Cloudwatch 대쉬보드 생성

순서: aws cloudwatch 서비스 접속-> 대쉬보드 탭-> 대쉬보드 생성 클릭-> 위젯 추가->metrics정보 출력 확인

  • 행 위젯 생성
    대시보드 생성 페이지에서 우상단 위젯추가 버튼-> 행 위젯 추가-> 지표 클릭 후 아래 그림처럼 namespace 목록이 출력됨.

  • 본인이 원하는 namespace의 metric 정보를 설정

  • y축의 퍼센트 수치를 0~100처럼 변경하고 싶으면 옵션 탭-> Left Y axis에서 레이블에 percent입력 후 최소/최대 수치 조정-> 단위 표시해제 후 위젯 생성→ percent로 표현되지 않는 metric 정보를 percent로 그래프에 표현하고 싶을 때 반드시 설정함.

  • 참고) disk 정보의 경우 window 서버는 linux서버와 달리 storage의 사용량 정보는 없기 때문에 사용량 정보로 변환하고 싶을 시 "수학 추가" 탭을 통해 아래처럼 식을 조정해야함. METRICS()는 해당 디멘션의 모든 지표들을 나타내고, METRICS(m1)은 m1만을 의미함. 아래 그림의 경우 metric이 하나 이므로 두 표현 모두 같은 의미를 지님. 

  • 경보 위젯 생성
    • 대쉬보드 창에서 본인이 설정한 경보의 정보를 이용하여 다음과 같이 구성할 수 있음. 

  • 번호 위젯 생성
    • 번호 위젯은 이전에 생성한 행 그래프를 수치화된 텍스트로 표현함.

m1: c드라이브의 free_space

m2: d드라이브의 free_space

e1: 잔여 공간이 아닌 사용량을 사용하기 위해 새로 생성한 지표

 

  • 행/번호 위젯 생성 완료

  • 외부 공유설정
    • 생성한 대시보드를 외부에서 참조할 수 있는 기능으로, public url을 통해 누구나 접근할 수 있음.
      cloudwatch 대시보드 탭에서 대시보드 선택-> 대시보드 공유 클릭-> "대시보드를 공개적으로 공유" 클릭-> "정책 수락 및 공유 가능한 링크 생성" 클릭-> 설정 완료 후 대시보드 생성 페이지에서 상단에 주소 링크가 보임. 이 링크를 통해 외부에서 그래프를 모니터링 할 수 있음. 링크 주소를 복사 하여 접속하면 그래프를 볼 수 있지만 읽기 권한만 제공됨.

  • 텍스트 위젯 생성
    • 텍스트 위젯은 aws의 마크다운 언어로 위젯을  자유롭게 구성할 수 있지만 aws에서 지원하는 markdown 문법은 매우 한정됨.(사용 지양 추천)

  • 서버 대시보드 구현상태

  • 다양한 위젯을 구성한 대시보드

 

Reference

https://docs.aws.amazon.com/ko_kr/awsconsolehelpdocs/latest/gsg/aws-markdown.html

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/create-and-work-with-widgets.html

AWS Cloudwatch

AWS의 리소스 상태를 실시간으로 모니터링 할 수 있는 서비스로, 데이터 수집, 알람 생성, 모니터링도구(로그, 대쉬보드)를 제공한다.(구체적인 설명은 아래 링크에 잘 나와있습니다.)

https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html

 

AWS Cloudwatch 구조

애플리케이션 환경에서 agent를 설치 후 데이터를 전송하면, aws에서 metric이라는 이름으로 수집되는데, 해당 메트릭은 Namespace 내부의 Dimension(차원) 안에 저장되어있다. 데이터를 가공하기 위한 다양한 math expression이 제공되며 가공처리 후 최종적으로 대시보드에 뿌려주게 되는 구조로 이루어져있다.

1. Window server -On premise 방식

          aws cli 설치 이후 powershell이나 cmd에서 "aws --version" 명령어가 인식되어야 함.

  • Cloudwatch agent 프로필 등록(region, data format등의 AmazonCloudWatchAgent 프로필을 생성하기 위함)
    • "aws configure --profile AmazonCloudWatchAgent" 명령어 입력 후 region은 ap-northeast-2, format은 json으로 설정
  • IAM권한 설정(agent 구성 파일 생성)
    • 아래 명령을 입력하여 구성 파일 생성
      • cd "C:\Program Files\Amazon\AmazonCloudWatchAgent".\amazon-cloudwatch-agent-config-wizard.exe
      • 명령어를 입력 하면 구성 파일 설정을 위한 옵션들을 선택하게 됨.(OS, 지표 타입, 전송 주기 등등)
      • 우선 대부분의 진행 옵션을 default로 선택하되 Log Agent/ log files/log/ SSM Parameter store와 관련된 옵션은 모두 No로 설정.
      • wizard실행 방식은 json 파일의 기본 format을 사용하기 위해 사용되고, 본인이 직접 config.json 파일을 생성하며 편집해도 됨.
  • 구성 파일 편집
    • cloudwatch에 연동을 시키면 default namespace가 생성되는데, 각 서버에 따라 이름을 따로 지어주기 위해 이전 단계를 통해 생성된 json 파일을 편집함(일단 이름만 변경)
    • 현재 디렉토리 위치에 있는 config.json 파일을 open한 뒤 namespace설정 구문 한 줄을 입력(winserver1은 본인이 설정한 namespace임.)

  • cloud watch agent 실행
    • 실행: & "C:\Program Files\Amazon\AmazonCloudWatchAgent\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m onPremise -s -c file:"C:\Program Files\Amazon\AmazonCloudWatchAgent\config.json"         - fetch-config: config.json
    • 상태 조회(stopped/running): fetch-config를 status로 변경
    • 중지: fetch-config를 stop으로 변경

  • agent 실행 로그 파악
    • ubuntu는 /opt/aws/amazon-cloudwatch-agent/logs 위치에 로그 파일이 존재. 이 파일을 조회하여 agent의 동작 상태 확인(ex. config.json 파일 문법 오류, 기타 에러 등)
    • windows는 C:\ProgramData\Amazon\AmazonCloudWatchAgent\Logs\amazon-cloudwatch-gent.txt
  • 지표 생성 확인
    • 위에서 살펴본 실행 명령의 결과로 aws cloudwatch 콘솔에 본인이 생성한 namespace의 메트릭스 정보가 뜸.
    • winserver1이 생성됨(cpu, disk, network 등의 metrics 정보 존재)
    • 나머지 3개의 namespace는 본인이 기존에 만들어 놓은 것.

 

2. Window Server -AWS EC2 방식

EC2방식은 Window/Linux 상관없이 Cloudwatchagentserverpolicy 역할을 생성 한 뒤 EC2인스턴스 페이지에서 해당 역할을 추가하면 됨. on premise방식과 유사하지만 IAM 권한 설정 및 에이전트 실행 명령어 옵션이 상이함.

3. Linux -AWS EC2 방식

  • cloudwatch agent 패키지 설치
    • sudo yum install amazon-cloudwatch-agent
  • IAM 권한 설정
    • window EC2방식과 동일
  • agent 구성 파일 생성
    • sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard
  • 구성 파일 편집
    • 마찬가지로 namespace를 새로 지정하려면 cd /opt/aws/amazon-cloudwatch-agent/ 디렉토리로 이동한 뒤 config.json을 open한 뒤 이전과 마찬가지로 namespace 구문 한 줄 추가 후 저장.
  • cloudwatch agent실행
    • sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file://opt/aws/amazon-cloudwatch-agent/bin/config.json
    • 주의) 공식 문서에는 아래와 같이 나와있지만, 실제로 "file:" 뒤에 슬래쉬( / ) 2개 추가 안해주면 cloudwatch 콘솔에서 namespace가 정상적으로 생성되지 않는 이슈 존재

 

Reference

https://docs.aws.amazon.com/ko_kr/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Agent-on-EC2-Instance.html

REST

Representational State Transfer의 약자로서 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처 스타일.

  • HTTP URI를 통해 자원을 명시하고, HTTP Method를 통해 해당 자원에 대한 CRUD연산을 적용하는 것
  • 자원 기반의 구조(ROA, Resource Oriented Architecture)설계의 중심에 Resource가 있고 HTTP Method를 통해 Resource를 처리하도록 설계된 아키텍처.

     *  URL vs URI

    • URL: Uniform Resource Locator로, 인터넷 상 자원의 위치를 의미함.
    • URI: Uniform Resource Identifier로, 인터넷 상의 자원을 식별하기 위한 문자열의 구성(URI는 URL을 포함)

    *  CRUD Operation

    • Create(생성): POST
    • Read(조회): GET)
    • Update(수정): PUT
    • Delete(삭제): DELETE

REST 특징

  • Uniform Interface(인터페이스 일관성)
    • 일관성있는 인터페이스로 URI를 통해 지정한 자원에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일.
    • HTTP 표준 프로토콜만 따른다면 모든 플랫폼(특정 OS/Language에 종속된 것이 아닌)에서 사용이 가능
  • Client-server(클라이언트-서버 구조)
    • 자원이 있는 쪽이 서버, 자원을 요청하는 쪽이 클라이언트로 동작하는 구조를 갖음.
    • REST서버는 API를 제공하고, 클라이언트는 사용자 인증, Context(세션, 로그인 정보 등)을 직접 관리.
    • 클라이언트와 서버의 역할이 구분되어 개발 내용이 명확해지고 의존성이 줄어듬
  • Stateless(무상태)
    • 서버는 단순히 요청에 대한 응답만 보낼 뿐, 세션 유지 관리는 클라이언트에게 책임이 있음.
    • 클라이언트의 context(세션, 쿠키 등의 정보)를 서버에 저장하지 않기 때문에 구현이 단순.
    • 서버는 클라이언트의 각각의 요청을 이전 상태 정보를 참고 하지 않고 매 요청을 별개의 것으로 인식해서 처리(→ 서버의 Response가 일관성있게 이루어지고 그만큼 서비스의 자유도가 높아짐.)

        → Stateless의 장점

    • 클라이언트의 요청의 세션 상태를 저장할 필요할 필요가 없으므로 구현이 간소화 되고 그만큼 API를 여러 서버에 배포하고 확장하는 데 도움이 됨.
    • 클라이언트가 각 요청과 함께 서버의 처리에 필요한 모든 정보를 전송하기 때문에 클라이언트의 정보를 단순 처리함.
    • 서버측에서 메모리 사용량을 줄일 수 있고, 세션이 필요하지 않으므로 세션관리가 불필요. 
  • Cacheable(캐시 가능)
    • REST의 가장 큰 특징 중 하나는 HTTP 웹 표준을 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 활용할 수 있음
    • HTTP의 캐싱 기능을 적용 가능하므로 Last-Modified태그나 E-Tag를 이용하면 캐싱 구현 가능.
  • Layered System(계층화 시스템)
    • 클라이언트와 서버가 분리되어 중간에 프록시 서버, 게이트웨이, 암호화 계층 등 중간 매체를 사용해 자유도를 높일 수 있음.
    • 클라이언트는 API만 호출하므로 서버와 직접 통신하는 것인지 중간 매체 서버와 통신하는지 알 수 없음.
  • Self-descriptiveness(자체 표현 구조)
    • REST API 메시지만 보고도 이를 쉽게 이해할 수 있는 자체 표현 구조로 구성되어 있음.

REST API  vs RESTful API

 * API: 응용 프로그램에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스

  • REST API: REST 아키텍쳐 스타일을 따르는 API
  • RESTful API: 위에서 살펴본 REST의 기본 원칙들을 잘 지켜서 설계된 API

REST의 구성 요소

  • Resource(자원): URI를 의미함. 클라이언트는 URI를 이용해 자원을 지정하고 해당 자원 상태(정보)에 대한 조작을 서버에 요청함.
  • Verb(행위) HTTP Method(GET, POST, PUT, DELTE ..)
  • Representation(표현): 서버와 클라이언트가 데이터를 주고받는 형태로 JSON, XML, TEXT, RSS등이 있고 주로 JSON, XML를 통해 데이터를 주고받음.

REST API 디자인 가이드

  • URI는 자원의 정보를 표현해야 한다.
  • 자원에 대한 행위는 HTTP Method로 표현하되, Method는 URI에 포함하지 않는다.

REST의 장단점

장점

  • REST API 사용을 위해 별도의 인프라 구축 필요X
  • HTTP 표준 프로토콜을 따르는 모든 플랫폼에서 사용 가능
  • REST API 메시지가 의도하는 바를 직관적으로 이해할 수 있음
  • server, client를 완전히 독립적으로 구현할 수 있음
  • 뛰어난 유연성, 낮은 유지 보수 비용, 높은 확장성, 사용 간단 등

단점

  • 표준이 존재하지 않아 별도의 정의가 필요함.
  • 일부 구형 브라우저가 아직 지원해주지 못하는 부분이 존재함.(익스플로어)
  • HTTP Method를 사용하지만 사용할 수 있는 메소드 숫자와 형태가 제한적임.

REST API 설계 규칙

  • URI(리소스 이름)는 명사를 사용한다.(URI는 어떤 정보의 자원을 표현해야한다.)
  • 슬래시로 계층 관계를 표현한다.
  • 자원의 행위는 HTTP Method로 표현한다.
  • URI의 마지막 문자로 슬래시를 표함하지 않는다.
  • 밑줄을 사용하지 않고 하이픈( -)을 사용한다.
  • URI는 소문자로만 구성한다.
  • 파일 확장자는 URI에 포함하지 않는다.

예시

/users/me/profile (O)
/users/me/profile/ (X)

 

/users/me/profile-preview (O)
/users/me/profilePreview (X)

 

/users/me/picture -Accept: image/png (O)
/users/me/picture.png (X)

Reference

https://restfulapi.net/

http://www.incodom.kr/REST

+ Recent posts