formspree를 적용하기

Dustin Jung·2025년 3월 18일

웹퍼블리싱 공부

목록 보기
8/20

포폴에 들어갈 이메일 폼을 알아보던 중 Formspree라는 무료 api를 발견, 이를 적용해본다.

문제는, 내가 data나 JSON쪽은 지금 이걸 알아보면서 처음 배운거라, 하나 하나 찾아가면서 짜집기 + 주석 정리를 해 보았다.

나중을 위해 기록.

                            <div class="email-form-list">
                                <form id="contact-form" action="https://formspree.io/f/xblglpvl" method="POST">
                                    <div class="contact-form-wrapper">
                                        <label for="email" class="label_hidden" tabindex="-1">이메일:</label>
                                        <input type="email" name="email" id="email" required placeholder="Your email">
                                        
                                        <label for="message" class="label_hidden" tabindex="-1">메시지:</label>
                                        <textarea name="message" id="message" required placeholder="Let's connect! Send me a message."></textarea>
                            
                                        <button type="submit" id="submit-btn">전송</button>
                                    </div>
                                    <div class="contact-form-text -success">
                                        <p class="text_balance point_font">뉴스레터에 가입해 주셔서 감사합니다. 이메일 주소로 전송된 링크를 클릭하여 구독을 확인해 주세요.</p>
                                        <p class="text_balance point_font">최신 뉴스, 프로모션, 이벤트를 알려드리게 되어 기쁩니다. 즐거운 읽기와 쇼핑 되세요!</p>
                                    </div>
                                </form>
                            </div>


<style>

#contact-form {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 320px;
    position: relative;
}

#contact-form input,
#contact-form textarea {
    width: 100%;
    padding: 10px;
    margin: 5px 0;
    border: 1px solid #ddd;
    border-radius: 5px;
    background: white;
}
#contact-form textarea {
    height: 200px;
    border-radius: 10px;
    resize: none;
}

#contact-form button {
    background-color: var(--point3-clr);
    color: var(--body-bg-clr);
    border: none;
    padding: 10px;
    cursor: pointer;
    border-radius: 5px;
    transition: color .3s ease, background-color .3s ease;
    width: 100%;
}
.contact-form-text{
    position: absolute;
    top: 0;
    left: 50%;
    transition: opacity .5s ease-out;
    transform: translateX(-50%);
    font-size: calc(21px * var(--size));
}
#contact-form.is-submitted .contact-form-wrapper{
    opacity: 0;
    pointer-events: none;
    transition: none;
}
.contact-form-text.-success{
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-column-gap: var(--grid-gutter);
}
#contact-form:not(.is-submitted) .contact-form-text.-success{
    opacity: 0;
    pointer-events: none;
    transition: none;   
}
.contact-form-text.-success p{
    letter-spacing: .65px;
    text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.3);
}

</style>
<script>

        function formBtnFunction() {
            let theBtn = document.getElementById("submit-btn");
            let emailInput = document.getElementById("email");
            let messageInput = document.getElementById("message");
            let form = document.getElementById("contact-form");
        
            form.addEventListener("submit", function (e) {
                e.preventDefault(); // 1. html 기본 폼 제출을 막는다 => Formspree에서 필수,
        
                theBtn.disabled = true;
                emailInput.disabled = true;
                messageInput.disabled = true;
        
                // Formspree API로 JSON 데이터 전송
                let formData = {
                    email: emailInput.value,
                    message: messageInput.value,
                };
        
                fetch(form.action, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Accept": "application/json",
                    },
                    body: JSON.stringify(formData),
                })
                .then(response => {
                    if (response.ok) {
                        // 성공적으로 전송됨
                        setTimeout(function () {
                            form.classList.add("is-submitted");
                            setTimeout(function () {
                                // 입력값 초기화
                                emailInput.value = "";
                                messageInput.value = "";
        
                                // Placeholder 원래대로 복구
                                emailInput.placeholder = "Your email";
                                messageInput.placeholder = "Let's connect! Send me a message.";
        
                                // 입력 필드 & 버튼 다시 활성화
                                emailInput.disabled = false;
                                messageInput.disabled = false;
                                theBtn.disabled = false;
        
                                form.classList.remove("is-submitted");
                            }, 5000);
                        }, 3000);
                    } else {
                        alert("전송에 실패했습니다. 다시 시도해주세요.");
                        emailInput.disabled = false;
                        messageInput.disabled = false;
                        theBtn.disabled = false;
                    }
                })
                .catch(error => {
                    alert("에러가 발생했습니다. 네트워크를 확인해주세요.");
                    emailInput.disabled = false;
                    messageInput.disabled = false;
                    theBtn.disabled = false;
                });
            });
        }

</script>

하나 하나 파헤쳐보자.

1. 기본 이벤트 막기

formspree는 JSON 형식을 요구한다. 그래서, javascript로 form에 관해 만질거면, 일단 html form 데이터 보내는 기본 형식을 event.preventDefault();로 막아야 한다.

2. 객체 data 만들기

formspree는 서버다. 즉, 그 서버에 보낼 데이터값을 만들어야 한다.

3. fetch() 사용.

fetch()는 자바스크립트에서 서버와 응답을 주고 받을 때 사용하는 함수다.

마찬가지로, response 또한 서버에서 오는 응답 객체이다.

4. 객체 data를 JSON 문자열로 변환

자바스크립트 data 객체는 말 그대로 자바스크립트 객체다.

문제는 formspree는 JSON data가 필요하기 때문에, 이걸 JSON.springify로 변환해줘야 한다.

참고로,

                headers: {
                    "Content-Type": "application/json",
                    "Accept": "application/json",
                },

이 부분은, 보낼 데이터가 json이라는 것을 알려주면서, 응답 데이터를 json으로 달라고 요청하는 것이다.

5. response.ok

response.ok는 서버에서 받은 응답 값이 true임을 판별하는 자바스크립트 기능이다.

여기서 else와 catch가 다른데,

else문은 말 그대로, 서버에서 받은 응답값이 오류일 때 else문이 적용되는 것이고,

catch error는 네트워크 문제일 확률이 높다.

이를 간단하게 주석으로 정리해 보았으며, 아래에 써 놓겠다.


<script>

        function formBtnFunction() {
            let theBtn = document.getElementById("submit-btn");
            let emailInput = document.getElementById("email");
            let messageInput = document.getElementById("message");
            let form = document.getElementById("contact-form");
        
            form.addEventListener("submit", function (e) {
                e.preventDefault(); // 1. html 기본 폼 제출을 막는다 => Formspree에서 필수,
        
                theBtn.disabled = true;
                emailInput.disabled = true;
                messageInput.disabled = true; // 중복 제출 방지
        
                // Formspree API로 JSON 데이터 만들기
                let formData = {
                    email: emailInput.value,
                    message: messageInput.value,
                };
        
                fetch(form.action, { //fetch()는 JavaScript에서 서버와 데이터를 주고받을 때 사용하는 함수, 웹사이트에서 서버로 요청을 보내고, 서버에서 응답을 받아오는 역할
                    method: "POST", //form.action의 method를 가져오고, 
                    headers: {
                        "Content-Type": "application/json", //formspree에서 필수, 보낼 데이터가 json이라는 걸 알려줌
                        "Accept": "application/json", // formspree에서 필수, 받을 데이터를 json으로 보내달라고 요쳥하는 것.
                    },
                    body: JSON.stringify(formData), // formData는 자바스크립트 객체임. 그러나 서버는 JSON 문자열이 필요해서, formData를 JSON.stringify로 변환한 것. method가 post고 우리가 데이터를 보내는 거기 때문에, body: 가 필수적이다.
                    // 만약 여기서 body가 없으면, 서버는 요청은 확인하지만, 뭘 보내는 지 인식하지 못함.
                })
                .then(response => { // response는 서버에서 오는 응답 객체, 이 응답 객체에는 응답 상태, 응답 본문(JSON 데이터), 헤더 정보 등이 들어 있음.
                    if (response.ok) { // fetch API에서 제공하는 기본 속성, respons.ok는 서버 응답이 성공했는지(true/false)를 확인하는 속성.
                        // 즉, 성공적으로 적용되었을 경우, 
                        setTimeout(function () {
                            form.classList.add("is-submitted"); 
                            setTimeout(function () {
                                // 입력값 초기화
                                emailInput.value = "";
                                messageInput.value = "";
        
                                // Placeholder 원래대로 복구
                                emailInput.placeholder = "Your email";
                                messageInput.placeholder = "Let's connect! Send me a message.";
        
                                // 입력 필드 & 버튼 다시 활성화
                                emailInput.disabled = false;
                                messageInput.disabled = false;
                                theBtn.disabled = false;
        
                                form.classList.remove("is-submitted");
                            }, 5000);
                        }, 3000);
                    } else { // 서버가 '응답을 보냈지만 실패한 경우, 예시로 오류코드 400, 401, 500'
                        alert("전송에 실패했습니다. 다시 시도해주세요.");
                        emailInput.disabled = false;
                        messageInput.disabled = false;
                        theBtn.disabled = false;
                    }
                })
                .catch(error => { // 이쪽 에러는 네트워크 쪽 오류일 확률이 높음, 인터넷 끊김, 서버 다운, fetch()오류
                    alert("에러가 발생했습니다. 네트워크를 확인해주세요.");
                    emailInput.disabled = false;
                    messageInput.disabled = false;
                    theBtn.disabled = false;
                });
            });
        }

</script>
profile
더스틴 정입니다

0개의 댓글