Dev/SW Engineering

16. Interaction With Server - Why We Use Fetch & Let's Use!

HJChung 2020. 7. 21. 12:49

1. Why We Use Fetch

저번에는"Client는 요청하는 주체 - API가 이 요청/응답을  정리해서 상호작용 매개, 이때 상호작용은 HTTP라는 규약에 맞게! - Server는 응답하는 주체, Client가 Server로부터 요청에 대한 응답(데이터같은..)을 받아서 이를 보여줄때 JavaScript를 사용한 비동기 통신으로 데이터를 주고받는 기술인 AJAX" 까지 알아보았습니다.

1) AJAX

AJAX를 통해서 서버의 자원을 요청하고 chaining방식으로 요청을 처리할 수 있지만 조금은 복잡한감이 있다고 합니다.(저는.. AJAX나 fetch나 다 어려워보이는건 마찬가지..)

간단 예시)

$.ajax({
	url: 'http://example.com',
    method: 'GET',
    dataType: 'json'
  })
  	.done(function(json){
    	console.log(json)
    })
    .fail(function(xhr, status, errorThrown){
    	
    })
    .always(function(xhr, status){
    	console.log('요청 완료')
    });

그래서 더 간단한 것으로 나온 것이XMLHttpRequest와 비슷한 역할을 하지만 조금더 강력하고 유연한 조작이 가능한 Fetch API입니다. 

2) Fetch API

형식)

fetch('주소', 설정객체)
	.then(콜백함수 res => { 
      console.log(res);
	
      // res : Response의 instance로 여러 정보를 담고 있습니다.
      //       일단, 우리가 원하는 정보가 바로나오지는 않는 다는 것을 인지할 수 있습니다.
      //       따라서, 우리가 원하는 정보로 다음 .then()으로 넘겨줍시다.
      //       res.json()을 통해 원하는 정보를 얻어봅시다.

      return res.json();
	})
  .then(콜백함수 res => {
      console.log(res);

      // res : 위의 .then()에서 return해준 결과를 뜻합니다.
      //       원하는 정보는 객체형태로 얻었습니다. 그 이후 원하는 것을 해보시면 됩니다.

      // ... todo something
  });
  .catch(콜백함수 err => {
    	//요청에 대한 에러를 받습니다. 
  });
  • 주소: 요청을 보낼 주소를 입력

  • 설정 객체: GET, POST 등의 메소드, 보낼 데이터

  • (or 주소와 설정객체 대신 Request 객체)

  • then: 응답 response 객체(Response 객체는 응답에 대한 정보)를 받고 ⇒ fetch가 request처리 할 때까지 시간이 걸린다. 이때동안 아무것도 안하고 있으면? 너무 비효율적! 그래서 'fetch야 request다 하고 나면~then~이하를 해줘' 라는 비동기 처리 방식이다.

  • catch: 요청에 대한 에러를 받습니다.

간단 예시)

fetch('http://example.com')
    .then(res => res.json())
    .then(data => {
    	console.log(data);
    })
    .catch(err => {
    	console.error(err)
    });

 

2. Let's use

여기까지 개념적인 것은 공부를 해봤으니 처음 목표였던 '서버와 잘 통신하는 Client 페이지'를 만들어보도록 하겠습니다.

여기서 핵심 기능은

  1. fetch API를 통해 서버에 자원/정보를 요청
  2. 요청된 자원을 이용하여 화면을 구성하고 변경
  3. event를 발생시켜서 서버에 자원/정보를 요청하고, 다시 화면을 변경

입니다.

 

① 사용할 서버 정의

app.js

const app = {
	server: 'http://잘 작동한는 서버 주소:3000/messages'
}

 

② fetch API를 통해 서버에 자원/정보 요청

  • fetch API로 GET 요청(서버에 자원을 요청) 해보겠습니다. 

app.js

fetch(app.server, { //1. 주소: 
	method: 'GET' //1-2. 설정객체: 
    })
    .then(res => { //2. res은 응답받은 것의 정보다 있다. 그러므로 이를 우리가 원하는 정보를 얻기위해 
    	return res.json(); //2-2. json() 을 해줍니다. (.json()의 경우 데이터의 형태에 따라 바뀔 수도 있습니다. 0
    )}
    .then(res => {//3. json()된 res을 바탕으로 
    	//3-2. Javascript를 통해 DOM을 조작하여 필요한 부분만 수정하는 방식으로 페이지 부분 수정을 합니다. 
        // 즉, 여긴 Javascript callback함수가 들어가게 되겠습니다. 
        renderMessage(json) //저같은 경우는 (화면에 res를 HTML형식으로 보여주는)render함수를 밖에서 만들었고, 이를 콜백함수로 넣어주었습니다.
    }
    .catch(err => console.errer(err))
  }	

 

③ 요청된 자원을 이용하여 화면을 구성하고 변경

저는 위에서 

render함수를 콜백함수로 넣어줌으로써 원하는 정보를 객체형태로 얻은 것을 화면에 HTML을 이용하여 출력하도록 하였습니다. 따라서 '요청된 자원을 이용하여 화면을 구성하고 변경' 하라는 요구사항은 render함수에 구현이 되어있는것입니다. 

app.js

//일단 fetchAPI로 GET요청을 해서 받아온 res.json()의 형태는 
//{"id":0,"username":"정현정","text":"hello","roomname":"담소","date":"2020-06-20T05:21:30.927Z"},같은 객체들이 여러개 있는 배열입니다. 

function renderMessage(DATA){
	for(let i=0; i<DATA.length; i++){
    	let ulElement = document.querySelector('#chat');
        
        let mes = document.createElement('div');
        mes.classList.add('chat');
        
        let id = document.createElement('div');
        id.classList.add('id);
        id.textContent = DATA[i].id;
        
        let username = document.createElement('span');
        username.classList.add('username');
        username.textContent = DATA[i].username;
        
        let text = document.createElement('div');
        text.classList.add('text');
        text.textContent = DATA[i].text;
        
        let roomname = document.createElement('span');
        roomname.classList.add('roomname')
        roomname.textContent = DATA[i].roomname;
        
        mes.appendChild(id);
        mes.appendChild(username);
        mes.appendChild(text);
        mes.append(roomname);
        
        ulElement.appendchild(mes)
    }
}   

 

④ event를 발생시켜서 서버에 자원/정보를 요청하고, 다시 화면을 변경

index.html - textarea에 메세지를 적고 button type인 submit 버튼을 누르면 onClick event가 발생합니다. 

<textarea placeholder="Input some text." class="area"></textarea>
<div>
	<input type="button" id="submit" value="submit onClick="app.init()">
</div>

이때 발생하는 app.init()은

app.js

//app.init: 메세지 작성 후 submit누르면 작동하는 메소드
init: () => {
	let submit = document.querySelector('#submit') 
    if(submit) {// 새로운 메세지 submit이 있으면
    	app.createNewMessage(); //새로운 메세지 하나를 기존 메세지들에 추가하고 
        app.clearMessagess(); //기존 메세지 출력된거 전체를 지우고
        app.printMessage(); //새롭게 전체를 다시 화면에 출력
     }
}
    	

여기서 app.createNewMessage()는 '새로운 메세지 하나를 기존 메세지들에 추가해'라는 요청을 app.server에 보내야합니다. 

자원을 생성하라고 요청하는건?! HTTP의 메소드

  • GET: 서버에 자원을 요청
  • POST: 서버에 자원을 생성
  • PUT: 서버의 자원을 수정
  • DELETE: 서버의 자원을 제거

중에서 POST입니다. 그래서 app.createNewMessage()에는

fetch(app.server, {
	method: 'POST', 
    body: JSON.stringify(message), 
    headers: {
    	"Content-Type": "application/json"
    }
 })
 	.then(response => {
    	return response.json();
    })
    .then(response => {
    	return callback);
 }

이런 fetch API로 POST 요청을 하는 부분이 들어갑니다. 

 

그리고 app.printMessage()는 '새롭게 전체 메세지들을 다시 화면에 출력'하는 부분입니다. 그러려면 '네가 가진 메세지데이터를 다 보내줘'라고 서버에 자원을  요청해야합니다. 자원을 요청하는건?! GET입니다. 

그래서 app.printMessage()에는

fetch(app.server, { //1. 주소: 
	method: 'GET' //1-2. 설정객체: 
    })
    .then(res => { //2. res은 응답받은 것의 정보다 있다. 그러므로 이를 우리가 원하는 정보를 얻기위해 
    	return res.json(); //2-2. json() 을 해줍니다. (.json()의 경우 데이터의 형태에 따라 바뀔 수도 있습니다. 0
    )}
    .then(res => {//3. json()된 res을 바탕으로 
    	//3-2. Javascript를 통해 DOM을 조작하여 필요한 부분만 수정하는 방식으로 페이지 부분 수정을 합니다. 
        // 즉, 여긴 Javascript callback함수가 들어가게 되겠습니다. 
        renderMessage(json) //저같은 경우는 (화면에 res를 HTML형식으로 보여주는)render함수를 밖에서 만들었고, 이를 콜백함수로 넣어주었습니다.
    }
    .catch(err => console.errer(err))
  }	

이 '② fetch API를 통해 서버에 자원/정보 요청' 할 때 사용한 코드가 들어가에 됩니다.