Understanding How API works and how to work with it
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,
- build other apps with the same resources
- 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
- get data from https://finance.yahoo.com/
- library to build API
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)):
passdef 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
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