Skip to content

Instantly share code, notes, and snippets.

@uzluisf
Last active June 15, 2022 23:00
Show Gist options
  • Save uzluisf/5312d33f75346aa0e80939094409fa40 to your computer and use it in GitHub Desktop.
Save uzluisf/5312d33f75346aa0e80939094409fa40 to your computer and use it in GitHub Desktop.
Simple JSON API
  1. Create directory json-api and place main.py and data.json in it.

  2. Create a Python environment and install the packages fastapi and "uvicorn[standard]":

$ python3 -m virtualenv venv
$ source venv/bin/activate
$ pip install fastapi
$ pip install "uvicorn[standard]"

To save this packages list into requirements.txt, do pip freeze > requirements.txt. Afterwards, you can simply install the packages in requirements.txt in a new environment as follows:

$ pip install -r requirements.txt
  1. Run the code:
$ uvicorn main:app --reload
INFO:     Will watch for changes in these directories: ['/home/luis/json-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [22187] using watchgod
INFO:     Started server process [22189]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
  1. HTTP requests:
  • GET /recipes
$ curl -X 'GET' \
  'http://127.0.0.1:8000/recipes' \
  -H 'accept: application/json'
{"recipeNames":["scrambledEggs","garlicPasta","butteredBagel","chai"]}
  • GET /recipes/details/{recipe_name}
$ curl -X 'GET' \
  'http://127.0.0.1:8000/recipes/details/garlicPasta' \
  -H 'accept: application/json'
{"details":{"ingredients":["500mL water","100g spaghetti","25mL olive oil","4 cloves garlic","Salt"],"numSteps":5}}
  • POST /recipes
$ curl -X 'POST' \
  'http://127.0.0.1:8000/recipes/' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
"name" : "butteredBagel",
"ingredients" : ["1 bagel", "butter"],
"instructions" : ["cut the bagel", "spread butter on bagel"]
}'
{"detail":"Recipe already exists"}
  • PUT /recipes
$ curl -X 'PUT' \
  'http://127.0.0.1:8000/recipes/' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
"name" : "butteredBagel",
"ingredients" : ["1 bagel", "2 tbsp butter"],
"instructions" : ["cut the bagel", "spread butter on bagel"]
}'
{
"recipes": [
{
"name": "scrambledEggs",
"ingredients": [
"1 tsp oil",
"2 eggs",
"salt"
],
"instructions": [
"Beat eggs with salt",
"Heat oil in pan",
"Add eggs to pan when hot",
"Gather eggs into curds, remove when cooked",
"Salt to taste and enjoy"
]
},
{
"name": "garlicPasta",
"ingredients": [
"500mL water",
"100g spaghetti",
"25mL olive oil",
"4 cloves garlic",
"Salt"
],
"instructions": [
"Heat garlic in olive olive",
"Boil water in spot",
"Add pasta to boiling water",
"Remove pasta from water and mix with garlic olive oil",
"Salt to taste and enjoy"
]
},
{
"name": "butteredBagel",
"ingredients": [
"1 bagel",
"2 tbsp butter"
],
"instructions": [
"cut the bagel",
"spread butter on bagel"
]
},
{
"name": "chai",
"ingredients": [
"400mL water",
"100mL milk",
"5g chai masala",
"2 tea bags or 20g loose tea leaves"
],
"instructions": [
"Heat water until 80C",
"Add milk, heat until 80C",
"Add tea leaves/tea bags, chai masala; mix and steep for 3-4 minutes",
"Remove mixture from heat; strain and enjoy"
]
}
]
}
from fastapi import FastAPI, status, HTTPException
from pydantic import BaseModel
import json
# A recipe schema.
class Recipe(BaseModel):
name: str
ingredients: list[str]
instructions: list[str]
# load up json into a python dict. This will serve
# as our backend.
datafile = "data.json"
with open(datafile, "r") as read_file:
recipes = json.load(read_file)
app = FastAPI()
@app.get("/recipes", status_code=200)
def get_recipes():
"""
Get all recipe names.
"""
return { "recipeNames" : [recipe['name'] for recipe in recipes['recipes']] }
@app.get("/recipes/details/{recipe_name}", status_code=200)
def get_ingredients(recipe_name: str):
"""
Take a recipe name as a `string` parameter and return the ingredients and
the number of steps in the steps in the recipe as JSON.
"""
for recipe in recipes['recipes']:
if recipe['name'] == recipe_name:
ingredients = recipe['ingredients']
numSteps = len(ingredients)
return { 'details' : { "ingredients" : ingredients, "numSteps" :
numSteps } }
return {}
@app.post("/recipes/", status_code=201)
async def add_recipe(recipe: Recipe):
"""
Add additional recipes in the existing format to the backend.
"""
new_recipe = recipe.dict()
for recipe in recipes['recipes']:
if new_recipe['name'] == recipe['name']:
raise HTTPException(status_code=401, detail=f'Recipe already exists')
with open(datafile, "w") as file:
recipes['recipes'].append(new_recipe)
file.write(json.dumps(recipes))
file.close()
@app.put("/recipes/", status_code=204)
async def update_recipe(recipe: Recipe):
"""
Update existing recipes.
"""
new_recipe = recipe.dict()
for recipe in recipes['recipes']:
if new_recipe['name'] == recipe['name']:
recipe['ingredients'] = new_recipe['ingredients']
recipe['instructions'] = new_recipe['instructions']
with open(datafile, "w") as file:
file.write(json.dumps(recipes))
file.close()
return None
raise HTTPException(status_code=404, detail="Recipe does not exist")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment