Fetch를 사용하여 멋진 JS API 인터페이스 만들기(50줄 미만)

이 튜토리얼에서는 50줄 미만의 코드로 모든 API 호출을 수행할 수 있는 재사용 가능한 단일 모듈을 만들 것입니다! (Jump to final module code here) . fetch API에 익숙하다면 모든 Promise 체인에서 보기 흉하고 읽을 수 없는 것처럼 보일 수 있습니다.

fetch(url)
  .then((response) => response.json())
  .then(data => {
    console.dir(data);
  });
})


어. 앱의 모든 API 호출에 대해 그렇게 하고 싶지는 않습니다. 우리는 이것을 모듈로 추상화하여 당신의 호출이 더 읽기 쉽고 만들기 쉽도록 해야 합니다. API 호출은 다음과 같습니다.

async function getArticles(userId) {
  const articles = await Fetch.get('/articles/' + userId);
  articles.forEach(item => {
   // iterate through results here...
  });
}


이 튜토리얼에서는 ES6 모듈을 사용할 것입니다. 갑시다! (sync 및 await 키워드에 유의하십시오).

Fetch.js 모듈 스켈레톤 만들기



먼저 모듈과 상호 작용하고 API 호스트를 정의하는 데 사용할 공개 CRUD 메서드를 정의하겠습니다.

// Fetch.js
const _apiHost = 'https://api.service.com/v1';

export default {
  get,
  create,
  update,
  remove
};


기본 가져오기 메서드 만들기



다음으로 실제 가져오기를 수행하는 모듈 내부의 private 메서드를 만들어 보겠습니다. 이 범용 메서드는 읽기 및 쓰기 API 호출을 모두 처리할 수 있어야 합니다. 우리의 방법은 3개의 인수를 취할 것입니다:

  • url - API 엔드포인트 - 예: '/articles'

  • params - POST, UPDATE 및 DELETE 호출에서 GET에 대한 쿼리 문자열 또는 요청 본문에 대한 데이터로 엔드포인트에 전달할 추가 매개변수

  • 메소드 - GET(기본값), POST, PUT, DELETE

  • // Fetch.js
    // ...
    
    async function request(url, params, method = 'GET') {
    
    }
    
    // ...
    


    함수 시작 부분에 있는 async에 주목하십시오. Promises 을 다룰 것이기 때문에 이것이 필요합니다.

    옵션을 추가하고 "await"를 사용해야 합니다.




    // Fetch.js
    const _apiHost = 'https://api.service.com/v1';
    
    async function request(url, params, method = 'GET') {
    
      // options passed to the fetch request
      const options = {
        method
      };
    
      // fetch returns a promise, so we add keyword await to wait until the promise settles
      const response = await fetch(_apiHost + url, options);
      const result = await response.json(); // convert response into JSON
    
      // returns a single Promise object
      return result;
    
    }
    
    // ...
    


    모든 요청 유형에 대한 매개변수 처리



    우리는 이 메소드가 API 요청의 일부로 포함되어야 할 수 있는 모든 매개변수를 처리할 수 있기를 원합니다. GET 요청의 경우 쿼리 문자열을 지원해야 합니다. 다른 모든 쓰기 관련 요청의 경우 요청에 본문을 포함할 수 있어야 합니다.

    우리는 모듈을 사용하기 매우 쉽게 하기를 원하므로 모든 경우에 대해 객체 처리를 표준화하겠습니다. 그런 다음 개체를 GET 요청에 대한 쿼리 문자열로 변환하고 다른 모든 유형에 대한 요청 본문의 일부로 개체를 JSON으로 포함할 수 있습니다.

    쿼리 문자열 변환 방법에 대한 개체를 만들어 보겠습니다.

    // Fetch.js
    
    // ...
    
    // converts an object into a query string
    // ex: {authorId : 'abc123'} -> &authorId=abc123
    function objectToQueryString(obj) {
      return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
    }
    
    // ...
    


    이제 매개변수가 있는 경우 이를 처리하는 코드를 추가할 수 있습니다. 요청 메서드의 옵션 정의 바로 뒤에 이것을 추가해 보겠습니다.

    // Fetch.js
    const _apiHost = 'https://api.service.com/v1';
    
    async function request(url, params, method = 'GET') {
    
      const options = {
        method,
        headers: {
          'Content-Type': 'application/json' // we will be sending JSON
        }
      };
    
      // if params exists and method is GET, add query string to url
      // otherwise, just add params as a "body" property to the options object
      if (params) {
        if (method === 'GET') {
          url += '?' + objectToQueryString(params);
        } else {
          options.body = JSON.stringify(params); // body should match Content-Type in headers option
        }
      }
    
      const response = await fetch(_apiHost + url, options);
      const result = await response.json();
    
      return result;
    
    }
    
    function objectToQueryString(obj) {
      return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
    }
    
    // ...
    


    공개 메서드 만들기



    훌륭한! 이제 서로 다른 요청을 수행하는 데 사용할 수 있는 네 가지 공용 메서드를 만들어 보겠습니다. 모듈 맨 아래에 있는 이 네 가지 메서드를 참조하는 단일 개체를 내보냅니다.

    // Fetch.js
    // ...
    function get(url, params) {
      return request(url, params);
    }
    
    function create(url, params) {
      return request(url, params, 'POST');
    }
    
     function update(url, params) {
      return request(url, params, 'PUT');
    }
    
    function remove(url, params) {
      return request(url, params, 'DELETE');
    }
    


    오류 처리



    모듈에 오류 처리를 추가하는 것이 좋습니다. 한 가지 방법은 응답의 상태 코드를 확인하는 것입니다. 200이 아니면 일종의 오류 메시지를 반환해야 합니다.

    원하는 방식으로 오류를 처리할 수 있습니다. 이 예에서는 상태 및 메시지가 포함된 개체를 반환합니다. 가져오기 요청 직후 상태를 확인해 보겠습니다.

    // Fetch.js
    
    // ...
    
      const response = await fetch(_apiHost + url, options);
    
      // show an error if the status code is not 200
      if (response.status !== 200) {
        return generateErrorResponse('The server responded with an unexpected status.');
      }
    
      const result = await response.json();
    
      return result;
    
    }
    
    // A generic error handler that just returns an object with status=error and message
    function generateErrorResponse(message) {
      return {
        status : 'error',
        message
      };
    }
    


    우리는 해냈다!



    이제 단일 모듈을 사용하여 네 가지 유형의 API 요청을 모두 만들 수 있습니다!

    비동기/대기



    Fetch.AI 호출은 단일 약속을 반환하므로 호출 앞에 await 키워드를 사용해야 합니다. 또한 await 키워드는 최상위 코드에서 작동하지 않으므로 비동기 함수 내부에 래핑되어야 합니다. 이러한 요청은 다음과 같습니다.

    import Fetch from './Fetch.js';
    
    // GET
    async function getAllBooks() {
      const books = await Fetch.get('/books');
    }
    
    // POST
    async function createBook() {
      const request = await Fetch.create('/books', {
        title: 'Code and Other Laws of Cyberspace',
        author: 'Lawrence Lessig'
      });
    }
    
    // PUT
    async function updateBook(bookId) {
      const request = await Fetch.update('/books/' + bookId, {
        title: 'How to Live on Mars',
        author: 'Elon Musk'
      });
    }
    
    // DELETE
    async function removeBook(bookId) {
      const request = await Fetch.remove('/books/' + bookId);
    }
    


    완성된 API 인터페이스 모듈! - 다음 단계

    I hope that you enjoyed this tutorial and that you can use it to become more productive!

    You can add all sorts of other options to this module and in the fetch request itself. For example, what parameters would you add to the fetch method to support CORS requests?

    How would you handle file uploads?

    해피 페칭!




    // Fetch.js
    const _apiHost = 'https://api.service.com/v1';
    
    async function request(url, params, method = 'GET') {
    
      const options = {
        method,
        headers: {
          'Content-Type': 'application/json'
        }
      };
    
      if (params) {
        if (method === 'GET') {
          url += '?' + objectToQueryString(params);
        } else {
          options.body = JSON.stringify(params);
        }
      }
    
      const response = await fetch(_apiHost + url, options);
    
      if (response.status !== 200) {
        return generateErrorResponse('The server responded with an unexpected status.');
      }
    
      const result = await response.json();
    
      return result;
    
    }
    
    function objectToQueryString(obj) {
      return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
    }
    
    function generateErrorResponse(message) {
      return {
        status : 'error',
        message
      };
    }
    
    function get(url, params) {
      return request(url, params);
    }
    
    function create(url, params) {
      return request(url, params, 'POST');
    }
    
     function update(url, params) {
      return request(url, params, 'PUT');
    }
    
    function remove(url, params) {
      return request(url, params, 'DELETE');
    }
    
    export default {
      get,
      create,
      update,
      remove
    };
    
    

    좋은 웹페이지 즐겨찾기