Ajax with XHR (사진/기사 검색 Web app 만들기)

Ajax with XHR (사진/기사 검색 Web app 만들기)

목차 - Before Ajax - API란? - XHR Object - APIs and JSON - Unsplash / NYT API를 이용한 웹애플리케이션 만들기


##### Ajax with XHR 과거 웹애플리케이션에서 클라이언트가 현재의 웹페이지 상에서 어떠한 새로운 정보나 수정을 요청하면, 서버는 그러한 요청을 받아들여 완전히 새로운 페이지를 클라이언트에 전달했고 클라이언트는 새 페이지를 로드해야 했습니다.

90년대 후반 마이크로소프트에서 XMLHTTP를 웹버전 outlook에 추가했고, 이것이 다른 브라우저에서 XMLHttpRequest로 적용되었습니다. 이것은 Javascript로 HTTP request를 할 수 있게 했으며, 페이지 전체의 로딩 없이 부족한 부분의 데이터만 서버로부터 가져올 수 있게 되었습니다.


##### API란? 그러면 Ajax란 기술로 전달 받는 데이터는 어디서 오는 것이고, 어떻게 접근할 수 있을까요? 그리고 어떻게 웹애플리케이션이 데이터를 받아올 수 있게 할까요? 우리는 API를 통해 다양한 데이터와 상호작용을 할 수 있습니다.

API는 Application Programming Interface의 약자입니다. 많은 유명 웹애플리케이션은 3rd party의 데이터를 가져와 그들의 서비스에 사용을 하고 있습니다. 여기서 말하는 Interface는 UI 또는 GUI와는 관련이 없습니다. interface는 property와 methods의 리스트를 의미합니다. 자세한 사항은 아래 유명 API 리스트 링크를 참고해 주세요.

Google's APIs Giant database of APIs


##### XHR Object 비동기 HTTP request를 보내기 위해 우리는 XMLHttpRequest 객체를 사용할 수 있습니다. XMLHttpRequest 객체에 대해서 다른 포스트에 조금 더 세부적으로 다루었기 때문에, 해당 글을 참고해주세요. [XMLHttpRequest 링크](https://chanwhekim.github.io/2018/09/25/xmlhttprequest/)
##### APIs and JSON API에서 HTML을 전달 받아 사용할 수 있지만, 데이터를 가공하고 사용하기에 쉽지는 않습니다. JSON을 사용하면 전달받은 데이터의 사용이 좀 더 수월해집니다. 아래와 같이 JSON.parse()를 이용해 자바스크립트 객체로 변환할 수 있습니다. ```javascript function handleSuccess() { const data = JSON.parse( this.responseText ); console.log(data); }; req.onload = handleSuccess; ```
##### setRequestHeader setRequestHeader 메서드는 HTTP request에 header를 포함하는 작업을 합니다. 아래에서 Unsplash의 API를 이용해 사진 검색 웹애플리케이션 만드는 단계를 설명하고자 합니다. 그러기 위해서 HTTP header를 추가하는 방법을 먼저 알아보겠습니다. ```javascript const searchedForText = 'hippos'; const unsplashRequest = new XMLHttpRequest();

unsplashRequest.open('GET', https://api.unsplash.com/search/photos?page=1&query=${searchedForText}); unsplashRequest.onload = addImage; unsplashRequest.setRequestHeader('Authorization', 'Client-ID '); unsplashRequest.send();

function addImage(){// do someting here};

<br>
##### Unsplash / NYT API를 이용한 웹애플리케이션 만들기
위에서 살펴본 API, XMLHttpRequest 객체를 이용해 사진과 기사를 검색해 보는 웹애플리케이션을 만들어 보도록 하겠습니다.

우선 Unsplash의 개발자 계정과 API를 발급받아야 합니다. 기사 검색을 위해서는 New York Times API를 받아야합니다.
Unsplash :
&nbsp;&nbsp;\- https://unsplash.com/developers
&nbsp;&nbsp;\- https://unsplash.com/oauth/applications
New York Times :
&nbsp;&nbsp;\- https://developer.nytimes.com/

우선 html은 아래와 같이 되어 있습니다. Ajax 관련 포스팅이기 때문에 html, css 관련해서는 설명을 생략하도록 하겠습니다.
```html
<body>
    <header class="masthead">
        <h1>What are you interested in today?</h1>

        <!-- 사진 검색을 위한 Form -->
        <div class="site-container">
            <form id="search-form" action="#">
                <label for="search-keyword" class="visuallyhidden">What are you interested in today?</label>
                <input id="search-keyword" type="text" name="search-keyword" placeholder="e.g. Android" required>
                <input id="submit-btn" type="submit" value="Submit">
            </form>
        </div>
    </header>

    <div class="site-container">
        <div id="response-container"></div>
    </div>

    <script src="app.js"></script>
</body>

앱 초기 시작을 위해 필요한 DOM 요소를 변수에 할당하고, 이후 사진과 기사를 추가할 html 요소의 innerHTML을 비웠습니다. 검색창에 'submit' 이벤트 리스너를 추가했습니다. 이벤트가 발생하면 해당 검색어를 이용해 unsplash에 사진을 요청하는 HTTP request를 발송합니다.

XHR이 성공적으로 이루어지면(onload 메서드 사용) addImage callback이 실행됩니다. Unsplash API는 HTTP request 시 header가 필요하기 때문에 setRequestHeader 메서드를 사용했습니다.

(function() {
  const form = document.querySelector('#search-form');
  const searchField = document.querySelector('#search-keyword');
  let searchedForText;
  const responseContainer = document.querSelector('#response-container');

  form.addEventListener('submit', function(e) {
    e.preventDefault();
    responseContainer.innerHTML = '';
    searchedForText = searchField.value;

    const imgRequest = new XMLHttpRequest();
    imgRequest.onload = addImage;
    imgRequest.onerror = function(err) {
      requestError(err, 'image');
    };

    imgRequest.open('GET', `https://api.unsplash.com/search/photos?page=1&query=${searchedForText}`);
    imgRequest.setRequestHeader('Authorization', 'Client-ID <이곳에 API key>');
    imgRequest.send();

    function addImage() {
      // Do something here
    }
  });
})();

HTTP request가 성공적으로 이루어 졌을때, unsplash API를 가져와 웹애플리케이션의 화면에 출력되도록 아래와 같이 함수를 작성할 수 있습니다.

function addImage() {
  let htmlContent;
  const data = JSON.parse(this.responseText);
  const firstImage = data.results[0];

  htmlContent = `
    <figure>
      <image src="${firstImage.urls.regular}" alt="${searchedForText}">
      <figcaption>${searchedForText} by ${firstImage.user.name}</figcaption>
    </figure>`;

  responseContainer.insertAdjacentHTML('afterbegin', htmlContent);
}

여기까지 코드를 작성하고 검색창에 검색어를 입력하면 웹브라우저에 사진이 출력되는 것을 확인할 수 있습니다.

다음으로 기사를 추가하기 위해서 뉴욕타임즈에 기사를 요청하는 XHR 객체를 작성했습니다.

const articleRequest = new XMLHttpRequest();
articleRequest.onload = addArticles;
articleRequest.onerror = function(err) {
  requestError(err, 'article');
};

articleRequest.open(
  'GET',
  `http://api.nytimes.com/svc/search/v2/articlesearch.json?q=${searchedForText}&api-key=<이곳에 API key>`
);
articleRequest.send();

function addArticles() {}

마지막으로 articleRequest가 성공적일시 실행할 함수는 아래와 같이 작성할 수 있습니다.

function addArticles() {
  let htmlContent;
  const data = JSON.parse(this.responseText);

  if(data.response && data.response.docs && data.response.docs.length > 1) {
    htmlContent = `<ul>` + data.response.docs.map(article =>
      `<li class="article">
          <h2><a href=${article.web_url}">${article.headline.main}</a></h2>
          <p>${article.snippet}</p>
      </li>`).join('') + `</ul>`;);
  } else {
    htmlContent = `<div class="error-no-articles">No articles available</div>`;
  }

  responseContainer.insertAdjacentHTML('beforeend', htmlContent);
}

위 예제는 Udacity의 Asynchronous JavaScript Requests 강좌 복습겸 작성했습니다. 강의에 관심있는 분은 www.udacity.com 을 참고해 주세요.

위 웹앱의 전체 코드를 보시고 싶으시면 아래 링크를 참조해 주세요. 링크