Introducing Sanic: The Async Python Web Framework

Let’s Build a CRUD App with Sanic

Mausam Adhikari
5 min readJul 18, 2021

1. What is Sanic?

Sanic is a Python 3.7+ web server and web framework that’s written to go fast. It allows the usage of the async/await syntax added in Python 3.5, which makes your code non-blocking and speedy.

Goal: To provide a simple way to get up and running a high-performance HTTP server that is easy to build, expand, and ultimately to scale.

Features

  • Built-in fast webserver
  • Production-ready
  • Highly scalable
  • ASGI compliant
  • Simple and intuitive API design
  • By the community, for the community

2. How to Sanic

In this tutorial, we will create Restful API using Sanic. Data formats of the REST API include application/JSON.

Prerequisites:

  • Python 3.7+
  • Postman/Insomnia
  • Your preferred Code editor, I will be using VS Code and Pycharm Community Edition

3. Project Setup

Before getting our hands dirty, we need to configure our project.

The following steps are followed for project configuration.

Create new project

Create a project directory named learnsanic and enter the folder.

Configure Virtual environment

To isolate each development environment we will be using a virtual environment.

Before creating the virtual environment we need to ensure we have virtualenv installed. For that execute the following:

virtualenv --version

If we get an error, execute the following:

pip install virtualenv

Now again execute:

virtualenv --version

And you can see the version of your virtual environment.

Now, create a virtual environment named venv by executing the following command:

virtualenv venv

After creating a virtual environment, the new directory can be visualized by executing the following command in the terminal:

ls

After creating a virtual environment, activate the virtual environment by running the following command:

source venv/bin/activate

Now you can see that in the terminal your virtual environment is activated:

Install Required Packages

After activating our virtual environment, install packages that are required for the project.

To install the sanic package in our virtual environment using the pip package manager, execute the following command:

pip install sanic

Create app.py file

Execute the following:

touch app.py 

And open the file in your preferred editor. If you are using VSCode executing the below command will do the work:

code app.py 

Configure Environment

First, create an instance of our Sanic application.

For that import Sanic and create an instance as follows:

4. Develop RESTful API

Before developing API let us know what we are building.

Our School is planning to make a RESTful API using Sanic so that they can add, get, update the details of their students. Initially, we will be focusing on an in-memory database i.e considering a variable as a database and later we will move to an actual SQL database.

Our School wants to have details of students and the fields contain a name, grade, roll, email, phone, subjects, friends initially.

Let’s create our in-memory DB and provide the data in dictionary format and save it in in_memory_student_db variable like in the figure.

To get the data that is just created i.e in_memory_student_db.

Create a get method.

@app.get("/")
async def get_student(request):
return in_memory_student_db

If you are wondering what is @app.get(“/”), then they are called decorators.

For getting the response we will just create a get_student function like above and run the sanic app:

sanic app.app

This will run your server and when you hit the route in insomnia you will get the error as mentioned below:

Sanic.exceptions.ServerError: Invalid response type (need HTTPResponse)

This mentions that we cannot return our list of dictionaries the return type must be HTTPResponse. For that we will import a response from sanic:

from sanic import response
---
---
async def get_student(request):
return response.json(in_memory_student_db)
---
---
@app.post("/")
async def post_student(request):
student = request.json
in_memory_student_db.append(student)
return response.json(student)

Similarly, we write a program for update and delete:

@app.put("/<id_:int>")
async def update_student(request,id_):
student = request.json
in_memory_student_db[id_] = student
return response.json(student)

@app.delete("/<id_:int>")
async def delete_student(request,id_):
del in_memory_student_db[id_]
return response.json({"message":"Deleted student successfully"})

This completes the simplest version of our CRUD operation in Sanic. But is it enough?

  • What if we want to get data if the database is empty?
  • what if we want to update a student that is not in the database?
  • What if we want to delete a student that is not in the database?
  • What if we want to get data by id, not whole data?

Now, remodeling the functions as follows:

To get data by id or whole data, Change get function as follows:

@app.get("/")
async def get_student(request):
id_ = request.args.get("id")
if id_:
if int(id_) in range(len(in_memory_student_db)):
return response.json(in_memory_student_db[int(id_)])
else:
return response.json(
{
"status": "error",
"message": f"data with id {id_} not found. Try with different id!!!"
}
)
return response.json(in_memory_student_db)

To update student that is not in the database, provide a message that there is no data with given id or specification. Change update function as follows:

@app.put("/<id_:int>")
async def update_student(request,id_):
student = request.json
if id_ in range(len(in_memory_student_db)):
in_memory_student_db[id_] = student
else:
return response.json({"error":"No Student with given id"})
return response.json(student)

To delete a student that is not in the database, provide the message that there is no data with the given id or specification. Change delete function as follows:

@app.delete("/<id_:int>")
async def delete_student(request,id_):
if id_ in range(len(in_memory_student_db)):
del in_memory_student_db[id_]
else:
return response.json({"error": "No Student with given id"})
return response.json({"message": "Deleted student successfully"})

This completes CRUD operations.

Next Part:

--

--