You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
12 KiB
223 lines
12 KiB
# 브라우저 확장 프로젝트 파트 2: 로컬 저장소를 사용한, API 호출
|
|
|
|
## 강의 전 퀴즈
|
|
|
|
[Pre-lecture quiz](.github/pre-lecture-quiz.md)
|
|
|
|
### 소개
|
|
|
|
이 강의에서는, 브라우저 확장의 폼을 제출하여 API를 호출하고 브라우저 확장에 결과를 출력합니다. 또한, 나중에 참조하고 사용하도록 브라우저의 로컬 저장소에 데이터를 저장하는 방법에 대해 알아봅니다.
|
|
|
|
✅ 적절한 파일 번호가 매겨진 세그먼트를 따라서 코드를 둘 위치를 알아봅니다.
|
|
|
|
### 확장에서 조작할 요소를 설정합니다:
|
|
|
|
지금까지 HTML 폼과 브라우저 확장에 대한 결과 `<div>`를 작성했습니다. 이제부터, `/src/index.js` 파일에서 작업하고 확장을 조금씩 빌드해야 합니다. 프로젝트 설정 및 빌드 프로세스에 대해서는 [이전 강의](../about-browsers/README.md)를 참조하세요.
|
|
|
|
`index.js` 파일에서 작업하면서, 다양한 필드에 값을 저장할 `const` 변수를 만드는 것으로 시작합니다:
|
|
|
|
```JavaScript
|
|
// form fields
|
|
const form = document.querySelector('.form-data');
|
|
const region = document.querySelector('.region-name');
|
|
const apiKey = document.querySelector('.api-key');
|
|
|
|
// results
|
|
const errors = document.querySelector('.errors');
|
|
const loading = document.querySelector('.loading');
|
|
const results = document.querySelector('.result-container');
|
|
const usage = document.querySelector('.carbon-usage');
|
|
const fossilfuel = document.querySelector('.fossil-fuel');
|
|
const myregion = document.querySelector('.my-region');
|
|
const clearBtn = document.querySelector('.clear-btn');
|
|
```
|
|
|
|
모든 필드는 이전 강의에서 HTML을 설정한 것처럼 CSS 클래스에서 참조됩니다.
|
|
|
|
### 리스너 추가하기
|
|
|
|
다음으로, 폼에 이벤트 리스너를 추가하고 폼을 리셋해주는 clear 버튼을 추가하여, 폼을 제출하거나 reset 버튼을 클릭하면 실행되도록, 파일 하단에 앱 초기화를 호출하도록 추가합니다:
|
|
|
|
```JavaScript
|
|
form.addEventListener('submit', (e) => handleSubmit(e));
|
|
clearBtn.addEventListener('click', (e) => reset(e));
|
|
init();
|
|
```
|
|
|
|
✅ submit 또는 click 이벤트를 받을 때 사용되는 약칭과, 이벤트가 handleSubmit 또는 reset 함수에 전달되는 방법에 유의하십시오. 이 약칭에 관련된 것을 더 긴 형식으로 바꿔 작성할 수 있나요? 어느 쪽을 선호하나요?
|
|
|
|
### init() 함수와 reset() 함수 작성하기:
|
|
|
|
이제 init()라고 불리는 확장 초기화하는 함수를 만드려고 합니다:
|
|
|
|
```JavaScript
|
|
function init() {
|
|
//if anything is in localStorage, pick it up
|
|
const storedApiKey = localStorage.getItem('apiKey');
|
|
const storedRegion = localStorage.getItem('regionName');
|
|
|
|
//set icon to be generic green
|
|
//todo
|
|
|
|
if (storedApiKey === null || storedRegion === null) {
|
|
//if we don't have the keys, show the form
|
|
form.style.display = 'block';
|
|
results.style.display = 'none';
|
|
loading.style.display = 'none';
|
|
clearBtn.style.display = 'none';
|
|
errors.textContent = '';
|
|
} else {
|
|
//if we have saved keys/regions in localStorage, show results when they load
|
|
displayCarbonUsage(storedApiKey, storedRegion);
|
|
results.style.display = 'none';
|
|
form.style.display = 'none';
|
|
clearBtn.style.display = 'block';
|
|
}
|
|
};
|
|
|
|
function reset(e) {
|
|
e.preventDefault();
|
|
//clear local storage for region only
|
|
localStorage.removeItem('regionName');
|
|
init();
|
|
}
|
|
|
|
```
|
|
함수에는, 약간의 흥미로운 로직이 있습니다. 이것을 읽어보면, 어떤 것이 보이나요?
|
|
|
|
- 사용자가 로컬 저장소에 APIKey 및 지역 코드를 저장했는지 확인하기 위해 두 'const'가 설정됩니다.
|
|
- 둘 중 하나가 null이면, 'block'으로 출력되도록 스타일을 변경하여 폼을 나타냅니다.
|
|
- 결과를 숨기거나, 불러오고, 또한 clearBtn을 숨기며 오류 텍스트를 빈 문자열로 설정합니다
|
|
- 키와 지역이 존재하는 경우에는, 다음 루틴이 시작됩니다:
|
|
- 탄소 사용량 데이터를 얻기 위한 API 호출
|
|
- 결과 영역 숨기기
|
|
- 폼 숨기기
|
|
- 리셋 버튼 보이기
|
|
|
|
계속 진행하기 전, 브라우저에서 사용할 수 있는 매우 중요한 개념: [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)에 대해 알아 보는 것이 좋습니다. LocalStorage는 브라우저에 문자열을 `key-value` 쌍으로 저장하는 유용한 방법입니다. 이런 타입의 웹 저장소는 브라우저에서 데이터를 관리하기 위해 JavaScript로 제어할 수 있습니다. LocalStorage는 만료되지 않지만, 다른 종류의 웹 저장소인 SessionStorage는 브라우저를 닫는 즉시 지워집니다. 다양한 타입의 저장소를 사용하는 것은 장점과 단점이 존재합니다.
|
|
|
|
> Note - 이 브라우저 확장은 로컬 저장소를 가집니다; 주요 브라우저 창은 각자 다른 객체이며 별도로 동작합니다.
|
|
|
|
APIKey를 문자열 값으로 설정한다고 하면, 예를 들어 웹 페이지를 "inspecting" 하고 (브라우저를 우측 클릭하여 검사할 수 있습니다) 애플리케이션 탭으로 이동하여 저장소를 확인했을 때 Edge에 설정되어 있다는 것을 볼 수 있습니다.
|
|
|
|
![Local storage pane](images/localstorage.png)
|
|
|
|
✅ LocalStorage에 일부 데이터를 저장하기 꺼리는 상황을 생각해보세요. 일반적으로 API 키를 LocalStorage에 배치하는 것은 좋지 않은 생각입니다! 알 수 있나요? 우리 경우, 앱은 순수하게 학습을 위함이고, 앱 스토어에도 배포하지 않으므로 이 방법을 사용합니다.
|
|
|
|
Web API로 `getItem()`, `setItem()` 또는 `removeItem()`을 사용하여 LocalStorage를 제어합니다. 대부분 브라우저에서 광범위하게 지원됩니다.
|
|
|
|
`init()`에서 호출되는 `displayCarbonUsage()` 함수를 만들기 전에 초기 폼 제출을 하는 기능을 만들어 보겠습니다.
|
|
|
|
### 양식 제출 제어하기
|
|
|
|
이벤트 인자 `(e)`를 받는 `handleSubmit` 함수를 만듭니다. 이벤트 전달을 중단하고(브라우저 새로 고침을 중단) `apiKey.value`와 `region.value` 인자를 전달하는 새로운 함수 `setUpUser` 를 호출합니다. 이런 방식으로, 적절한 필드가 채워지는 순간 초기 폼을 통해 가져온 두 값을 사용합니다.
|
|
|
|
```JavaScript
|
|
function handleSubmit(e) {
|
|
e.preventDefault();
|
|
setUpUser(apiKey.value, region.value);
|
|
}
|
|
```
|
|
✅ 메모리를 초기화합니다 - 지난 강의에서 설정한 HTML에는 파일 상단에 지정한 `const`를 통해 `values`이 잡히는 두 입력 필드가 있으며, 둘 다 `required`이므로 브라우저에서 사용자가 null 값을 입력하지 못하도록 합니다.
|
|
|
|
### 사용자 설정하기
|
|
|
|
`setUpUser` 함수로 이동하고, 여기에 apiKey와 regionName에 대한 로컬 저장소 값을 설정합니다. 새로운 함수를 추가합니다:
|
|
|
|
```JavaScript
|
|
function setUpUser(apiKey, regionName) {
|
|
localStorage.setItem('apiKey', apiKey);
|
|
localStorage.setItem('regionName', regionName);
|
|
loading.style.display = 'block';
|
|
errors.textContent = '';
|
|
clearBtn.style.display = 'block';
|
|
//make initial call
|
|
displayCarbonUsage(apiKey, regionName);
|
|
}
|
|
```
|
|
이 함수는 API가 호출되는 동안 로딩 메시지를 설정하게 합니다. 핵심으로, 이 브라우저 확장의 가장 중요한 함수를 만드는 데 도달했습니다!
|
|
|
|
### 탄소 사용량 출력하기
|
|
|
|
마지막으로 API 쿼리할 시간입니다!
|
|
|
|
계속 진행하기 전에, API에 대해 논의해야 합니다. API, 또는 [Application Programming Interfaces](https://www.webopedia.com/TERM/A/API.html)는 웹 개발자의 툴박스에서 중요한 요소입니다. 프로그램이 상호 작용하거나 할 수 있게 도와주는 표준 방법을 제공합니다. 예시로, 데이터베이스를 쿼리할 웹 사이트를 구축하는 경우, 누군가 사용할 API를 만들었을 수 있습니다. 다양한 유형의 API가 있지만 가장 인기있는 API 중 하나는 [REST API](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/)입니다.
|
|
|
|
✅ 'REST'라는 용어는 'Representational State Transfer'를 의미하고 데이터를 가져오기 위해서 다양하게-구성된 URL을 쓰는 기능입니다. 개발자가 사용할 수 있는 다양한 타입의 API에 대해 약간 알아보십시오. 어떤 포맷이 좋습니까?
|
|
|
|
이 함수에 대해 유의해야 할 중요 사항이 있습니다. 먼저 [`async` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)를 확인합니다. 비동기로 실행되도록 함수를 작성한다는 것은 수행되기 전 데이터 반환 작업이 완료될 때를 기다린다는 점을 의미합니다.
|
|
|
|
다음은 `async`에 대한 간단한 영상입니다 :
|
|
|
|
[![Async and Await for managing promises](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "Async and Await for managing promises")
|
|
|
|
C02Signal API를 쿼리할 새로운 함수를 만듭니다:
|
|
|
|
```JavaScript
|
|
import axios from '../node_modules/axios';
|
|
|
|
async function displayCarbonUsage(apiKey, region) {
|
|
try {
|
|
await axios
|
|
.get('https://api.co2signal.com/v1/latest', {
|
|
params: {
|
|
countryCode: region,
|
|
},
|
|
headers: {
|
|
'auth-token': apiKey,
|
|
},
|
|
})
|
|
.then((response) => {
|
|
let CO2 = Math.floor(response.data.data.carbonIntensity);
|
|
|
|
//calculateColor(CO2);
|
|
|
|
loading.style.display = 'none';
|
|
form.style.display = 'none';
|
|
myregion.textContent = region;
|
|
usage.textContent =
|
|
Math.round(response.data.data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)';
|
|
fossilfuel.textContent =
|
|
response.data.data.fossilFuelPercentage.toFixed(2) +
|
|
'% (percentage of fossil fuels used to generate electricity)';
|
|
results.style.display = 'block';
|
|
});
|
|
} catch (error) {
|
|
console.log(error);
|
|
loading.style.display = 'none';
|
|
results.style.display = 'none';
|
|
errors.textContent = 'Sorry, we have no data for the region you have requested.';
|
|
}
|
|
}
|
|
```
|
|
|
|
이는 큰 함수입니다. 여기에 어떤 일이 일어나고 있나요?
|
|
|
|
- 좋은 사례에 따라, `async` 키워드를 사용하여 이 함수가 비동기로 동작하도록 합니다. 이 함수는 API가 데이터를 반환할 때 promise를 반환하므로 `try/catch` 블록을 포함합니다. API 응답 속도를 제어할 수 없기 때문에 (전혀 응답을 못 받을 수 있습니다!) 확실하지 않은 일은 비동기로 호출하여 처리해야 합니다.
|
|
- API 키를 사용해서, 지역의 데이터를 얻기 위해 co2signal API를 쿼리하고 있습니다. 이 키를 사용하려면, 헤더 파라미터에 인증 타입을 사용해야 합니다.
|
|
- API가 응답하면, 이 데이터를 출력하도록 설정한 화면에 응답 데이터의 다양한 요소를 할당합니다.
|
|
- 오류가 있거나, 결과가 없는 경우에는, 오류 메시지가 출력됩니다.
|
|
|
|
✅ 비동기 프로그래밍 패턴을 사용하는 것은 툴박스의 다른 매우 유용한 도구입니다. [about the various ways](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)를 읽고 이런 타입의 코드를 구성할 수 있습니다.
|
|
|
|
축하합니다! 확장을 빌드하고 (`npm run build`) 확장 패널에서 새로 고치면, 작동하는 확장이 있습니다! 아이콘만 작동하지 않으며 다음 강의에서 수정할 예정입니다.
|
|
|
|
---
|
|
|
|
## 🚀 도전
|
|
|
|
지금까지 이 강의에서 여러 타입의 API에 대해 논의했습니다. 웹 API를 선택하고 제공하는 내용에 대해 자세히 알아보세요. 예시로, [HTML Drag and Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)와 같은 브라우저에서 쓸 수 있는 API를 보세요. 당신의 의견에 비추어 볼 때 좋은 API를 만드는 방법은 무엇일까요?
|
|
|
|
## 강의 후 퀴즈
|
|
|
|
[Post-lecture quiz](.github/post-lecture-quiz.md)
|
|
|
|
## 리뷰 & 자기주도 학습
|
|
|
|
이 강의에서는 전문 웹 개발자에게 매우 유용한, LocalStorage와 API에 대해 학습했습니다. 어떻게 두 가지가 같이 작동하는지 생각해볼 수 있나요? API에서 사용할 아이템을 저장하는 웹 사이트를 어떻게 설계할지 생각해보세요.
|
|
|
|
## 과제
|
|
|
|
[Adopt an API](assignment.md)
|
|
|