본문 바로가기

공부방/Upstage AI Lab 4기

7/19 학습일지 | 자바스크립트 깔짝, 외부 API로 데이터 가져오기

오늘 줌으로 한 실시간 강의에서는 자바스크립트로 웹에서 간단하게 뭔가를 표현하고 거기에 들어가는 함수나 필요한 동작을 파이썬으로 실행시켜서 그 결과를 웹에 보여주는(?) 법에 대해 공부했다. 자바스크립트 일도 모르는 상태에서 듣기 시작해서 그런지 꽤나 난이도가 높게 느껴졌고 머릿 속에 정리하 하나도 안된 느낌인데 일단 정리를 해보려고 한다. 


1. 자바 & 자바스크립트 (오늘 내가 깔짝댔던 건 자바스크립트)

자바와 자바스크립트는 다르다. 

  • 자바(Java): 주로 큰 규모의 애플리케이션(앱)이나 서버를 만들 때 사용. 예를 들어, 은행 시스템이나 안드로이드 앱을 만드는 데 자바를 많이 사용해.
  • 자바스크립트(JavaScript): 웹 페이지를 동적으로 만들기 위한 프로그래밍 언어. 웹 페이지를 더 생동감 있게 만들 때 사용해. 예를 들어, 버튼을 누르면 화면이 바뀌거나, 게임을 웹 페이지에서 할 수 있게 해주는 기능들이 자바스크립트로 만들어져. 

VS Code에서 html을 치면 html, html: 5, html: xml 이렇게 3가지가 뜨는데 일반적으로 웹 페이지를 만들 때는 'html:5'를 사용한다. 

  • html: 기본 HTML 문서 구조 생성.
  • html:5: 최신 HTML5 표준에 맞는 문서 구조 생성.
  • html: XML 문법에 맞춘 HTML 문서 구조 생성.

 

2. HTML의 구조

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
  • head: 문서의 정보(메타데이터), 스타일, 스크립트 등을 포함해.
  • body: 실제 웹 페이지에 표시될 콘텐츠를 포함해. 

 

3. HTML 파일 안에 자바스크립트 넣기

html 안에서 자바스크립트 코드를 쓰려면 <script> 태그를 사용한다.
일반적으로(기본적으로) 자바스크립트 코드는 head 태그 안에다가 집어넣는다.(라고 설명해주셨는데, 왜 이게 기본적인 건지는 잘 모르겠음.(?).) (이 방법은 자바스크립트가 HTML 문서가 로드되기 전에 실행되도록 하는 것! 주로 페이지의 메타데이터, 스타일시트, 외부 스크립트 파일을 포함시키기 위해 사용돼.)
body 태그 안에 넣을 수도 있는데, 그러면 HTML 문서의 콘텐츠가 모두 로드된 후에 자바스크립트가 실행된다. (주로 사용자와의 상호작용을 처리하는 스크립트를 작성할 때 사용돼)

* VS Code에서 라이브서버를 설치하면 html을 변경할 때마다 편하게 볼 수 있다.

 

4. 자바스크립트 문법

자바스크립트에서 함수 만들때 function 함수명(매개변수){ 내용 }
특정 이벤트가 발생했을 때 실행되는 코드는 보통 on으로 시작한다. 예를 들어서 onclick은 사용자가 요소를 클릭했을 때 실행된다. 

예시)

더보기
  • 버튼을 누르면 인사하기
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
            function goClick(){
            document.getElementById("SayHi").innerHTML=
            "<font color='blue'>HI~~~</font>";
        }
    </script>
</head>
<body>
    <button onclick="goClick()"> 클릭클릭 </button>
    <div id="SayHi"> 버튼을 누르면 인사합니다. </div>
</body>
</html>

<head> 안에서 
function goClick() : 이 부분은 함수를 선언하는 것. 함수 이름이 goClick 이다. 
document.getElementById("SayHi") : HTML 문서에서 ID가 "SayHi"인 요소를 선택.
.innerHTML: 선택된 요소의 innerHTML 속성을 "<font color='blue'>HI~~~</font>"로 설정

<body> 안에서
onclick은 버튼을 클릭하면 onclick 이벤트 핸들러 안에 있는 코드가 실행. 여기서는 goClick이 실행되는 것.
옆에 클릭클릭이라는 글자는 버튼 안에 새겨있는 글자를 말해.
<div>는 블록 레벨 요소로, 콘텐츠를 그룹화하고 스타일링하거나 레이아웃을 구성하는 데 사용. 이 경우에는 그냥 버튼 밑에 글자를 입력해주기 위해 작성됨("버튼을 누르면 인사합니다.")
<div>에 id="SayHi"가 들어있기 때문에, 버튼을 누르면, goClick 함수가 적용되면서 "SayHi" id 자리를 찾아 그 부분을 HI~~~ 로 바뀌는 함수가 실행된 것. 

 

  • 자바스크립트에서 JSON 문자열을 객체로 바꾸기

JSON: JSON은 JavaScript Object Notation의 약자로, 데이터를 저장하고 전송하는 데 사용되는 가볍고 쉽게 읽을 수 있는 데이터 형식.

JSON 객체

{
    "name": "meme",
    "color": "red",
    "mbti": "intj"
}


JSON 배열

[
    "red",
    "green",
    "blue"
]


JSON 문자열

const jsonString = '{"name":"meme", "color":"red", "mbti":"intj"}';

이렇게 문자열에 들어있는 것을 객체로 변환하고 속성에 접근하고 싶다면, JSON.parse() 함수를 사용하면 된다. 
문자열 -> 객체로 변환

            const jsonString='{"name":"meme", "color":"red", "mbti":"intj"}';
            const jsonObject=JSON.parse(jsonString);
            console.log(jsonObject.name);
            console.log(jsonObject.color);
            console.log(jsonObject.mbti);

반대로 객체를 문자열로 변환하려면

            const jo = {
                "name" : 'meme',
                "color" : 'red',
                "mbti" : "intj"
            };

            const js = JSON.stringify(jo);
            console.log(jo); //object
            console.log(js); //string

마지막으로 문자열 -> 객체로 바꾼 것을 활용해 표로 만들었다. tr은 table row(행), td는 table data(셀)

let html = '<table border="1">';
html += '<tr>'; // 첫 번째 행 시작
html += '<td>NAME</td>'; // 첫 번째 행의 첫 번째 셀
html += '<td>color</td>'; // 첫 번째 행의 두 번째 셀
html += '<td>mbti</td>'; // 첫 번째 행의 세 번째 셀
html += '</tr>'; // 첫 번째 행 끝
html += '<tr>'; // 두 번째 행 시작
html += '<td>' + jsonObject.name + '</td>'; // 두 번째 행의 첫 번째 셀
html += '<td>' + jsonObject.color + '</td>'; // 두 번째 행의 두 번째 셀
html += '<td>' + jsonObject.mbti + '</td>'; // 두 번째 행의 세 번째 셀
html += '</tr>'; // 두 번째 행 끝
html += '</table>'; // 표 끝
document.getElementById('msg').innerHTML = html; // 'msg' 요소에 표 삽입

 

5. 외부 API에서 데이터 가져와서 웹에 나타내기

더보기

fetch 함수: fetch 함수는 네트워크 요청을 보내고, Promise를 반환한다. 

Promise란?

Promise는 비동기 작업이 완료된 이후에 결과 값을 제공하거나 실패 이유를 제공하는 객체야. Promise는 다음과 같은 세 가지 상태를 가질 수 있어:

  1. Pending (대기): 초기 상태로, 아직 완료되지 않은 상태.
  2. Fulfilled (이행): 작업이 성공적으로 완료된 상태.
  3. Rejected (거부): 작업이 실패한 상태.

fetch 함수가 반환하는 Promise는 응답을 나타내는 Response 객체로 해결되거나, 네트워크 오류 등으로 인해 거부될 수 있어. 

첫 번째 then 블록: 네트워크 요청이 완료되면 응답(response)을 받아. response.json()을 호출하면 응답 본문을 JSON 형식으로 파싱하여 또 다른 Promise를 반환해.
두 번째 then 블록: 파싱된 JSON 데이터(json)를 받아서 처리해. 이 블록 안에서는 받은 JSON 데이터를 사용하여 HTML 표를 생성하고, 이를 웹 페이지에 삽입해.

            fetch('https://jsonplaceholder.typicode.com/todos/')
                .then(response => response.json())
                .then(json => {
                    let html = '<table border="1">';
                    html += '<tr>';
                    html += '<td>userId</td>';
                    html += '<td>id</td>';
                    html += '<td>title</td>';
                    html += '</tr>';

                    json.forEach(element => {
                        html += '<tr>';
                        html += '<td>' + element.userId + '</td>';
                        html += '<td>' + element.id + '</td>';
                        html += '<td>' + element.title + '</td>';
                        html += '</tr>';
                        
                    });

                    html += '</table>';
                    document.getElementById('msg').innerHTML = html;
                })
                .catch(error=console.log("Error:"+error));

Promise를 사용하는 이유

Promise는 비동기 작업의 결과를 처리하는 데 매우 유용해. 콜백(callback) 함수와 비교했을 때, Promise는 코드의 가독성을 높이고, 비동기 작업의 체인을 쉽게 만들 수 있어. 이는 비동기 작업이 순차적으로 또는 병렬로 수행될 때 특히 유용해.

동기/비동기 부분 아직 헷갈린다..

fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => console.log(json))

fetch는 URL에 가서 정보를 달라고 콜. 요청하는 것. 서버가 응답한 첫 번째 데이터를 then에서 받음. 원래 함수로 받아야 하는데, 함수(response) => 이건 람다식. 매개변수 response는 다른 이름으로 해도 되지만, 서버가 응답했다는 의미로 주로 response를 씀. 첨에 받을 때는 string으로 받음. 그렇게 받은 데이터를 json으로 바꿔주고(스트링이 오브젝트로 바뀜), 두 번째 then(json)으로 바꿔서 뒤에 원하는 걸로 바꿀 수 있음. (json.name 이런 식으로,,) 마지막 .then(json => {  함수 } 이렇게 해서 그 안에 표를 만들어주거나 원하는 동작을 시킬 수도 있음. 

연습용 데이터를 제공해 준 서버: 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

 

6. 웹에서 숫자 2개를 받은 뒤에 파이썬으로 계산하고 그 값을 웹에 표시하기

챗지피티랑 오류난 걸 가지고 계속 씨름하느라 엄청나게 오래 걸렸던 작업.. 챗지피티야... 포트 오류라며.... 아니였짜나....

HTML로 이렇게 숫자 2개를 받은 입력받은 뒤에, 파이썬에서 이 숫자를 받아 더한다.
submit을 누르면 파이썬이 계산한 결과값이 나오는 것! 

입력 전과 입력 후

이전에 참고한 실습 예제 코드를 많이 참고해서 만들었다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calculate</title>
</head>
<body>
    <h1>Add numbers!</h1>
    <form id="numberForm">
        <label for="number1">Number 1:</label>
        <input type="number" id="number1" name="number1"><br><br>

        <label for="number2">Number 2:</label>
        <input type="number" id="number2" name="number2"><br><br>

        <input type="submit" value="Submit">
    </form>
    <p id="result"></p>

    <script>
        document.getElementById('numberForm').addEventListener('submit', async (event) => {
            event.preventDefault();
            const number1 = document.getElementById('number1').value;
            const number2 = document.getElementById('number2').value;

            const response = await fetch('http://127.0.0.1:5555/add', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    number1: number1,
                    number2: number2
                })
            });

            const result = await response.json();
            document.getElementById('result').textContent = 
            `The result of adding ${number1} and ${number2} is ${result.sum}`;
        });
    </script>
</body>
</html>

 첨에 잘 작동하지 않았다. 숫자가 입력된 뒤에 페이지 새로고침이 되기 때문이였던 것 같다. 폼이 제출될 때 기본 동작은 페이지를 새로고침하는 것이라고. 그래서 새로고침을 막고 서버에 '비동기적'으로 데이터를 보내는 작업이 필요. 그래서 여기서 핵심(?)은

document.getElementById('numberForm').addEventListener('submit', async (event) => { event.preventDefault()

이 코드가 중요했던 것!

그리고 처음에는 fetch 정보도 const response = await fetch('/add') 이렇게만 입력했었는데, 실행이 안됐다. const response = await fetch('http://127.0.0.1:5555/add'); 이렇게 서버의 주소와 포트를 명시적으로 지정해야 실행이 잘 됐다. 이 포트 정보는 파이썬에서 실행되는 포트를 보고 입력했었다. 

from flask import Flask, request, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route('/add', methods=['POST'])

def add():
    data = request.get_json()
    number1 = int(data['number1'])
    number2 = int(data['number2'])
    result = number1 + number2
    return jsonify({'sum': result})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5555)

그리고 파이썬에서 실행할때마다 오류가 나서 포트가 잘못된 건 줄 알고 온갖 포트 번호를 다 써보고, 강제로 포트에 할당된 PID를 찾아 종료도 하고 노트북을 껐다가 키기도 했는데. 결국 안되다가 찾은 게. 마지막에 써있는 이 문구. 이걸 지우니까 실행됨.. 

if __name__ == '__main__':
    app.run(debug=True)

이게 있을 때 떴던 에러를 보니, 디버그 모드 온이라고 되어 있다. 

* Serving Flask app '__main__' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5001 Press CTRL+C to quit * Restarting with stat Traceback (most recent call last):

현재 잘 실행되는 상태에서는 디버그 모드 오프.. 

debug=True 만 넣으면 다시 오류가 뜬다. ㅎㅎㅎㅎㅎㅎ 왜 그런지는 모르겠지만, 일단 해결은 했으니!!!!

이제 자자