Demo Video: https://vimeo.com/873499383
- Python
- Flask
- Flask-WTF
- WTF Forms
- Flask Bootstrap
- SendGrid
- Pytest
- HTML
- CSS
The project.py file contains the routes for the application and the contact form functionality. If a user filled out the contact form, it is validated with Flask WTForms and then the submission is printed in the logs. If the form submission was successful a success flag is sent to the contact.html page and displays a message to the user.
Each route in the project.py file has a function to return a Flask render_template function with the corresponding html web page. For the home page, which routes with a "/" and is defined in the app.route decorator, it returns the index.html page. Using Jinja templates, I designed the navigation bar and footer to go around the content for each page in the base.html file. Jinja templates can extend or inherit from another template, so the index.html page extends the base.html file with the Jinja syntax. Then in the block content from Jinja, I added a card with Flask Bootstrap styling to display a photo and heading text overlayed on it to welcome the user.
The about page is routed as "/about" in the project.py file with a function that retuns the Flask render_template function to display the about.html page. This page is also styled with Flask Bootstrap and the image is hosted on github for ease of use. The content is a back story about me.
The contact page is routed in project.py as "/contact" with a function that returns the Flask render_template function to display the contact.html page. This page is styled with a combination Flask Bootstrap and some internal CSS on the base.html file. I also used Flask-WTForms to build the ContactForm class and invoke it within the contact function. With Flask Forms, I used validators to require the fields and check the email field. As I mentioned above, if the form is successfully submitted, a flag is sent to the contact page that is was a success and to display a confirmation message. Submitting the form also triggers a POST method which also initiates the form validation and prints the submission into the logs. The form submission also triggers an email to be sent with the SendGrid API to my verified email so that I can see if someone filled out the contact form.
As for my design choices, I took time to think about what I really wanted to do for my project. I considered building something fun like a game but it made more sense to me to create something useful, at least for myself. In using the Flask library, I kept the python scripting in one file since it was a small application. If I had a larger application, I would have put the routes in their own file. Same for the form classes and function, they would have been placed in thier own python file if it was a larger application or form. It made sense to me to keep each html page separate and then render them into the project.py file in each route function. I went with minimal styling to use the power of Flask Bootstrap. It was very easy for me to use and allowed me to spend more time on coding rather than custom styling everything. Jinja templates was also a powerful way to inject python programming into the html files. It made the physical design of the pages much faster since the files could extend or inherit from another. In my production application on Vercel, the contact form integrates with SendGrid to send me an email if the form is filled out, which is more secure than SMTP or smtplib as a Python library. Flask-WTForms just made sense since there were a lot built in functions that worked well with Flask in general. I also chose to deploy my project in Vercel since they had a Flask app option that would directly deploy from a public Github repository. The images are linked from my public github repository for the Vercel deployment.
The test_project.py file uses pytest to test the Flask Application and each route or page. Each test uses the test_client() method from Flask that contains the features needed to make HTTP requests to the application under test. Each route or endpoint is tested with a GET request and the code then asserts that the response recieved, which should be a 200 status code. Also checking in the response data that it contains the correct page title for each endpoint. I also tested that the contact form sends back a 200 status code when the form is filled out by provide data for each field in a dict.
In conclusion, I learned how to use the Flask library for python and how to build a small working application by reading the documentation and looking at examples that were provided there. It was fun until I dove into the world of SMTP with my contact form and learned the security measures that been put in place in the last year or so even. I was also reminded how long it can take to write or design content and spend quite a bit of time on making my application user interface look good with Flask Bootstrap, CSS, and HTML. Although I used a minimal looking web design, it still took a lot of time and thought into how I wanted to build the base of the web pages. The contact page was actually the most challenging of all pages. The routing part was not as difficult but when it came to the functions, I ran into a lot of set backs. Initially, I wanted to use smtplib to have the form send me an email with the contact form submission with a gmail account. Through reading Google's Gmail API documentation and forums, I found that Gmail does not allow less secure apps to send through SMTP without an app password or OAuth 2.0. For this project, I did end up using an email service from Twilio SendGrid to have the ease of their API and security in my production application which is shown in the Demo URL and video.