Create a Simple API with FastAPI (Part 1)

Create a Simple API with FastAPI (Part 1)

Part 1

api mem.jpg

Creating an API has not been this much easier. In the tutorial, we will use FASTAPI to create a simple API but first what the heck is an API and what terms are we to understand?

What is an API?

Let's destructure the definition. An API technically stands for

  • A - Application
  • P- Programming

  • I - Interface

It is basically the bridge between your app's frontend and backend (server & database)

An APIs operates through ‘requests’ and ‘responses.’ When an API requests to access data from a web application or server, a response is expected. The location where the API sends a request and where the response emanates is what is known as an endpoint. Reputedly, the endpoint is the most crucial part of the API since it’s where the developer will implement to make their requests.

Endpoint

An API endpoint is the touchpoint of entry between an API and server, basically is one fancy word for a URL of a server/ service. It is a means by which an API fetches data from a server to perform a task.
For example: 127.0.0.8000/ get_items . get_items is the endpoint

Endpoint Methods used

GET - gets / returns data

POST - creates new data

PUT - updates data

DEL - deletes data

What is FASTAPI

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. Its key features include

Fast: Very high performance and on par with NodeJS and Go (thanks to Starlette for the web parts and Pydantic for the data parts). With it being one of the fastest Python frameworks available.

Fast to code: Increase the speed to develop features by about 200% to 300%.

Fewer bugs: Reduce about 40% of human (developer) induced errors.

Intuitive: Great editor support. Completion everywhere. Less time debugging.

Easy & Short: Designed to be very easy to use and learn. Less time reading docs. Trust me their docs are way easier and simpler. FASTAPI allows for minimised code duplication and multiple features from each parameter declaration.

Robust: Get production-ready code. With automatic interactive documentation. (That's the best part since you can also test your API in the docs without having to use POSTMAN) and it's based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.

NB: FastApi has swagger embedded so it is easier to have a very nice API to test your data endpoints with

Now let's code

via GIPHY

First, we install FASTAPI and a server called uvicorn

pip install fastapi

pip install uvicorn

Import module

from fastapi import FASTAPI

Create an instance

app = FASTAPI()

Start creating your API

@app.get("/")
def index():
    return {"name": "First Item"}

Path Parameter

It is used to return data relating to an input

@app.get("/get-items/{items_id}")
def get_items(items_id: int = Path(None, description="Items ID you want to view")):
    return items[items_id]

Query Parameter

A query is used to pass a value into a URL


@app.get("/get-by-name")
def get_items(*, name: Optional[str] = None, test: int):
    for items_id in items:
        if items[items_id]["name"] == name:
            return items[items_id]
    return {"error": "Item not found"}

Combining Query & Path Parameters

@app.get("/get-by-name/{items_id}")
def get_items(*, items_id: int, name: Optional[str] = None, test: int):
    for items_id in items:
        if items[items_id]["name"] == name:
            return items[items_id]
    return {"error": "Item not found"}

Request Body & Post Method

@app.post("/create-items/{items_id}")
def create_items(items_id: int, item: Items):
    if items_id in items:
        return {"error": "Item Already Exist"}
    items[items_id] = item  # create new object of item
    return items[items_id]

Put Method

@app.put("/update-items/{items_id}")
def update_items(items_id: int, item: UpdateItem):
    if items_id not in items:
        return {"error": "Item does not exist"}

    if item.name != None:
        items[items_id].name = item.name  # does not overide update if they are are none

    if item.price != None:
        items[items_id].name = item.price

    if item.expiry_year != None:
        items[items_id].name = item.expiry_year

    items[items_id] = item
    return items[items_id]

Delete Method


@app.delete("/delete-items/{items_id}")
def delete_items(items_id: int):
    if items_id not in items:
        return {"error": "Item does not exist"}
    del items[items_id]
    return {"message": "Item deleted successfully"}

Full code for the project

from fastapi import FastAPI, Path
from pydantic import BaseModel
from typing import Optional


app = FastAPI()


items = {
    1: {"name": "rice", "price": 187, "expiry_year": 2024},
    2: {"name": "beans", "price": 19, "expiry_year": 2031},
    3: {"name": "sardine", "price": 201, "expiry_year": 2022},
    4: {"name": "soap", "price": 21, "expiry_year": 2031},
    5: {"name": "choco", "price": 50, "expiry_year": 2025},
}


class Items(BaseModel):
    name: str
    price: int
    expiry_year: int


class UpdateItem(BaseModel):
    name: Optional[str] = None
    price: Optional[int] = None
    expiry_year: Optional[int] = None


@app.get("/")
def index():
    return {"item": "First Item"}


# Path Parameters


@app.get("/get-items/{items_id}")
def get_items(items_id: int = Path(None, description="Items ID you want to view")):
    return items[items_id]


# Query Parameters


@app.get("/get-by-name")
def get_items(*, name: Optional[str] = None, test: int):
    for items_id in items:
        if items[items_id]["name"] == name:
            return items[items_id]
    return {"error": "Item not found"}


# Combining Query & Path Parameters
@app.get("/get-by-name/{items_id}")
def get_items(*, items_id: int, name: Optional[str] = None, test: int):
    for items_id in items:
        if items[items_id]["name"] == name:
            return items[items_id]
    return {"error": "Item not found"}


# Request Body & Post Methods


@app.post("/create-items/{items_id}")
def create_items(items_id: int, item: Items):
    if items_id in items:
        return {"error": "Item Already Exist"}
    items[items_id] = item  # create new object of item
    return items[items_id]


# put method


@app.put("/update-items/{items_id}")
def update_items(items_id: int, item: UpdateItem):
    if items_id not in items:
        return {"error": "Item does not exist"}

    if item.name != None:
        items[items_id].name = item.name  # does not overide update if they are are none

    if item.price != None:
        items[items_id].name = item.price

    if item.expiry_year != None:
        items[items_id].name = item.expiry_year

    items[items_id] = item
    return items[items_id]


@app.delete("/delete-items/{items_id}")
def delete_items(items_id: int):
    if items_id not in items:
        return {"error": "Item does not exist"}
    del items[items_id]
    return {"message": "Item deleted successfully"}