Web APIs

여기서는 웹사이트 구축에 꼭 필요한 Web API들 몇가지 간략히 소개합니다. 이 부분은 html과 css, JavaScript에 관해 상당한 수준의 이해가 전제됩니다..

Web API는 한 컴퓨터의 앱이 다른 컴퓨터의 앱과 상호작용할 수 있도록 한 일련의 규약이다: 클라이언트는 웹서버에 필요한 데이터를 요청하고, 해당 요청은 HTTP를 통해 웹서버 앱으로 이동하며, 웹서버는 요청에 따라 데이터를 처리하여 그 결과물을 다시 HTTP를 통해 클라이언트 측으로 보낸다

곧, Web API는 데이터가 데이터베이스에서 애플리케이션으로 흐르는 인터페이스를 제공하는 역할을 한다!

국제화 API

Intl 객체에는 여러 생성자와 국제화 생성자 및 기타 언어에 민감한 함수에 공통된 기능이 포함되어 있는데, 이를 종합하여 언어에 민감한 문자열 비교, 숫자 서식, 날짜 및 시간 서식 등을 제공하는 국제화 API를 구성한다

Intl.NumberFormat API
1. Intl.NumberFormat([지역코드, {옵션 객체}]).format()은 각국의 언어에 맞는 숫자 서식에 맞게 표시해주는데, 달리 지역코드옵션 을 주지 않으면; 해당 지역에 맞는 표기법으로 표시해준다:
[ Intl.NumberFormat 사용법 1 ]
                                        
                                            const number= 3500

                                            new Intl.NumberFormat().format(number) // 3,500 ← 기본값: 해당 지역에 맞는 표기법으로 표시된다!
                                            new Intl.NumberFormat("ko-KR", {style: "currency", currency: "KRW"}).format(number) // ₩123,457 ← 한국 원화로 표기
                                        
                                    

format() 메서드는 Intl.NumberFormat 객체와 결합된다(날짜, 문자열 등의 다른 국제화 관련 클래스도 마찬가지이다!). 따라서, 형식 객체를 참조하는 변수를 만들고 그 변수에서 format() 메서드를 호출할 필요 없이, 바로 변수에 할당하고 그 변수를 독립된 함수처럼 사용할 수 있다!

2. 원하는 지역과 옵션을 써서 Intl.NumberFormat 객체의 인스턴스를 만들고, format() 메서드에 숫자 를 전달해 적절한 형식의 숫자로 된 문자열을 얻을 수 있다:
[ Intl.NumberFormat 사용법 2 ]
                                        
                                            let pounds= Intl.NumberFormat("en", { style: "currency", currency: "GBP" })

                                            console.log(pounds.format(1000)) // £1,000.00                                
                                        
                                    

{옵션객체}의 첫번째 인자인 style: "값"으로는 decimal (정수.소수 형식 - 기본값) percent (퍼센티지) 및 currency (화폐 형식)를 사용할 수 있는데, currency 에서는 ISO 화폐코드 또한 지정해주어야 한다!


✓   {옵션객체}의 두번째 인자인 currency: "값" 에는 다음과 같은 옵션들을 사용할 수 있다:

  • useGrouping: false 천 단위 구분자 사용하지 않음
  • minimumInterDigits: n 숫자의 정수 부분 자릿수 실제 숫자보다 지정된 자릿수가 크면; 앞에 0 을 붙여서 맞춘다!
  • minimumFractionDigits/maximumFractionDigits: n 숫자의 소수점 아래 부분 최소(기본값: 0)/최대(기본값: 3) 자릿수 지정 실제 숫자보다 지정된 자릿수가 크면; 뒤에 0 을 붙여서 맞추며, 작으면; 반올림한다!
Intl.DateTimeFormat API
Intl.DateTimeFormat([지역코드, {옵션객체}]).format()은 각국의 언어에 맞는 날짜 및 시간 서식에 맞게 표시해주는데, 달리 지역코드옵션 을 주지 않으면; 해당 지역에 맞는 표기법으로 표시해준다:
[ Intl.DateTimeFormat 사용법 ]
                                        
                                            let date= new Date(Date.UTC(2025, 6, 7)) // 월은 0부터 시작한다!

                                            console.log(new Intl.DateTimeFormat().format(date)) // 2025. 7. 7. ← 기본값: 해당 지역에 맞는 표기법으로 표시된다!
                                            console.log(new Intl.DateTimeFormat("ko-KR").format(date)) // 2025. 7. 7. ← 한국에서는 년/월/일 순서
                                        
                                    
                                    
                                        let options= { // 긴 날짜 서식에 더해 요일 추가
                                            year: "numeric", month: "long", day: "numeric", weekday: "long"
                                        }
                                        console.log(new Intl.DateTimeFormat("ko-KR", options).format(today)) // 2025년 7월 7일 월요일

                                        options= { // 숫자로 된 날짜와 시간
                                            year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric"
                                        }
                                        console.log(new Intl.DateTimeFormat("default", options).format(today)) // 2025. 7. 7. 오후 9:29:36 ← 옵션을 지정하면서 지역은 브라우저 기본값을 사용할 때: 'default' 지정

                                        options= { // 오전/오후 시간 표시가 필요할 때
                                            hour: "numeric", dayPeriod: "short"
                                        }
                                        console.log(new Intl.DateTimeFormat("ko-KR", options).format(today)) // 오전 9시
                                    
                                

✓   옵션값 키워드 정리:

  • year: numeric (4자리: 2005), 2-digit (항상 2자리: 05)
  • month: numeric (가급적 짧은 숫자), long (전체 이름: January), short (약어: Jan)
  • day: numeric (가급적 짧은 숫자), 2-digit (항상 2자리)
  • hour, minute, second: numeric (가급적 짧은 숫자), 2-digit (항상 2자리)
  • hour12: true / false (12시간제로 표시할 지 여부)
                                    
                                        let date= new Date(Date.UTC(2025, 6, 7)) // 월은 0부터 시작한다!

                                        console.log(new Intl.DateTimeFormat().format(date)) // 2025. 7. 7. ← 기본값: 해당 지역에 맞는 표기법으로 표시된다!
                                        console.log(new Intl.DateTimeFormat("ko-KR").format(date)) // 2025. 7. 7. ← 한국에서는 년/월/일 순서
                                    
                                

나중에 더 필요해지면; 최신 API를 사용하는 날짜-시간 관련 JavaScript 라이브러리인 도 참조하십시오.. 이를 쓰면 좀 더 쉽고 다양하게 날짜/시간을 다룰 수 있습니다!

Intl.Collator API
Intl.Collator 객체를 생성하고, compare() 메서드를 sort() 메서드에 전달하면; 지역에 적합한 순서로 정렬하는 것이 가능해진다 compare() 메서드와 sort() 정렬 함수는 정확히 같은 방식으로 작동한다!
  • usage: sort/search Collator 객체를 사용하는 방법 지정 기본값인 sort 는 엄격한 비교이며, search 는 느슨한 비교이다
  • sensitivity: base/accent/case/variant 문자열 비교시 대소문자와 악센트를 감안할지 여부 지정 base 는 기본 글자만 비교하며, variant (이는 sort() 정렬에서의 기본값이다)는 악센트와 대소문자까지 엄격히 비교한다
  • ignorePunctuation: true 공백과 구두점을 무시하고 비교한다
  • numeric: true 정수 또는 정수가 포함된 문자열을 숫자 순서로 비교한다
  • caseFirst: upper/lower 대문자/소문자를 앞에 둔다 이는 배열의 sort() 메서드의 기본 동작이며, 대문자가 소문자보다 앞에 오는 유니코드 순서와는 다르다!
                                    
                                        // 사용자의 지역에 맞게 정렬하는 기본 비교 함수
                                        const collator= new Intl.Collator().compare
                                        console.log(["a", "z", "A", "Z"].sort(collator)) // ['a', 'A', 'z', 'Z']
                                        console.log(["다", "마", "가", "하"].sort(collator)) // ['가', '다', '마', '하']

                                        // 파일 이름에 숫자가 포함되는 경우가 많으므로 따로 정렬해야 한다:
                                        const f_name= new Intl.Collator(undefined, { numeric: true }).compare
                                        console.log(["Page10", "Page5"].sort(f_name)) // ['Page5', 'Page10']

                                        // 대상 문자열과 비슷한 문자열을 모두 찾는다:
                                        const fuzzy= new Intl.Collator(undefined, { sensitivity: "base", ignorePunctuation: true }).compare
                                        let str= ["food", "fool", "Foo Bar"]
                                        console.log(str.findIndex(s => fuzzy(s, "foobar") === 0)) // 2 ← 찾은 요소의 인덱스번호
                                        console.log(str.findIndex(s => fuzzy(s, "f00bar") === 0)) // -1 ← 찾지 못함
                                    
                                

국제화 API의 첫번째 인자로 undefined 값을 주면; 기본값으로 설정된다!


✓   대부분의 전역객체와는 달리, Intl은 생성자가 아니므로 new 연산자와 함께 사용하거나 Intl 객체를 함수로 호출할 수 없다. Math 객체와 마찬가지로 Intl의 모든 프로퍼티와 메서드는 정적이다!

Web 푸시 메시지

스크립트의 Notification API를 써서 사용자에게 푸시 메시지를 나타낼 수 있는데, 이 알림은 브라우저 뷰포트의 바깥에 위치하므로 사용자가 탭을 변경하거나 다른 앱으로 이동했을 때에도 표시할 수 있다(그 모양은 각 OS 고유의 알림창으로 표시된다)

Notification API
Notification API를 사용하려면 웹브라우저의 허가를 받아야 한다. 먼저, Notification.permission으로 브라우저의 알림 허가 여부를 확인하여 값이 default (아직 사용자에게 알림표시 권한을 요구하지 않은 상태)라면; Notification.requestPermission()으로 허가를 요청하고, 나아가, 값이 granted (사용자에게 알림표시 권한을 요구하고, 사용자가 권한을 허용한 상태)이면; new Notification(타이틀[, {옵션객체}])로 알림표시 내용을 설정해준다:
                                    
                                        
                                    
                                
                                    
                                        const btn= document.querySelector('.push_btn')
                                        btn.addEventListener('click', notify)

                                        function notify() { // 푸시 알림은 먼저 브라우저의 허가를 물어야 한다!
                                            switch(Notification.permission) { // 푸시 알림 상태값 확인
                                                case 'default': Notification.requestPermission(); // 알림표시 허가 요청
                                                case 'granted': new Notification('안녕?'); break; // 알림표시 내용
                                                case 'denied': alert('알림이 거부됨!'); break; // 알림 거부
                                            }
                                        }
                                    
                                

이 기능은 Web Worker에서 사용할 수 있고, 모든 지원 브라우저의 보안 컨텍스트(HTTPS)에서 사용할 수 있다!

1. 프라미스로 Notification.requestPermission() 사용하기:
                                    
                                        Notification.requestPermission().then(function (result) {
                                            console.log(result)
                                        });
                                    
                                
2. 알림 내용 설정 및 닫기:
                                    
                                        // 알림 내용 설정
                                        let img= "/to-do-notifications/img/icon-128.png"
                                        let text= `아! ${title} 작업 기한이 만료됐습니다 ㅡㅡ;`
                                        let notification= new Notification("할일 목록", { body: text, icon: img });

                                        // 알림 닫기 설정 ← 단, 대다수 브라우저에서는 약 4초 후에 자동으로 닫는다!
                                        setTimeout(notification.close.bind(notification), 4000);
                                    
                                

새 메시지가 도착하면 사용자가 다른 애플리케이션으로 다른 일을 하고 있더라도 사용자에게 알릴 필요가 있는데, 이러한 웹 알림 메시지의 대표적인 사용 사례는 웹 기반 메일이나 같은 IRC 애플리케이션이다!

스트리밍 API

Streams API는 자바스크립트를 이용해 네트워크를 통해 전송된 데이터 스트림에 접근하여 다룰 수 있는 API를 제공한다

스트리밍 API란?
Streaming은 네트워크를 통해 받은 리소스를 작은 조각으로 나누어, Bit 단위로 처리하는데, 이는 브라우저가 받은 자원을 웹페이지에 표현할 때 주로 사용하는 방법이다. 새롭게 도입된(아직은 실험적인 기능이다!) Streams API를 이용하면; Buffer, blob, String 없이도 자바스크립트를 통해 원시 데이터를 비트 단위로 처리할 수 있게 된다. 나아가, 스트림의 시작 및 종료를 감지할 수 있고, 여러 스트림을 엮어서 에러를 처리하거나 필요한 경우 스트림을 취소할 수도 있다. 또한 스트림이 읽어들이는 속도에 따라 반응할 수도 있다!
스트림의 기본 사용법은 응답 데이터를 스트림으로 만드는 것인데, fetch() API를 통해 정상적으로 전송된 응답 바디는 ReadableStream으로 표현 가능하다. 또한 ReadableStream.getReader() 메서드를 통해 Reader 객체를 얻어 데이터를 읽거나, ReadableStream.cancel() 메서드로 스트림을 취소하는 것 또한 가능하다. 조금 더 복잡한 사용법은 ReadableStream() 생성자를 통해 사용자가 직접 스트림을 생성하는 것인데, WritableStream을 써서 스트림에 데이터를 쓸 수도 있다!
                                    
                                        fetch('big.json')
                                        .then(response => streamBody(response, reportProgress))
                                        .then(bodyText => JSON.parse(bodyText))
                                        .then(handleBigJSONObject);
                                    
                                
                                    
                                        /*** fetch() 요청으로 받은 응답 객체의 바디를 스트리밍하는 비동기 함수
                                        * streamBody 함수는 문자열로 해석되는 프라미스를 반환한다: 응답 객체를 첫번째 인자로 받고, 콜백 2개는 선택사항이다
                                        * reportProgress 콜백은 덩어리를 받을 때마다 호출된다: reportProgress(수신된 바이트의 합계, 다운로드 진척 정도)
                                        * processChunk 콜백은 데이터 덩어리를 받을 때마다 처리하는 함수
                                        --- */
                                        async function streamBody(response, reportProgress, processChunk) { // (응답객체, 콜백1, 콜백2)
                                            // 받아야되는 바이트 숫자
                                            let expectedBytes= parseInt(response.headers.get("Content-Length")) // Content-Length 헤더가 없으면; NaN
                                            let bytesRead= 0 // 지금까지 받은 바이트 숫자
                                            let reader= response.body.getReader() // 바이트를 읽는 함수
                                            let decoder= new TextDecoder("utf-8"); // 바이트를 텍스트로 변환한다
                                            let body= ""; // 지금까지 읽은 텍스트

                                            while(true) { // Loop until we exit below
                                                let {done, value}= await reader.read(); // 덩어리를 읽어들인다

                                                if(value) { // 바이트 배열을 받았다면;
                                                    if(processChunk) { // 콜백이 있으면;
                                                        let processed= processChunk(value) // 바이트를 처리한다
                                                        if(processed) {
                                                            body += processed
                                                        }
                                                    } else { // 콜백이 없으면;
                                                        body += decoder.decode(value, {stream: true}); // 바이트를 텍스트로 디코딩한다
                                                    }

                                                    if(reportProgress) { // 진행상태 콜백이 있으면;
                                                        bytesRead += value.length;
                                                        reportProgress(bytesRead, bytesRead / expectedBytes) // 호출해서 진행 상태를 표시한다
                                                    }
                                                }

                                                if(done) { // 마지막 덩어리라면;
                                                    break; 
                                                }
                                            }

                                            return body; // 병합한 바디 텍스트를 반환한다
                                        }
                                    
                                

서버전송 이벤트

서버에서 클라이언트에 보낼게 있으면 연결을 통해 데이터를 보내지만, 연결을 끊지는 않는다. 보통, 이런 형태의 연결이 오래 지속되는 경우는 많지 않으며, 클라이언트는 연결이 끊겼음을 감지하면 그냥 새로운 요청을 보내 다시 연결하게 된다. 이렇게 서버가 클라이언트에 메시지를 전송하는 방법은 대단히 효율적이라서 클라이언트 사이드 자바스크립트에서는 EventSource API를 통해 이 패턴을 지원한다

서버전송 이벤트
웹서버에 이런 지속성 요청을 보낼 때는 EventSource() 생성자에 URL 을 전달하기만 하면 된다. 서버가 그 연결에 적절한 형태의 데이터를 기록하면 EventSource 객체는 그 데이터를 이벤트로 일으키게 된다.
                                    
                                        let ticker= new EventSource("stockprices.php")

                                        ticker.addEventListener("bid", (e) => { displayNewBid(e.data) });
                                    
                                

메시지 이벤트의 이벤트 객체에는 서버에서 응답으로 보낸 문자열이 data 프로퍼티에 담겨있고, type에는 이벤트의 이름이 저장되는데, 이 타입은 서버에서 결정한다 이름을 생략하고 데이터만 보내면; 이벤트 타입의 기본값은 message 이다!

서버전송 이벤트 예)


서버전송 이벤트 프로토콜: 클라이언트가 EventSource 객체를 생성해 서버에 연결을 보내면 서버는 이 연결을 열어둔 채, 이벤트가 일어나면; 서버는 이 연결에 텍스트를 보내게 된다

IndexedDB API

IndexedDB는 파일이나 블롭 등 많은 양의 구조화된 데이터를 클라이언트에 저장하기 위한 저수준 API로서, 인덱스를 사용해 데이터를 고성능으로 탐색할 수 있다

API

Google Ads

사용자 정보 분석 등..

Google Ads 분석
사용자 정보 분석 등..

MDN 참조
항상 sandbox 특성을 사용하세요

다른 코드베이스에 영향을 미치지 않으면서도 특정 코드를 테스트하거나 적절하게 사용할 수 있도록 코드를 감싸고 있는 영역을 sandbox라고 합니다

샌드박스를 적용하지 않은 콘텐츠는 JavaScript를 실행하거나, 폼을 제출하거나, 새 창을 띄우는 등의 작업을 할 수 있습니다. 이전 예시에서 보았듯 기본적으로 sandbox 특성을 파라미터 없이 사용하여 가능한 모든 제약을 부과해야 합니다.

CSP 지시어를 설정하세요

CSP는 콘텐츠 보안 정책 을 나타내며 HTML 문서 보안을 개선하기 위해 고안된 일련의 HTTP 헤더를 제공합니다. HTTP 헤더란 웹 서버에서 웹페이지가 전송될 때 동반되는 메타데이터입니다. iframe 보안과 연관 지어 말씀드리자면, 적절한 X-Frame-Options 헤더를 전송하도록 설정할 수 있습니다. 이렇게 하면 다른 웹사이트에서 여러분의 웹페이지를 삽입하지 못하도록 만들어서 클릭재킹이나 다른 공격의 대상이 되는 일을 막을 수 있습니다. 이전 예시에서 보셨듯이 이것이 바로 MDN 개발자들이 설정해 둔 것입니다.

wave