본문 바로가기

Front End/Javascript

[JavaScript] Fetch API 사용해보기

fatch() 함수가 어떤 역활을 하는지 알아보기 전에 일단 예제 하나를 만들어 보고 시작 하겠습니다. 

다음은 fatch()를 이용하여 이미지를 받아 화면에 표시한 예제 입니다.

 

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch 예제</title>
    <script>
        window.onload = () => {
            const img = document.querySelector("img");
            fetch(img_url)
                .then((response) => {
                    if (!response.ok) {
                        throw new Error(`HTTP error, status = ${response.status}`);
                    }
                    console.log(response);
                    return response.blob();
                })
                .then((blob) => {
                    const objectURL = URL.createObjectURL(blob);
                    img.src = objectURL;
                })
                .catch((error) => {
                    const p = document.createElement("p");
                    p.appendChild(document.createTextNode(`Error: ${error.message}`));
                    document.body.insertBefore(p, myImage);
                });
        }
    </script>
    <style>
        figure {
            width: 350px;
            text-align: center;
            font-style: italic;
            font-size: smaller;
            text-indent: 0;
            border: thin silver solid;
            margin: 0.5em;
            padding: 0.5em;
        }
    </style>
</head>

<body>
    <figure>
        <img src="" class="img" />
        <figcaption>
            <a href='https://www.pexels.com/ko-kr/photo/669015/'>Pexels Septimiu Lupea님의 사진</a>
        </figcaption>
    </figure>
</body>

</html>

 

F12키를 눌러 개발자 모드의 console 창을 열어 확인한 내용입니다.

 

이미지 하단에 다운로드하는 링크를 달아보겠습니다.

위 html 파일을 수정합니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch 예제</title>
    <script>
        window.onload = () => {
            const img = document.querySelector("img");
            fetch(img_url)
                .then((response) => {
                    if (!response.ok) {
                        throw new Error(`HTTP error, status = ${response.status}`);
                    }
                    console.log(response);
                    return response.blob();
                })
                .then((blob) => {
                    const objectURL = URL.createObjectURL(blob);
                    img.src = objectURL;
                    //================================================================
                    // 추가
                    //-----------------------------------------------------------------------------------------------------------------
                    // 'a' 요소를 생성하여 link라는 이름의 상수에 할당 (이 요소는 다운로드 링크를 나타냄)
                    const link = document.createElement('a');
                    // 'a' 요소의 href 속성을 다운로드할 URL인 objectURL 설정
                    link.href = objectURL;
                    // 'a' 요소의 download 속성을 설정하여 파일 이름을 지정
                    link.setAttribute('download', 'pexels-photo-669015.jpg');
                    link.innerHTML = '이미지다운로드'
                    // 'a' 요소를 문서의 본문(body)에 추가
                    document.body.appendChild(link);
                    //=================================================================                   
                })
                .catch((error) => {
                    const p = document.createElement("p");
                    p.appendChild(document.createTextNode(`Error: ${error.message}`));
                    document.body.insertBefore(p, myImage);
                });
        }
    </script>
    <style>
        figure {
            width: 350px;
            text-align: center;
            font-style: italic;
            font-size: smaller;
            text-indent: 0;
            border: thin silver solid;
            margin: 0.5em;
            padding: 0.5em;
        }
    </style>
</head>

<body>
    <figure>
        <img src="" class="img" />
        <figcaption>
            <a href='https://www.pexels.com/ko-kr/photo/669015/'>Pexels Septimiu Lupea님의 사진</a>
        </figcaption>
    </figure>
</body>

</html>

 

다운로드 링크가 생겼으며 클릭시 다운로드 되는것을 확인할 수 있습니다.

 

어떻게 보셨나요 재미있을것 같지요 자세하게 알아보도록 하겠습니다.

 

비동기식으로 원격의 서버에 데이터를 요청하여 처리하는 Ajax (Asynchronous JavaScript and XML, 에이잭스) 기능을 지금까지는 XMLHttpRequest 객체를 사용해 왔었습니다.

fetch 함수는  XMLHttpRequest에 대한 보다 강력하고 유연한  HTTP 요청 전송 기능을 제공하는 최신의 Web API  입니다.

 

fetch 함수는 비동기적으로 작동하며 HTTP response 객체를 래핑한 Promise 객체를 반환합니다. 앞서 배운 Promise 처리 방법을 이용하여 받아온 데이터를 처리해야 합니다.

fetch(url, option)
.then((response)=>{
       // 데이터 처리
})
.catch((err)=>{
      // 에러 처리
})

 

무료로 가짜 API를 사용할 수 있어 각종 테스트를 진행할 수 있는 JSONPlaceholder를 이용하여 실습을 진행 하도록 하겠습니다.

https://jsonplaceholder.typicode.com

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake and reliable API for testing and prototyping. Powered by JSON Server + LowDB. Serving ~3 billion requests each month.

jsonplaceholder.typicode.com

 

간단하게 글 하나를 읽어와 보겠습니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch 예제</title>
    <script>
        window.onload = () => {
            const url = "https://jsonplaceholder.typicode.com/posts/1";
            fetch(url)
                .then((response) => {
                    console.log(response);
                    return response.json();
                })
                .then((jsonData) => {
                    console.log(JSON.stringify(jsonData));
                })
                .catch((error) => {
                    console.log(error);
                });
        }
    </script>
</head>

<body>
</body>

</html>

 

F12키를 눌러 개발자 모드를 열고 Console 탭을 확인하면 실행 결과를 볼 수 있습니다.

Response 객체를 리턴해 줍니다. 상태코드가 200이고 ok가 true로서 올바른 응답을 혹인할 수 있습니다.

response.json() 함수를 이용하여 받은 데이터를 JSON 형식으로 가져옵니다. json()메서드도 Promise 객체를 반환합니다. 그래서 then()으로 받았습니다.

 

존재하지 않는 url 주소로 접근하면 다음과 같은 에러가 발생합니다.

 

 

HTTP 메서드란 서버와 클라이언트 간에 이루어지는 요청(Request)과 응답(Response) 데이터를 전송하는 방식을 일컫는용어입니다.  서버에 있는 리소스에  처리 해야 할 행동을 지정하여 요청을 보내는 방법입니다. fetch 함수에 요청 메서드를 지정하지 않으면 기본적으로 요청은 GET방식으로 처리 됩니다.

 

HTTP 메소드의 종류는 총 9가지가 존재하는데  주로 쓰이는 메소드는 5가지로 보시면 됩니다.

주요 메소드

  • GET : 리소스 조회하는 메서드로 데이터를 얻어올 때 사용합니다.
  • POST:  요청 데이터 처리하는 메서드로 주로 데이터 저장할 때 사용합니다.
  • PUT : 리소스를 대체하는 메서드로 주로 수정할 때 사용합니다. 해당 리소스가 없으면 생성합니다.
  • PATCH : 리소스 일부분 변경하는 메서드입니다. (PUT이 전체 변경, PATCH는 일부 변경)
  • DELETE : 리소스 삭제하는 메서드 입니다.

기타 메소드

  • HEAD : GET과 동일하지만 메시지 부분(body 부분)을 제외하고, 상태 줄과 헤더만 반환합니다.
  • OPTIONS : 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명(주로 CORS에서 사용)합니다.
  • CONNECT : 대상 자원으로 식별되는 서버에 대한 터널을 설정합니다.
  • TRACE : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행 합니다.

 

 

JSON 데이터가 아닌 데이터도 얼마든지 요청이 가능합니다. 첫번째 예제에서 보았듯이 이미지도 요청이 가능합니다. 다음은 Text형식의 데이터 처리를 해보도록 하겠습니다. 회원 약관, 개인보호 정책 등 대량의 데이터를 읽어와 표시할때 편리하게 사용하시면 됩니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch 예제</title>
    <script>
        function fileRead(no) {
            let url = `./data/text${no}.txt`;
            fetch(url)
                .then((response) => {
                    return response.text();
                })
                .then((content) => {
                    console.log(content);
                    // document.querySelector("#content").innerText = content;
                    document.querySelector("#content").innerHTML = content;
                })
                .catch((error) => {
                    console.log(error);
                });
        }
    </script>
</head>

<body>
    <button onclick="fileRead(1)"> 파일 읽기 1</button>
    <button onclick="fileRead(2)"> 파일 읽기 2</button>
    <button onclick="fileRead(3)"> 파일 읽기 3</button>
    <hr>
    <div id="content"></div>
</body>

</html>

 

Data 폴더를 만들고 다음의 파일 3개를 넣어 둡니다.  파일의 내용은 아무의미 없는 문구입니다. text3.txt 파일에는 html태그를 2개 적용시켜 보았습니다.

text1.txt
0.00MB
text2.txt
0.00MB
text3.txt
0.00MB

 

response.text() : 받아온 리소스를 Text형식으로 변환해주는 메서드 입니다. 

내용을 Text나 Html 형식으로 넣을 수 있습니다.

Text 형식으로 넣기                   
document.querySelector("CSS선택자").innerText = 넣을 내용;

HTML형식으로 넣기
document.querySelector(" CSS선택자 ").innerHTML = 넣을 내용 ;

 

 

My JSON Server 만들어 보기

다음을 이용하여 나만의 서버를 만들어 처리해 보도록 하겠습니다.

https://my-json-server.typicode.com/

 

My JSON Server - Fake online REST server for teams

my-json-server.typicode.com/user/repo/posts/1 { "id": 1, "title": "hello" }

my-json-server.typicode.com

 

1. github.com에 회원 가입을 합니다.

2. 저장소(repository)를 하나 만듭니다.

3. 저장소에 db.json 파일을 다음과 같이 만듭니다.

{
    "comments": [
        {
            "id": 1,
            "name": "kimc",
            "content": "우와 일등이다."
        },
        {
            "id": 2,
            "name": "leec",
            "content": "우와 이등이다."
        }
    ],
    "names": [
        {
            "name": "주인장"
        },
        {
            "name": "나그네"
        },
        {
            "name": "지나는이"
        },
        {
            "name": "떠돌이"
        }
    ]
}

 

4. 나의 서버 주소는 다음과 같이 됩니다.  https://my-json-server.typicode.com/Git아이디/저장소이름/

 

My JSON Server - Fake online REST server for teams

my-json-server.typicode.com/user/repo/posts/1 { "id": 1, "title": "hello" }

my-json-server.typicode.com

 

다음과 같은 Endpoint가 생성이 됩니다.

 

객체에 id필드가 존재하는 경우 다음의 Endpoint가 생성이 됩니다.

GET           /comments
GET           /comments /:id
POST        /comments
PUT           /comments /:id
PATCH      /comments /:id
DELETE   /comments /:id

 

객체에 id필드가 존재하지 않는 경우 다음의 Endpoint가 생성이 됩니다.

GET       /names
PUT       /names
PATCH  /names

 

API를 테스트 할 수 있는 다음의 사이트를 방문하여 다운로드 후 설치를 하고 회원 가입을 하면 테스트 할 수 있습니다.

 

https://www.postman.com/downloads/

 

Download Postman | Get Started for Free

Try Postman for free! Join 35 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.

www.postman.com

테스트 하는 화면 입니다.

 

이렇게 만든 서버는 저장 삭제 요청이 처리만 되지 실제 데이터는 변화가 없습니다. 데이터의 변화를 직접 확인 하시려면 로컬에 JSON-Server를 설치 하시면 됩니다.

설치 방법은 여기를 참조하세요!!!  [JavaScript] JSON-SERVER 사용해 보기

 

[JavaScript] JSON-SERVER 사용해 보기

json-server란?JSON Server는 JSON 파일을 이용해 모의용 RESTful API 서버 및 DB를 구축할 수 있는 도구입니다.백엔드 API 서버나 DB가 준비되지 않은 상황에서도 프로토타입을 개발하거나 테스트

101developer.tistory.com

 

 

 

자바스크립트의 fetch 함수를 이용하여 접속해 보도록 하겠습니다.

 

조회 : GET방식의 요청입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch GET 요청 예제</title>
    <script>
        window.onload = () => {
            .then((response) =>{
                console.log(response);
                // 데이터를 JSON으로 반환
                return response.json();
            }).then((json)=>{
                console.log(JSON.stringify(json));
                // ul태그 작성
                let mylist = document.createElement('ul');
                for(let comment of json){
                    console.log(JSON.stringify(comment));
                    let li = document.createElement('li');
                    // li태그에 내용 추가
                    li.textContent = `${comment.name} : ${comment.content}`;
                    // ul태그에 자식으로 추가
                    mylist.appendChild(li);
                }
                // ul태그를 body에 자식으로 추가
                document.body.appendChild(mylist);
            });
        }
    </script>
</head>
<body>
</body>
</html>

 

실행 화면 입니다.

 

저장 : POST 요청입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch POST 요청 예제</title>
    <script>
        let id=2;
        window.onload = () => {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    id : ++id,
                    name: "leec",
                    content: "우와 3등이다.",
                }),                
            })
            .then((response) =>{
                console.log(response);
                // 데이터를 JSON으로 반환
                return response.json();
            }).then((json)=>{
                // ul태그 작성
                let mylist = document.createElement('ul');
                // JSON요소 반복
                for(let key in json){
                    // li태그 작성
                    let li = document.createElement('li');
                    // li태그에 내용 추가
                    li.textContent = `${key} : ${json[key]}`;
                    // ul태그에 자식으로 추가
                    mylist.appendChild(li);
                }
                // ul태그를 body에 자식으로 추가
                document.body.appendChild(mylist);
                console.log('저장이 완료되었습니다.')
            });
        }
    </script>
</head>
<body>
</body>
</html>

 

저장 완료 확인이 가능합니다. 

 

Response 객체의 상태 코드를 보면 GET 요청에 200 OK 응답과  POST 요청에 201 Created 임을 확인 가능합니다.

200 OK는 일반적으로 요청(Request)을 서버가 처리를 성공적으로 완료했을 때 사용되며, 클라이언트가 요청한 데이터(자원)을 응답이 담아 보내는 경우가 있습니다. 요청에 대해 성공적으로 처리를 했을 때 제일 보편적으로 사용되는 응답 코드입니다.
 
201 Created는 요청(Request)을 서버에서 처리를 성공적으로 완료했으며, 새로운 resource가 성공적으로 생성이 되었을 때 사용됩니다. 응답은 일반적으로 resource가 새롭게 생성된 위치를 포함하고 있습니다.
 
이 둘의 차이점은 200은 이미 존재하는 resource에 대한 요청을 성공적으로 처리했을 때 주로 사용되며, 201은 새로운 resource를 생성하는데에 성공했을 때 사용됩니다.
 
200은 제일 보편적으로 사용되는 성공 응답 코드이기 때문에, 요청받은 HTTP method의 종류에 구애받지 않고 사용되는 경우가 많습니다.
반면 201은 RESTful API의 관점에서 주로 새로운 entity가 생성되는POST 요청에 대한 응답 코드로 많이 사용됩니다.

 

 

전체 수정 : PUT 요청입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch PUT 요청 예제</title>
    <script>
        window.onload = () => {
                method: "PUT",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    name: "바뀐사람",
                    content: "오늘은 이빠다~~~~~",
                }),                
            })
            .then((response) =>{
                console.log(response);
                // 데이터를 JSON으로 반환
                return response.json();
            }).then((json)=>{
                // ul태그 작성
                let mylist = document.createElement('ul');
                // JSON요소 반복
                for(let key in json){
                    // li태그 작성
                    let li = document.createElement('li');
                    // li태그에 내용 추가
                    li.textContent = `${key} : ${json[key]}`;
                    // ul태그에 자식으로 추가
                    mylist.appendChild(li);
                }
                // ul태그를 body에 자식으로 추가
                document.body.appendChild(mylist);
                console.log('수정이 완료되었습니다.')
            });
        }
    </script>
</head>
<body>
</body>
</html>

 

 

 

일부 수정 : PATCH 요청입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch PATCH 요청 예제</title>
    <script>
        window.onload = () => {
                method: "PATCH",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    name: "바뀐사람",
                }),                
            })
            .then((response) =>{
                console.log(response);
                // 데이터를 JSON으로 반환
                return response.json();
            }).then((json)=>{
                // ul태그 작성
                let mylist = document.createElement('ul');
                // JSON요소 반복
                for(let key in json){
                    // li태그 작성
                    let li = document.createElement('li');
                    // li태그에 내용 추가
                    li.textContent = `${key} : ${json[key]}`;
                    // ul태그에 자식으로 추가
                    mylist.appendChild(li);
                }
                // ul태그를 body에 자식으로 추가
                document.body.appendChild(mylist);
                console.log('수정이 완료되었습니다.')
            });
        }
    </script>
</head>
<body>
</body>
</html>

 

 

 

삭제 : DELETE 요청입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch DELETE 요청 예제</title>
    <script>
        window.onload = () => {
                method: "DELETE"          
            })
            .then((response) =>{
                console.log(response);
                console.log('삭제 완료되었습니다.')
            });
        }
    </script>
</head>
<body>
</body>
</html>

 

 

POST/PUT/PATCH는 정보를 서버로 보내야 하기 떄문에 옵션에 "header" 와 "body" 속성이 반드시 있어야 합니다.

 "header"에서 지정한 데이터 형식과  "body" 에서 보내는 데이터 형식이 일치해야만 합니다. 주로 JSON 형식을 사용합니다.

 

그때 그때 작성하기가 귀찮으면 다음과 같이 함수를 만들어 사용해도 됩니다.

        async function myFetch(url = "", method = "GET", data = {}) {
            let option =  {
                method: method,     // *GET, POST, PUT, DELETE 등
                mode: "cors",       // no-cors, *cors, same-origin
                cache: "no-cache",  // *default, no-cache, reload, force-cache, only-if-cached
                credentials: "same-origin", // include, *same-origin, omit
                headers: {
                    "Content-Type": "application/json",
                    // 'Content-Type': 'application/x-www-form-urlencoded',
                },
                // manual, *follow, error
                redirect: "follow",
                // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin,
                // same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                referrerPolicy: "no-referrer",
            };
            // GET 방식이 아닐 경우에만 보내는 데이터가 있다.
            if(method!=='GET'){
                option.body =  JSON.stringify(data); // body의 데이터 유형은 반드시 "Content-Type" 헤더와 일치해야 함
            }
            const response = await fetch(url, option);
            const json = await response.json();
            return json; // JSON 응답을 네이티브 JavaScript 객체로 파싱
        }

       
        // GET : 읽기
        myFetch("https://jsonplaceholder.typicode.com/posts/1", 'GET')

        // POST : 저장
        myFetch("https://jsonplaceholder.typicode.com/posts", 'POST', {
            userId: 1,
            title: "Test",
            body: "I am testing!",
        })

        // PUT : 전체 수정
        myFetch("https://jsonplaceholder.typicode.com/posts/1", 'PUT', {
            id: 1,
            userId: 1,
            title: "변경제목",
            body: "내용을 변경합니다.",
        })

        // PATCH : 일부분 수정
        myFetch("https://jsonplaceholder.typicode.com/posts/2", 'PATCH', {
            title: "제목을 변경했습니다.",
            body : "내용을 변경했습니다."
        })

        // DELETE : 삭제
        myFetch("https://jsonplaceholder.typicode.com/posts/3", 'DELETE',{})

 

전체 테스트 코드 입니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>myFetch  요청 예제</title>
    <script>
        async function myFetch(url = "", method = "GET", data = {}) {
            let option =  {
                method: method,     // *GET, POST, PUT, DELETE 등
                mode: "cors",       // no-cors, *cors, same-origin
                cache: "no-cache",  // *default, no-cache, reload, force-cache, only-if-cached
                credentials: "same-origin", // include, *same-origin, omit
                headers: {
                    "Content-Type": "application/json",
                    // 'Content-Type': 'application/x-www-form-urlencoded',
                },
                // manual, *follow, error
                redirect: "follow",
                // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin,
                // same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                referrerPolicy: "no-referrer",
            };
            // GET 방식이 아닐 경우에만 보내는 데이터가 있다.
            if(method!=='GET'){
                option.body =  JSON.stringify(data); // body의 데이터 유형은 반드시 "Content-Type" 헤더와 일치해야 함
            }
            const response = await fetch(url, option);
            const json = await response.json();
            return json; // JSON 응답을 네이티브 JavaScript 객체로 파싱
        }

        // GET : 읽기
        myFetch("https://jsonplaceholder.typicode.com/posts/1", 'GET')
            .then((data) => {
                console.log(JSON.stringify(data));
                document.querySelector('body').innerHTML += JSON.stringify(data);
            })
            .finally(() => {
                console.log('데이터 읽기를 완료했습니다.');
            });
        // POST : 저장
        myFetch("https://jsonplaceholder.typicode.com/posts", 'POST', {
            userId: 1,
            title: "Test",
            body: "I am testing!",
        }).then((data) => {
            console.log(`데이터 저장 완료!!! : ${JSON.stringify(data)}`);
        });
        // PUT : 전체 수정
        myFetch("https://jsonplaceholder.typicode.com/posts/1", 'PUT', {
            id: 1,
            userId: 1,
            title: "변경제목",
            body: "내용을 변경합니다.",
        }).then((data) => {
            console.log(`데이터 수정 완료!!! : ${JSON.stringify(data)}`);
        });

        // PATCH : 일부분 수정
        myFetch("https://jsonplaceholder.typicode.com/posts/2", 'PATCH', {
            title: "제목을 변경했습니다.",
            body : "내용을 변경했습니다."
        }).then((data) => {
            console.log(`일부분 수정 완료!!! : ${JSON.stringify(data)}`);
        });

        // DELETE : 삭제
        myFetch("https://jsonplaceholder.typicode.com/posts/3", 'DELETE',{})
        .then((data) => {
            console.log(`삭제 완료!!! : ${JSON.stringify(data)}`);
        });
    </script>
</head>
<body>
</body>
</html>

 

'Front End > Javascript' 카테고리의 다른 글

[JavaScript] SPA/MPA & SSR/CSR  (5) 2024.11.12
[JavaScript] Axios 사용해 보기  (4) 2024.11.08
[JavaScript] JSON-SERVER 사용해 보기  (4) 2024.11.07
[JavaScript] Async & Await 알아보기  (7) 2024.11.07
[JavaScript] Promise란?  (0) 2024.11.06