Browse Source

Started on my own API

Fred Damstra (Macbook 2015) 2 năm trước cách đây
mục cha
commit
2c32757c97
6 tập tin đã thay đổi với 173 bổ sung92 xóa
  1. 3 0
      .gitignore
  2. BIN
      api/__pycache__/main.cpython-310.pyc
  3. 10 0
      api/curl_examples.sh
  4. 107 0
      api/examples.py.disabled
  5. 52 92
      api/main.py
  6. 1 0
      requirements.txt

+ 3 - 0
.gitignore

@@ -3,3 +3,6 @@ env/
 *.bak
 tmp*
 *.swp
+
+*.pyc
+__pycache__

BIN
api/__pycache__/main.cpython-310.pyc


+ 10 - 0
api/curl_examples.sh

@@ -0,0 +1,10 @@
+#! /bin/bash
+#
+curl -X 'POST' \
+  'http://127.0.0.1:8000/login' \
+  -H 'accept: application/json' \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "username": "fdamstra"
+  }'
+

+ 107 - 0
api/examples.py.disabled

@@ -0,0 +1,107 @@
+#! /usr/bin/env python3
+# NOTE: Requires python3.10 or above
+
+from enum import Enum
+from fastapi import FastAPI, Query
+from pydantic import BaseModel
+
+app = FastAPI()
+
+# Root is an example, just returns static stuff
+@app.get("/")
+async def root():
+    return {"message": "Hello World"}
+
+
+# /items is an example, just returns the provided value, but must be an int.
+@app.get("/items/{item_id}")
+async def read_items(item_id: int):
+    return {"item_id": item_id}
+
+
+# /models only allows select values. These are machine learning models.
+class ModelName(str, Enum):
+    alexnet = "alexnet"  # FTD: Appears both sides have to match
+    resnet = "resnet"
+    lenet = "lenet"
+
+
+@app.get("/models/{model_name}")
+async def get_model(model_name: ModelName):
+    if model_name is ModelName.alexnet:
+        return {"model_name": model_name, "message": "Deep Learning FTW!"}
+
+    if model_name.value == "lenet":
+        return {"model_name": model_name, "message": "LeCNN all the images."}
+
+    return {"model_name": model_name, "message": "Have some residuals"}
+
+
+# /items/ has query parameters
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+@app.get("/items/")
+async def read_item(skip: int = 0, limit: int = 10):
+    return fake_items_db[skip : skip + limit]  # first value, last value
+
+
+# /items2/ shows how to use an optional parameter
+@app.get("/items2/{item_id}")
+async def read_item2(item_id: str, q: str | None = None):
+    if q:
+        return {"item_id": item_id, "q": q}
+    return {"item_id": item_id}
+
+
+# A POST to /items/, our first example with a body
+class Item(BaseModel):
+    name: str
+    description: str | None = None
+    price: float
+    tax: float | None = None
+
+
+@app.post("/items/")
+async def create_item(item: Item):
+    return item
+
+
+# Validation:
+#   max_length: async def read_items(q: str | None = Query(default=None, max_length=50)):
+#   default: async def read_items(q: str = Query(default="fixedquery", min_length=3)):
+#   Regex: Query(default=None, ..., regex="^fixedquery$"
+#   List: async def read_items(q: list[str] | None = Query(default=None)): # call via ?q=foo&q=bar&q=zoo
+# more: https://fastapi.tiangolo.com/tutorial/query-params-str-validations/
+@app.get("/items3/")
+async def read_items(
+    q: list[str] | None = Query(default=None),
+):  # call via ?q=foo&q=bar&q=zoo
+    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+    if q:
+        results.update({"q": q})
+    return results
+
+
+# More metadata (https://fastapi.tiangolo.com/tutorial/query-params-str-validations/)
+# Big example of lots of metadata
+@app.get("/items4/")
+async def read_items(
+    q: str
+    | None = Query(
+        default=None,
+        alias="item-query",
+        title="Query string",
+        description="Query string for the items to search in the database that have a good match",
+        min_length=3,
+        max_length=50,
+        regex="^fixedquery$",
+        #        gt=0,  # For numeric types, Won't work here, "greater than"
+        #        le=1000, # for numeric types, "less than or equal"
+        deprecated=True,
+    )
+):
+    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+    if q:
+        results.update({"q": q})
+    return results

+ 52 - 92
api/main.py

@@ -1,107 +1,67 @@
 #! /usr/bin/env python3
 # NOTE: Requires python3.10 or above
 
+import json
+import redis
+import uuid
+import sys
+
 from enum import Enum
-from fastapi import FastAPI, Query
-from pydantic import BaseModel
+from fastapi import FastAPI, Query, HTTPException
+from fastapi.encoders import jsonable_encoder
+from pydantic import BaseModel, Field
 
 app = FastAPI()
+r = redis.StrictRedis(host="redis.home.monkeybox.org", port=6379, db=0)
 
-# Root is an example, just returns static stuff
-@app.get("/")
-async def root():
-    return {"message": "Hello World"}
-
-
-# /items is an example, just returns the provided value, but must be an int.
-@app.get("/items/{item_id}")
-async def read_items(item_id: int):
-    return {"item_id": item_id}
-
-
-# /models only allows select values. These are machine learning models.
-class ModelName(str, Enum):
-    alexnet = "alexnet"  # FTD: Appears both sides have to match
-    resnet = "resnet"
-    lenet = "lenet"
-
-
-@app.get("/models/{model_name}")
-async def get_model(model_name: ModelName):
-    if model_name is ModelName.alexnet:
-        return {"model_name": model_name, "message": "Deep Learning FTW!"}
-
-    if model_name.value == "lenet":
-        return {"model_name": model_name, "message": "LeCNN all the images."}
-
-    return {"model_name": model_name, "message": "Have some residuals"}
-
-
-# /items/ has query parameters
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+# Games is a list of implemented games
+class Games(str, Enum):
+    #    ttt3d = "ttt3d"
+    #    euchre = "euchre"
+    #    poker = "poker"
+    #    ...?
+    ttt = "ttt"
 
 
-@app.get("/items/")
-async def read_item(skip: int = 0, limit: int = 10):
-    return fake_items_db[skip : skip + limit]  # first value, last value
-
-
-# /items2/ shows how to use an optional parameter
-@app.get("/items2/{item_id}")
-async def read_item2(item_id: str, q: str | None = None):
-    if q:
-        return {"item_id": item_id, "q": q}
-    return {"item_id": item_id}
-
-
-# A POST to /items/, our first example with a body
-class Item(BaseModel):
-    name: str
-    description: str | None = None
-    price: float
-    tax: float | None = None
+class User(BaseModel):
+    username: str = Field(
+        title="User Name",
+        description="A username to identify yourself.",
+        min_length=3,
+        max_length=255,
+        regex="^[A-Za-z0-9 -_]*$",
+    )
+    secret: str | None = Field(
+        default=None,
+        description="A secret, currently assign from the server",
+        min_length=0,
+        max_length=64,
+        regex="^[A-Za-z0-64]*$",
+    )
 
 
-@app.post("/items/")
-async def create_item(item: Item):
-    return item
+@app.get("/list")
+async def list_games():
+    return {"games": [g.name for g in Games]}
 
 
-# Validation:
-#   max_length: async def read_items(q: str | None = Query(default=None, max_length=50)):
-#   default: async def read_items(q: str = Query(default="fixedquery", min_length=3)):
-#   Regex: Query(default=None, ..., regex="^fixedquery$"
-#   List: async def read_items(q: list[str] | None = Query(default=None)): # call via ?q=foo&q=bar&q=zoo
-# more: https://fastapi.tiangolo.com/tutorial/query-params-str-validations/
-@app.get("/items3/")
-async def read_items(
-    q: list[str] | None = Query(default=None),
-):  # call via ?q=foo&q=bar&q=zoo
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results
+@app.post("/login")
+async def login(user: User):
+    j_user = jsonable_encoder(user)
+    if j_user.get("secret") is not None:
+        raise HTTPException(
+            status_code=500, detail="You may not specify a secret during login"
+        )
+    j_user["secret"] = uuid.uuid4().hex
+    return j_user
 
 
-# More metadata (https://fastapi.tiangolo.com/tutorial/query-params-str-validations/)
-# Big example of lots of metadata
-@app.get("/items4/")
-async def read_items(
-    q: str
-    | None = Query(
-        default=None,
-        alias="item-query",
-        title="Query string",
-        description="Query string for the items to search in the database that have a good match",
-        min_length=3,
-        max_length=50,
-        regex="^fixedquery$",
-        #        gt=0,  # For numeric types, Won't work here, "greater than"
-        #        le=1000, # for numeric types, "less than or equal"
-        deprecated=True,
-    )
-):
-    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
-    if q:
-        results.update({"q": q})
-    return results
+## def main():
+##    print(f"Not intended to be run from command-line")
+##
+##
+###    sys.exit(1)
+##
+##
+## if __name__ == "__main__":
+##    main()

+ 1 - 0
requirements.txt

@@ -1,2 +1,3 @@
 fastapi[all]
 uvicorn[standard]
+redis