코로나 건강 설문 앱을 만들면서(feat. google forms, react, pwa, firebase functions)

눈치볼나이·2020년 8월 22일
1

회사에서 코로나 때문에 매일 건강 이상 여부를 체크하는 구글 설문지를 작성해야되는 일이 생겼습니다. 사실 1분도 채 안 걸리지만 여간 귀찮은 일이 아니어서 자동화를 해보기로 마음먹었습니다.

1. Before & After

Before

  • 먼저 매일 매일 제출해야 했었던 설문지입니다. 원본이 아니라 제가 비슷하게 만든 녀석임을 알려드립니다. 사진에 다 나오진 않지만 약 7~8문항 정도 됩니다.

After

  • 다음으로 제가 만든 웹앱입니다. 보이는 이름은 팀원들의 이름입니다(물론 가명입니다). 자신의 이름을 선택 후 제출하기 버튼을 누르면 미리 저장해놓은 구글 설문 응답이 제출됩니다.

2. 아이디어

구글 설문지 정보 가져오기

구글 설문지의 선택항목을 개발자 도구로 선택해봐도 사실 input이나 select 태그가 나오진 않습니다. 실제 input태그는 hidden으로 감춰져있어서 그걸 찾아서 사용해야 합니다. 아는 분께서 이 사실을 알려주었고, 제 미니 프로젝트는 여기서 시작되었습니다.

제가 처음 근무지를 묻는 문항에 대전을 선택했을 때의 모습입니다. 위 form태그의 action을 보시면 이 설문지를 제출할 때 쓰일 url을 확인할 수 있습니다.

같은 설문지일 경우 항상 저 action의 url과 input태그의 name 속성이 갖는 값(entry.숫자)이 같다는 걸 알고 이 것을 이용해 보고자 하였습니다.

의식의 흐름(프론트 엔드)

먼저 js(브라우저)에서 해당 form에 요청이 가능한 지 테스트를 해보았는데 cross origin 이슈가 발생하였습니다. 그래서 프론트는 팀원 중 누구를 선택했는 지를 서버로 넘기는 역할만 하기로 하였습니다. 백엔드에서 해당 form에 요청을 보낼 것입니다.

개인적으로 react를 좋아해서 CRA를 통해 프론트 환경을 만들었습니다. 프론트에서는 이름 선택해서 쏴주기만 하면 끝이라, 어려운 점은 없었습니다. 다만 팀원의 요청으로 처음 pwa를 만들어 보았는데, pwa의 장점을 처음으로 직접 느껴보게 되었습니다. 마치 네이티브 앱을 사용하는 것 같은 편안함을 느꼈지만 네이티브 앱을 만드는 고통은 없는 느낌이었네요. 배포는 netlify를 사용하였습니다.

의식의 흐름(백엔드)

처음엔 flask로 서버를 만들었습니다. (딱히 이유는 없습니다. 그냥 생각이 났어요.) heroku에 배포했는데, 매일 아침 긴 로딩 시간을 참는 것(프리티어라서)이 싫어서 AWS EC2에 올리기로 마음먹게 되었습니다.

삽질의 단계를 지나 어렵사리 EC2에 올렸는데, 구글 설문지로의 요청이 거부되는 것을 발견하였습니다. 구글 설문지는 https 프로토콜인데, 제 서버는 http였거든요. (이럴 경우 요청이 거부된다는 것도 처음 알게 되었습니다.) EC2에서는 도메인이 있어야 https 서비스를 할 수 있는데, 이 것 때문에 도메인까지 구매하긴 싫더군요. 사실 AWS 문서가 편히 읽히지 않은 탓도 있습니다. 저만 AWS 문서가 어려운가요?ㅎㅎ

아는 동생이 제 문제를 듣고 firebase functions를 소개해 주었습니다. 문서도 잘 되어있고, 사용법도 너무 간단하더군요. 아마 AWS labmda도 비슷할테지만, 왠지 정이 가진 않습니다. 어쨌든 최종적으로 firebase functions를 백엔드에 쓰기로 결정하였습니다.

3. 기록해두고 싶은 것들

프론트엔드

백엔드

  • firebase functions 사용
    functions에서 다른 api에 요청을 보내야 한다면 무료 요금제로는 해당 작업을 할 수 없습니다. 그래서 저도 역시 blaze 요금제를 사용하고 있지만, 무료로 사용할 수 있는 요청 수가 우리 팀원들 사용량보다 무척 커서 아직 요금이 결제된 적은 없습니다.

  • js(node)에서 POST 요청 with form-data, axios
    노드환경에는 FormData가 없습니다. 저는 axios를 썼는데, npm에서 form-data를 설치해서 요청을 보내봐도 왜인지 실패하더군요. 그래서 저는 stackoverflow에서 검색한 답변을 참고하였습니다. 아래는 functions에서 관련된 부분만 잘라온 코드입니다.

// 보낼 form-data 예시
const healthData = {
  'entry.1682982420': '지역',
  'entry.1736238762': '층수',
  'entry.409090123': '이름',
  'entry.1191662158': '37.5 미만',
  'entry.1175693492': '이상없음',
  'entry.111036440': '아니오',
}
// object를 form-data 형식으로 바꾸는 함수
const formUrlEncoded = (x) =>
  Object.keys(x).reduce((p, c) => p + `&${c}=${encodeURIComponent(x[c])}`, '')
// 요청
await axios({
  url,
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  data: formUrlEncoded(healthData),
})

생각

serviceWorker를 이해하고 썼는가?

저는 아직도 서비스워커가 정확히 어떤 느낌인지를 모르겠습니다. pwa를 위해서 사용하긴 했지만, 그게 다이고 더 이해할 필요성도 느끼지 못합니다. 정확히 이해하고 사용한다면 좋겠지만, 제가 서비스 워커를 이해하려고 노력하다가 이 프로젝트를 포기하는 일은 없었으면 좋겠습니다. 저는 서비스 워커가 어떤 일을 하는지 잘 모르지만, 앱을 완성했고, 팀원들은 앱을 잘 사용하고 있습니다.

제가 처음에 미니 프로젝트를 만들려고 했을 때는 너무 완벽히 만들려고 하다가 제 풀에 지쳐 프로젝트를 엎었던 적이 많습니다. 제 생각에는 조금 모자라더라도 배포해서 사람들이 쓰게하는 게 먼저인 것 같아요. 제 앱을 사용하는 사람들이 만약 서비스워커 때문에 불편함을 느낀다면, 저는 자연스럽게 서비스워커를 공부하게 될 것입니다. 그 때에 서비스워커를 공부하는 동기는 그냥 공부할 때보다 훨씬 더 강력한 동기로 다가오지 않을까요?

  • 해당 프로젝트에 푸쉬 알림을 추가하면서 서비스 워커 공부를 많이 하게되었네요ㅎㅎ

혹시나 궁금하신 분들을 위해

그냥 일지처럼 개발하며 느낀 점, 나중에 참고할 만한 점을 위주로 작성하였는데, 혹시 코드 작성이 궁금하신 분이 있다면 추가로 포스팅을 작성해보겠습니다. 댓글 남겨주세요. :)

profile
일상블로그 같은 개발블로그

5개의 댓글

comment-user-thumbnail
2020년 12월 26일

이거 저도 너무너무 해보고 싶은데 혹시 코드 공유해주실수 있을까요??

2개의 답글
comment-user-thumbnail
2021년 12월 17일

그런데 혹시 구글폼 제출할때 구글 로그인 해야만 가능하지 않나요? 로그인 부분은 생략해도 제출이 되려나요?

답글 달기