[Toy Project] 날씨 웹앱 만들기 (부제: 에러 노트)

dev-hannahk·2021년 6월 27일
0

Toy Project

목록 보기
1/1
post-thumbnail
  • 타입스크립트, 리액트, 리덕스로 오픈 API를 사용해서 날씨 웹 앱을 만들어봤다.

  • 간단한 웹앱이지만 배포까지 해보려니 에러와 에러해결의 연속이었다.

  • 그래서 에러 노트를 기록해보려 한다!

  • 프로젝트는 크게 네 단계였다.

    1. 기능 구현
    2. 디자인
    3. AWS S3 + Github Actions 배포
    4. Netlify functions 리다이렉트 서버
  • 배포는 gh-pages로만 해본 게 다라 처음이나 마찬가지였고, open api의 key를 감추기 위해 리다이렉트 서버를 만들어본 것도 처음이라 기능적으로는 별거 없지만 많이 배울 수 있었다.

STEP 1. 기능 구현

기능 구현을 할 때 어려움을 겪었던 부분은 weather api가 주는 data로 검색된 지역의 시간을 계산하는 것이었다. 아래는 api 응답의 예시인데, 아래에서 dt와 timezone 데이터를 활용해서 시간 계산을 해야했다.

// Example of API response
{
  "coord": {
    "lon": -122.08,
    "lat": 37.39
  },
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "clear sky",
      "icon": "01d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 282.55,
    "feels_like": 281.86,
    "temp_min": 280.37,
    "temp_max": 284.26,
    "pressure": 1023,
    "humidity": 100
  },
  "visibility": 16093,
  "wind": {
    "speed": 1.5,
    "deg": 350
  },
  "clouds": {
    "all": 1
  },
  "dt": 1560350645,
  "sys": {
    "type": 1,
    "id": 5122,
    "message": 0.0139,
    "country": "US",
    "sunrise": 1560343627,
    "sunset": 1560396563
  },
  "timezone": -25200,
  "id": 420006353,
  "name": "Mountain View",
  "cod": 200
  }                         

결론적으로 나는 dt는 활용하지 않고 new Date() 객체를 활용해서 현재 시각을 구하고, 해당 시각과 timezone을 밀리초만큼 곱한 다음, 9시간 차이가 나는 걸 빼 주었다. 해당 함수는 모듈화해서 임포트해와서 사용했다. (참고)

export const getWeatherTime = (data: WeahterData): string => {
  const now = new Date();
  const getCurrentTime = now.getTime();
  const currentTime = new Date(
    getCurrentTime + data.timezone * 1000 - 9 * 60 * 60 * 1000
  );

  const getHour = currentTime.getHours();
  const getMin = currentTime.getMinutes();

  const hour = getHour >= 10 ? getHour : `0${getHour}`;
  const min = getMin >= 10 ? getMin : `0${getMin}`;

  return `${hour}:${min}`;
};

이 외에는 켈빈 온도를 섭씨 온도로 바꿔주는 함수를 만들어봤다.

export const currentCelsiusTemp = (data: WeahterData): string => {
  return (data.main.temp - 273.15).toFixed(2);
};

타입스크립트로 작성해서 api 응답 데이터 형식의 타입을 다 지정해줘서 api관련 코드를 쓸 때 활용할 수 있었다.

export interface Weather {
  id: number;
  main: string;
  description: string;
  icon: string;
}

export interface ForecastData {
  clouds: {
    all: number;
  };
  dt: number;
  dt_txt: string;
  main: {
    feels_like: number;
    grnd_level: number;
    humidity: number;
    pressure: number;
    sea_level: number;
    temp: number;
    temp_kf: number;
    temp_max: number;
    temp_min: number;
  };
  pop: number;
  rain: {
    '3h': number;
  };
  sys: {
    pod: string;
  };
  visibility: number;
  weather: Weather[];
  wind: {
    deg: number;
    gust: number;
    speed: number;
  };
}

export interface ForecastState {
  data: ForecastData[] | null;
  loading: boolean;
  error: string;
}

STEP 2. 디자인

  • 프로젝트를 하면서 웹 디자이너 분들의 절대적 필요성을 다시 느꼈다. 그래서 결국 디자인은 구글링해서 나온 리액트 웹앱 디자인을 클론했다.
  • 생각보다 스타일링하는 데 시간이 걸렸다. 거의 기능 구현시간과 맞먹었던 것 같다. 반응형 웹을 좀 더 촘촘하게 해보고 싶었으나 그러면 시간이 너무 오래 걸릴 것 같아서 그냥 PC와 모바일 두 버전으로만 하기로 했다.
  • 디자인하면서 겪은 힘들었던 점은 x축으로 스크롤을 하는데 화면이 가운데 고정이 되어서 왼쪽 화면이 안보였다. 아래처럼.

    검색하다가 스택오버플로우(링크)에서 답을 얻었는데, align-items: centerjustify-content: center를 적용하면 센터에 고정되서 그런거였다. 대신에 margin:0 auto 등을 써보거나 safe value를 적용해보라고 솔루션을 줬지만 나에게 적용은 되지 않았다 ㅠㅠ 그래서 결국 flex를 버리고 grid로 바꿨더니 (display: grid; justify-items: center;) 문제가 해결 되었다!!!

STEP 3. AWS S3 + Github Actions 배포

gh-pages로 배포해본적은 있지만 이번에는 좀 더 욕심내서 aws에 배포해 보고 싶었다.
벨로그에 자세히 써주신 분 덕분에 s3와 깃헙 액션으로 자동 배포까지 차근차근 잘 진행할 수 있었다. 👍 👍 (링크)
그렇게 쉽게 배포가 되나 싶었는데... 역시나 오류가 발생했다 😩😩

에러 1: An error occurred (AccessDenied) when calling the PutObject operation...

에러 해결: 버킷 정책 Action에 "s3:PutObject" 추가

{
    "Version": "2012-10-17",
    "Id": "Policy1546336529826",
    "Statement": [
        {
            "Sid": "Stmt1546336528005",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::hannahk-weather-app/*"
        }
    ]
}

에러 2: github에 .env파일이 없어서 api key없이는 api에 접근 불가

에러 해결:

  1. github에 그냥 키를 올린다^^; 어차피 서버없이 프론트단에서는 개발자도구에서 네트워크 탭 열면 키 노출됨ㅎ
  2. 리다이렉트 서버를 이용한다!!!!

처음에는 깃헙에 키를 올렸다. 메인 브랜치에 올리기는 좀 그래서 배포용 브랜치를 새로 파서... 사실 api key를 노출시키는게 치명적인 건 아니지만 그래도 찝찝해서 해결방안 2를 찾아봤고 그건 Step4에서 자세히 설명하기로.

에러 3: Failed to load resource: the server responded with a status of 404 (Not Found)

에러 해결:

리다이렉트 서버가 문제없이 돌아가서 api key가 그대로 노출되어 있던 브랜치를 삭제하고 메인브랜치를 다시 배포했는데 갑자기 404 에러가 떴다ㅜㅜ 버킷에는 파일들이 잘 들어가 있는데 도대체 뭐가 문제지 고민하다가 파일들의 경로를 보니 /ts-weatehr-app/ 이라고 중간 폴더가 있는 걸 확인하고 static폴더를 위의 폴더로 이동시켰더니 다행히 잘 불러와 진다. (참고)

STEP 4. Netlify functions 리다이렉트 서버

이번에도 벨로그 블로그 도움을 받았다. 어느 친절한 분이 네트리파이를 이용한 리다이렉트 서버를 이용하는 걸 알려주셔서 진행할 수 있었다. (링크)
하지만 역시나 에러 발생 😂😂 처음엔 헤더에 Access-Control-Allow-Origin을 처리하는 걸 안해서 headers 설정을 해줬는데도 에러가 계속 떴다. Why...?

에러: CORS Error

에러 해결: netlify.toml 파일에 headers 설정 추가

[[headers]]
for = "/*"

[headers.values]
Access-Control-Allow-Origin = "*" 

cors 에러를 해결해주고 나서 리퀘스트를 요청했더니 개발자도구-네트워크탭에서 아래와 같이 redirect server로 요청이 잘 되었고, api key가 노출되는 걸 방지했다. 😆

출처:
https://stackoverflow.com/questions/62376115/how-to-obtain-open-weather-api-date-time-from-city-being-fetched
https://stackoverflow.com/questions/33454533/cant-scroll-to-top-of-flex-item-that-is-overflowing-container
https://reactjsexample.com/a-weather-app-made-with-react-js/
https://www.youtube.com/watch?v=ddYwN1h_Jno
https://github.com/DanJFletcher/how-to-hide-api-keys-with-netlify-functions
https://velog.io/@loakick/Github-Action%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-React-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-S3%EC%97%90-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0
https://velog.io/@bigsaigon333/Client-Side%EC%97%90%EC%84%9C-Youtube-API-Key-%EC%88%A8%EA%B8%B0%EA%B8%B0

profile
Make it count.

0개의 댓글