Git Commit: user registration in webapp
Well, that was pretty good, Now, our users will see the details of a blog post. But what if someone wants to create a blog post? Do you remember, each blog post should have an author? That means we need to provide our users with a way to register and log in. In this post, we are going to see the signup/registration part. Let's put our code for user registration in a new file apps > v1 > route_login.py
import json
from fastapi import APIRouter, Request, Depends
from fastapi.templating import Jinja2Templates
from fastapi import responses, status, Form
from sqlalchemy.orm import Session
from db.session import get_db
from schemas.user import UserCreate
from db.repository.user import create_new_user
from pydantic.error_wrappers import ValidationError
templates = Jinja2Templates(directory="templates")
router = APIRouter()
@router.get("/register")
def register(request: Request):
return templates.TemplateResponse("auth/register.html",{"request":request})
@router.post("/register")
def register(request: Request, email: str = Form(...), password: str= Form(...), db: Session = Depends(get_db)):
errors = []
try:
user = UserCreate(email=email,password=password)
create_new_user(user=user, db=db)
return responses.RedirectResponse("/?alert=Successfully%20Registered",status_code=status.HTTP_302_FOUND)
except ValidationError as e:
errors_list = json.loads(e.json())
for item in errors_list:
errors.append(item.get("loc")[0]+ ": " + item.get("msg"))
return templates.TemplateResponse("auth/register.html",{"request":request,"errors":errors})
Let's understand what's happening:
Moving on to the next section, We need to tell our fastapi app that we have made this functionality. So, its time to modify apps > base.py
from apps.v1 import route_blog
from apps.v1 import route_login
from fastapi import APIRouter
app_router = APIRouter()
#new
app_router.include_router(
route_login.router, prefix="/auth", tags=[""], include_in_schema=False
)
The final touch, We need to make an HTML form which should display a form as well as should display the errors in the form. Plus, any data which the user fills in should be there if the form has an error. That's why we have value = {{username}} kind of thing. Let's create a template at templates > auth > register.html
{% extends "base.html" %}
{% block title %}
<title>Sign Up</title>
{% endblock %}
{% block content %}
{% for error in errors %}
<div class="alert alert-danger">
<li>{{error}}</li>
</div>
{% endfor %}
<div class="container">
<div class="text-center display-4">Register</div>
<div class="row mt-3 mb-5">
<div class="col-3"></div>
<div class="col-6">
<form method="POST">
<label>Email</label>
<input type="email" required class="form-control mb-2" name="email" value="{{email}}" placeholder="Enter your email">
<label>Password</label>
<input type="password" required placeholder="Choose a secure password" value="{{password}}" name="password" class="form-control mb-2">
<button type="submit" class="btn btn-outline-success">Create an Account</button>
</form>
</div>
<div class="col-3"></div>
</div>
</div>
{% endblock %}
Woahhh! That was a lot of work. One last thing, promise this is last 😁
if everything works correctly, We might want to redirect the user to the homepage and show an alert message that should say "Successfully Registered". To implement this, we need to an optional query parameter to our homepage route. (apps > v1 > route_blog.py)
@router.get("/")
def home(request: Request,alert: Optional[str] = None, db: Session = Depends(get_db)):
blogs = list_blogs(db=db)
return templates.TemplateResponse(
"blog/home.html", {"request": request, "blogs": blogs,"alert":alert}
)
Obviously, since, it is now passing an alert message to the frontend, we will need to catch the alert message and display it as an alert.
{% extends "base.html" %}
{% block title %}
<title>Algoholic</title>
{% endblock %}
{% block content %}
{% with alert=alert %}
{% include "components/alert.html" %}
{% endwith %}
<!-- Old content here -->
{% endblock %}
Finally, one last thing, we would need to implement templates > components > alert.html
{% if alert %}
<div class="alert alert-info" role="alert">
{{alert}}
</div>
{% endif %}
Time to test our work now. visit http://127.0.0.1:8000/auth/register/ and you should see the form and it should be working properly. There is a huge scope for improvement, especially in this code, We should have done much more validation in the implementation of the form, which I am leaving up to you. We should have also checked if a user with the same email already exists. If the same email exists, Our system will raise a validation error. As an assignment, I leave it up to you to catch the exception and show a proper message. Also, we have not passed the email and password, in case an error occurs. It makes it irritating for the end users to fill in the same information all again.
Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.
We know, we might make it hard for you but definitely worth the efforts.
© Copyright 2022-23 Team FastAPITutorial