112. Handling the Response

npm create vue@latest


이 강의에서는 Firebase로부터 오는 응답을 처리하는 방법에 대해 설명합니다.
여기서는 createUserWithEmailAndPassword 함수를 사용하여 Firebase에 사용자 등록 요청을 보내고, 이 요청으로부터 오는 응답을 처리하는 과정을 다룹니다.

  1. 에러 처리

    • Firebase로부터 오류 응답을 받을 수 있으므로, 이를 처리해야 합니다.
      async/await 구문을 사용하고 있으므로, try/catch 블록을 사용하여 에러를 캐치합니다.
      catch 블록에는 error 매개변수가 포함되어 있으며, 모든 오류는 코드와 메시지를 포함합니다.
      하지만 구체적인 오류 내용 대신 일반적인 메시지를 사용자에게 표시하기로 합니다.
  2. 경고 메시지 업데이트

    • 오류가 발생했을 때, 사용자에게 알리기 위해 경고 메시지를 업데이트합니다.
      먼저 information 속성을 false로 설정하여 폼을 다시 활성화시키고, alert 속성의 변형을 빨간색으로 설정합니다.
      이는 일반적인 오류 메시지와 연관됩니다.
      마지막으로, '예상치 못한 오류가 발생했습니다. 나중에 다시 시도해 주세요.'라는 메시지를 설정합니다.
  3. 변수 범위

    • userCredentials 변수가 try/catch 블록 바깥에서 접근할 수 없으므로, 이 변수를 함수의 상단에서 정의하고 초기값을 null로 설정합니다.
  4. 사용자 등록 테스트

    • 앱을 브라우저에서 열고 콘솔을 열어 오류없이 계정을 등록해보세요.
      성공 메시지가 표시되며, 콘솔에서 사용자 자격 증명에 대한 정보를 볼 수 있습니다.
  5. Firebase 콘솔 확인

    • Firebase 콘솔로 이동하여 '인증' 페이지에서 사용자가 목록에 있는지 확인합니다.
      새로고침하여 사용자가 리스트에 나타나는지 확인할 수 있습니다.
  6. 오류 테스트

    • 같은 정보로 폼을 다시 제출하여 Firebase가 중복 이메일을 허용하지 않음을 확인합니다.
      이 경우, 빨간색 경고 메시지가 표시됩니다.

이 강의에서는 Firebase를 사용하여 사용자 등록 요청을 처리하고, 그 응답을 관리하는 방법을 설명하고 있습니다.
Firebase를 사용하면 백엔드 로직에 대해 걱정할 필요가 적어지며, 몇 번의 클릭으로 바로 사용할 수 있는 인증 시스템을 제공받을 수 있습니다.
Firebase는 요청을 보내고, 그들의 서버에서 정보를 검증한 후, 사용자의 자격 증명에 대한 응답을 제공합니다.
개발자는 Firebase가 제공하는 응답만을 처리하면 됩니다.
이러한 접근 방식은 백엔드로직을 간소화하고, 인증 시스템을 빠르게 구축할 수 있게 해줍니다.

src/components/RegisterForm.vue
<script setup lang="ts">
import { ref } from 'vue'
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth'

const schema = ref({
  name: 'required|min:3|max:100|alpha_spaces',
  email: 'required|min:3|max:100|email',
  age: 'required|min_value:18|max_value:100',
  password: 'required|min:9|max:100|excluded:password', // password 단어를 입력하면 유효성 검사를 통과할 수 없다.
  confirm_password: 'passwords_mismatch:@password', // 비밀번호 입력할 때, 비밀번호 재확인차 입력하는 필드 // 위의 password 부분과 일치하는지 확인함
  country: 'required|country_excluded:Antarctica',
  tos: 'required'
})

const userData = ref({
  country: 'USA'
})

const reg_in_submission = ref(false)
const reg_show_alert = ref(false)
const reg_alert_variant = ref('bg-blue-500')
const reg_alert_msg = ref('Please wait! Your acount is being created.')

const register = async (values: {
  age: number
  confirm_password: string
  country: string
  email: string
  name: string
  password: string
  tos: number
}) => {
  // VeeForm 안에 VeeField의 모든 유효성 검사를 통과해야지 values 값이 들어온다.
  // ex.
  // {
  //  age: 31
  //  confirm_password: "asdf"
  //  country: "Germany"
  //  email: "sdf@sdf.com"
  //  name: "sfdf"
  //  password: "asdf"
  //  tos: "1"
  // }

  reg_show_alert.value = true
  reg_in_submission.value = true
  reg_alert_variant.value = 'bg-blue-500'
  reg_alert_msg.value = 'Please wait! Your account is being created.'

  let userCred
  try {
    const auth = getAuth()
    userCred = await createUserWithEmailAndPassword(auth, values.email, values.password)
  } catch (error) {
    reg_in_submission.value = false
    reg_alert_variant.value = 'bg-red-500'
    reg_alert_msg.value = 'An unexpected error occured. Please try again later.'
    return
  }

  reg_alert_variant.value = 'bg-green-500'
  reg_alert_msg.value = 'Success! Your account has been created.'
  console.log(userCred)
}
</script>

<template>
  <!-- Registration Form -->
  <div
    class="text-white text-center font-bold p-4 rounded mb-4"
    v-if="reg_show_alert"
    :class="reg_alert_variant"
  >
    {{ reg_alert_msg }}
  </div>
  <VeeForm :validation-schema="schema" @submit="register" :initial-values="userData">
    <!-- Name -->
    <div class="mb-3">
      <label class="inline-block mb-2">Name</label>
      <VeeField
        type="text"
        name="name"
        class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
        placeholder="Enter Name"
      />
      <ErrorMessage class="text-red-600" name="name" />
    </div>
    <!-- Email -->
    <div class="mb-3">
      <label class="inline-block mb-2">Email</label>
      <VeeField
        type="email"
        name="email"
        class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
        placeholder="Enter Email"
      />
      <ErrorMessage class="text-red-600" name="email" />
    </div>
    <!-- Age -->
    <div class="mb-3">
      <label class="inline-block mb-2">Age</label>
      <VeeField
        type="number"
        name="age"
        class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
      />
      <ErrorMessage class="text-red-600" name="age" />
    </div>
    <!-- Password -->
    <div class="mb-3">
      <label class="inline-block mb-2">Password</label>
      <VeeField name="password" :bails="false" #default="{ field, errors }">
        <input
          type="password"
          class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
          placeholder="password"
          v-bind="field"
        />
        <div class="text-red-600" v-for="error in errors" :key="error">
          {{ error }}
        </div>
      </VeeField>
    </div>
    <!-- Confirm Password -->
    <div class="mb-3">
      <label class="inline-block mb-2">Confirm Password</label>
      <VeeField
        type="password"
        name="confirm_password"
        class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
        placeholder="Confirm Password"
      />
      <ErrorMessage class="text-red-600" name="confirm_password" />
    </div>
    <!-- Country -->
    <div class="mb-3">
      <label class="inline-block mb-2">Country</label>
      <VeeField
        as="select"
        name="country"
        class="block w-full py-1.5 px-3 text-gray-800 border border-gray-300 transition duration-500 focus:outline-none focus:border-black rounded"
      >
        <option value="USA">USA</option>
        <option value="Mexico">Mexico</option>
        <option value="Germany">Germany</option>
        <option value="Antarctica">Antarctica</option>
      </VeeField>
      <ErrorMessage class="text-red-600" name="country" />
    </div>
    <!-- TOS -->
    <div class="mb-3 pl-6">
      <VeeField
        type="checkbox"
        name="tos"
        value="1"
        class="w-4 h-4 float-left -ml-6 mt-1 rounded"
      />
      <label class="inline-block">Accept terms of service</label>
      <ErrorMessage class="text-red-600 block" name="tos" />
    </div>
    <button
      type="submit"
      class="block w-full bg-purple-600 text-white py-1.5 px-3 rounded transition hover:bg-purple-700"
      :disabled="reg_in_submission"
    >
      Submit
    </button>
  </VeeForm>
</template>

<style scoped></style>