Understanding How API works and how to work with it

Feri Lukmansyah
7 min readMay 14, 2021
image from Unsplash

hello, welcome to my another blog post, after I write Getting Started with FastAPI, in this post we will discuss How API works, and work with it 😄

here is a post topic

  • What is API
  • Why we Need API
  • How To API works
  • Build Simple API projects with FastAPI

What is API

At first, we talked about API or Application Programming Interface, which allows interaction of two or more software to communicate with each other,
with API we do not worry about the platform, for example, you have a website like Facebook, the website can open in a browser, but you need android/IOS apps for your website, how to get resource in your web and append it to your Android/IOS apps? the answer is Using API.

Why we Need API

in some case, we build some apps, where the application can be run on several different platforms, now there are several ways to solve this problem,

  1. build other apps with the same resources
  2. build REST API so that applications can interact with each other

Build other apps with the same resources

the first solution, build similar apps with the same resources such as content, structure, or any other, but similar apps this run on different platform for example in android or web base, this solution is not effective because we will work twice, and this is very time consuming, just imagine we create 10 applications where each application runs on a different platform but uses the same resources.

Build REST API so that applications can interact with each other

now in the second solution, create REST API so that applications can interact with each other, the second solution is better than the first because we will save the time we will use to create the application, in this case, we only need to build 1 line of communication so that applications can communicate with each other and access the same resources without having to rebuild the database and several other sources to save the budget used to build these 10 applications.

Build Simple API project with FAST API framework

now that we learn the concept, it is very important how to implement it in a project, we will build a simple project about how we retrieve historical data from a market, in this case, we will take data from the website finance.yahoo.com, let's build... 😄

install requirements Module

In this project, several modules are required to be installed for this purpose

install required module with this command

pip install 'fastapi[all]' yfinance

now create main.py file and create hello world program 😄

from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def root():
return {"message": "Hello World"}

try run with this command

uvicorn main:app --reload

now open http://localhost:8000/ and check the response, you will see

{"message": "Hello World"}

Create Models

create a file to set database and define models for example named models.py then define the model like this

from sqlalchemy import Column, Integer, String, Numeric

from database import Base


class Stock(Base):
__tablename__ = "stocks"

id = Column(Integer, primary_key=True, index=True)
symbol = Column(String, unique=True, index=True)
price = Column(Numeric(10, 2))
forward_pe = Column(Numeric(10, 2))
forward_eps = Column(Numeric(10, 2))
dividend_yield = Column(Numeric(10, 2))
ma50 = Column(Numeric(10, 2))
ma200 = Column(Numeric(10, 2))

Setting Database Connection for FastAPI

now python file to set a database connection for fastAPI so we can save and add data to our database, for example database.py

from sqlalchemy import create_engine

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.orm import sessionmaker


SQLALCHEMY_DATABASE_URL = "sqlite:///./stock.db"


engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

Setup Main File project

import required module to main.py like this

import models
import yfinance as yf
from fastapi import FastAPI, Request, Depends, BackgroundTasks
from fastapi.templating import Jinja2Templates
from database import SessionLocal, engine
from pydantic import BaseModel
from models import Stock
from sqlalchemy.orm import Session

then initialize the app and create a table from models.py

app = FastAPI()
models.Base.metadata.create_all(bind=engine)

after that initialize template directory to create dashboard and setup frontend

# init templates
templates = Jinja2Templates(directory='templates')

then define pydantic models and function helper dependencies like this

# pydantic models
class StockRequest(BaseModel):
symbol: str


# dependencies
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()

Define Route

now create a route like this

@app.get("/")
def dashboard(request: Request, forward_pe=None, dividend_yield=None, ma50=None, ma200=None, db: Session = Depends(get_db)):
pass
def fetch_stock_data(id: int):
pass
@app.post("/stock")
async def create_stock(stock_request: StockRequest, backround_task: BackgroundTasks, db: Session = Depends(get_db)):
pass

in this case, we create a tree route to

  • display stock
  • Filtering Stock Data
  • add stock

Display Stock

first setup for how to display the stocks, in root route you can code like this

"""
show all stocks in the database and button to add more
button next to each stock to delete from database
filters to filter this list of stocks
button next to each to add a note or save for later
"""

stocks = db.query(Stock)

if forward_pe:
stocks = stocks.filter(Stock.forward_pe < forward_pe)

if dividend_yield:
stocks = stocks.filter(Stock.dividend_yield > dividend_yield)

if ma50:
stocks = stocks.filter(Stock.price > Stock.ma50)

if ma200:
stocks = stocks.filter(Stock.price > Stock.ma200)

stocks = stocks.all()

return templates.TemplateResponse("dashboard.html", {
"request": request,
"stocks": stocks,
"dividend_yield": dividend_yield,
"forward_pe": forward_pe,
"ma200": ma200,
"ma50": ma50
})

first, get data from the database

stocks = db.query(Stock)

then filtering data

if forward_pe:
stocks = stocks.filter(Stock.forward_pe < forward_pe)

if dividend_yield:
stocks = stocks.filter(Stock.dividend_yield > dividend_yield)

if ma50:
stocks = stocks.filter(Stock.price > Stock.ma50)

if ma200:
stocks = stocks.filter(Stock.price > Stock.ma200)

stocks = stocks.all()

then return a response like this

return templates.TemplateResponse("dashboard.html", {
"request": request,
"stocks": stocks,
"dividend_yield": dividend_yield,
"forward_pe": forward_pe,
"ma200": ma200,
"ma50": ma50
})

Filtering Stock Data

the second step is how to filtering data, All the data we need is already in the database, but what if we want to display only specific data? Therefore, we create the fetch_stock route, in this route we handle how to count and display specific data, add this code to fetch_stock route

db = SessionLocal()
stock = db.query(Stock).filter(Stock.id == id).first()

yahoo_data = yf.Ticker(stock.symbol)

stock.ma200 = yahoo_data.info['twoHundredDayAverage']
stock.ma50 = yahoo_data.info['fiftyDayAverage']
stock.price = yahoo_data.info['previousClose']
stock.forward_pe = yahoo_data.info['forwardPE']
stock.forward_eps = yahoo_data.info['forwardEps']
if yahoo_data.info["dividendYield"] is not None:
stock.dividend_yield = yahoo_data.info['dividendYield'] * 100


db.add(stock)
db.commit()

Add Stock

last we create a route for handle how to add stock to our database like this

"""
create new stock and stored to database
:return:
"""

stock = Stock()
stock.symbol = stock_request.symbol
db.add(stock)
db.commit()

backround_task.add_task(fetch_stock_data, stock.id)

return {
"code": "success",
"message": "stock Created"
}

Configuring The Template

after handling the backend last step create a frontend for our app, these a tree step for creating fronted

  • create Base Template
  • Create Dashboard Template

Create Base Template

first, in this project, we will Use semantic-UI CSS framework, create base template like this

<!doctype html>
<
html lang="en">

<
head>
<!-- Required meta tags -->
<meta charset="utf-8">
<
meta name="viewport" content="width=device-width, initial-scale=1">

<
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<
script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<
script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>

<
title>
{% block title %}

{% endblock title %}
</title>
</
head>

<
body>
<
div class="ui container">
{% block contents %}

{% endblock contents %}
</div>
</
body>
</
html>

like flask framework, Fast API support Jinja2 template now we can define block like a flask framework

Create Dashboard Template

create file named dashboard.html inside templates the directory then fill like this

{% extends "base.html" %}

{% block title %}
Dashboard
{% endblock title %}


{% block contents %}
{% endblock contents %}

fill contents block with ajax function for better UI experience, then create a form to add stocks a

<script>
$(document).ready(function() {
$("#add_symbol").click(function() {
$('.ui.modal').modal('show');
});

$("#save").click(function() {

var textareaContent = $("#symbols").val();
var symbols = textareaContent.split("\n");

for (var i = 0; i < symbols.length; ++i) {
console.log(symbols[i]);

$.ajax({
url: '/stock',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ "symbol": symbols[i] }),
dataType: 'json'
});
}

$('.ui.modal').modal('hide');
});
});
</script>

<
h2>Filters</h2>

<
form method="get">

<
div class="ui input">
<
input name="forward_pe" type="text" placeholder="Forward P/E" value="{{ forward_pe or '' }}">
</
div>

<
div class="ui input">
<
input name="dividend_yield" type="text" placeholder="Dividend Yield" value="{{ dividend_yield or '' }}">
</
div>

<
div class="ui checkbox">
<
input name="ma50" type="checkbox" {% if ma50 %}checked="checked"{% endif %}>
<
label>Above 50 Day MA</label>
</
div>

<
div class="ui checkbox">
<
input name="ma200" type="checkbox" {% if ma200 %}checked="checked"{% endif %}>
<
label>Above 200 Day MA</label>
</
div>

<
button type="submit" class="ui button primary">Filter</button>

</
form>

<
button id="add_symbol" class="ui button secondary">Add Symbols</button>


<
table class="ui celled table">
<
thead>
<
tr>
<
th>Symbol</th>
<
th>Price</th>
<
th>Forward P/E</th>
<
th>Forward EPS</th>
<
th>Dividend Yield</th>
<
th>50 Day MA</th>
<
th>200 Day MA</th>
</
tr>
</
thead>
<
tbody>
{% for stock in stocks %}
<tr>
<
td>{{ stock.symbol }}</td>
<
td>{{ stock.price }}</td>
<
td>{{ stock.forward_pe }}</td>
<
td>{{ stock.forward_eps }}</td>
<
td>{{ stock.dividend_yield }}</td>
<
td>{{ stock.ma50 }}</td>
<
td>{{ stock.ma200 }}</td>
</
tr>
{% endfor %}
</tbody>
</
table>

<
div class="ui modal">
<
i class="close icon"></i>
<
div class="header">
Add Stocks
</div>
<
div class="content">
<
div class="ui form">
<
div class="field">
<
label>Symbols</label>
<
textarea id="symbols"></textarea>
</
div>
</
div>
</
div>
<
div class="actions">
<
div id="save" class="ui positive right labeled icon button">
Add Symbols
<i class="plus icon"></i>
</
div>
</
div>
</
div>

Creat Bash Script to Automating command

now in the root projects directory create a directory named scripts and create a bash script for automating running command for example name run_dev.sh

uvicorn main:app --reload

project complete run the project with

source ./scripts/run_dev.sh
display project
add stock
Filtering Result

Conclusion

build stock screener project to help understand API concept and how to implement in the real case with fast API framework will help you understanding API concept and how to work with it, source code in this post available on GitHub, Hopefully, useful and good luck Feri Lukmansyah

--

--