Custom Serverless Contact Form

Easy POST action form using FastAPI and Deta

In this article i bring to you a very easy way to handle forms in your site or html templates (a.k.a static site) without "complicated" stuff like php or javascript by using FastAPI with micros and storing the form in a database, in this case DetaBase is the chosen one.

Setup

For our setup, is always recomended a virtualenv. Type in terminal

$ mkdir post && cd post
$ virtualenv env
$ . env/bin/activate
$ mkdir src && cd src
$ touch main.py && touch requirements.txt

Open requirements.txt in the editor and type

fastapi
uvicorn
deta
python-multipart

In terminal type

$ pip install -r requirements.txt

FastAPI POST

Open main.py in the editor

#Importing the libraries
from fastapi import FastAPI, Form, Request 
from deta import Deta

# DetaBase setup
key = 'project-key-generated-by-deta'
deta = Deta(key) # DetaBase instance
db = deta.Base("contact") # Name of the data base

app = FastAPI() # FastAPI instance

# Health check
@app.get('/')
async def index():
    return {'message':'ok'}

# Post method
@app.post('/form')
async def email(
    request: Request,
    contactName: str = Form(...), 
    contactEmail: str = Form(...), 
    contactSubject: str = Form(...), 
    contactMessage: str = Form(...)):
    try:
        insert = db.insert({
                'nombre':contactName, 
                'email':contactEmail, 
                'sujeto':contactSubject, 
                'mensaje':contactMessage,
                })
    except:
        return {'message':'something went wrong'}
    return {'message':'sended'}

So far all good

Run your app, type in terminal

$ uvicorn main:app --reload

Go to 127.0.0.1:8000/docs and test the thing we just made in the interactive docs, if everything went good, go to web.deta.sh open Bases tab and look for the contact database, there should be the post entries.

alt text

Deploy to DetaMicros

In terminal type

$ deta login # If not logged in
$ deta new
Output

Successfully created a new micro
{
        "name": "src",
        "runtime": "python3.7",
        "endpoint": "https://xxxxxx.deta.dev", # yours will be diferent
        "visor": "enabled",
        "http_auth": "disabled"
}
Adding dependencies...

Now go to https://xxxxxx.deta.dev/docs and repeat the test

Contact form

If you use VScode install live server plugin

Create a index.html file and type the code above, in the action="https://xxxxxx.deta.dev/form" paste your domain generated by Deta

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>contact form</title>
</head>

<body>

<link href="contact-form.css" rel="stylesheet">

<div class="fcf-body">

    <div id="fcf-form">
    <h3 class="fcf-h3">Contact us</h3>

    <form id="fcf-form-id" class="fcf-form-class" method="post" action="https://xxxxxx.deta.dev/form">

        <div class="fcf-form-group">
            <label for="Name" class="fcf-label">Your name</label>
            <div class="fcf-input-group">
                <input name="contactName" type="text" id="contactName" placeholder="Name" value="" minlength="2" required="" class="fcf-form-control">
            </div>
        </div>

        <div class="fcf-form-group">
            <label for="Email" class="fcf-label">Your email address</label>
            <div class="fcf-input-group">
                <input name="contactEmail" type="email" id="contactEmail" placeholder="Email" value="" required="" class="fcf-form-control">
            </div>
        </div>

        <div class="fcf-form-group">
            <label for="Subject" class="fcf-label">Your subject</label>
            <div class="fcf-input-group">
                <input name="contactSubject" type="text" id="contactSubject" placeholder="Subject" value="" class="fcf-form-control" required="">
            </div>
        </div>

        <div class="fcf-form-group">
            <label for="Message" class="fcf-label">Your message</label>
            <div class="fcf-input-group">
                <textarea name="contactMessage" id="contactMessage" placeholder="message" rows="10" cols="50" required="" class="fcf-form-control"></textarea>
            </div>
        </div>

        <div class="fcf-form-group">
            <button type="submit" id="fcf-button" class="fcf-btn fcf-btn-primary fcf-btn-lg fcf-btn-block">Send Message</button>
        </div>

    </form>
    </div>

</div>

</body>
</html>

Hit Go live and test the contact form

Thats a Basic setup, we need to redirect after the post was sent and we can do that by change the code in main.py

#Importing the libraries
from fastapi import FastAPI, Form, Request 
from deta import Deta

from fastapi.responses import RedirectResponse
import starlette.status as status

# DetaBase setup
key = 'project-key-generated-by-deta'
deta = Deta(key) # DetaBase instance
db = deta.Base("contact") # Name of the data base

app = FastAPI() # FastAPI instance

# Health check
@app.get('/')
async def index():
    return {'message':'ok'}

# Post method
@app.post('/form')
async def email(
    request: Request,
    contactName: str = Form(...), 
    contactEmail: str = Form(...), 
    contactSubject: str = Form(...), 
    contactMessage: str = Form(...)):
    try:
        insert = db.insert({
                'nombre':contactName, 
                'email':contactEmail, 
                'sujeto':contactSubject, 
                'mensaje':contactMessage,
                })
    except:
        return {'message':'something went wrong'}
    return RedirectResponse(url='/', status_code=status.HTTP_302_FOUND)

Change url='/' to redirect wherever you want, may be your own domain.

BTW go to Akane contact form and drop me a message, this contact form is handled with this tutorial and redirect to "/"

For the final words, you can go fansy and implement a email notification system to let you know when someone has used the contact form (Hint: SMTPlib :D)

For further read, take a look at.