Browse Source

Initial commit - Basically tutorial examples

Fred Damstra (Macbook 2015) 2 years ago
commit
6725e10216
6 changed files with 156 additions and 0 deletions
  1. 5 0
      .gitignore
  2. 34 0
      README.md
  3. BIN
      api/__pycache__/main.cpython-310.pyc
  4. 107 0
      api/main.py
  5. 8 0
      api/start.sh
  6. 2 0
      requirements.txt

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+env/
+
+*.bak
+tmp*
+*.swp

+ 34 - 0
README.md

@@ -0,0 +1,34 @@
+# Game Server - Containerized Method
+
+A game server to provide simple games, intended for testing of strategies, AI, and general playing around. As such, do not expect strong anti-cheat mechanisms, or really much of anything other than an impartial game server that can run separately from the client code.
+
+## Present State
+
+Dreaming it up.
+
+## Architecture
+
+All of this is brand new to me, so expect mistakes and amateur moves.
+
+Giving [FastAPI](https://fastapi.tiangolo.com/) a shot.
+FastAPI inherits [starlette](https://www.starlette.io/), so look into that functionality some day, too.
+Expects a redis container/cluster somewhere to store data.
+
+### API Notes
+
+At this point, almost all operations use POST
+
+### Notes for myself
+
+FastAPI recommendation is "if your \[function\] doesn't have to communicate with anything else and wait for it to respond, use `async def` instead of `def`".
+
+Auto Generated API docs are [here](http://127.0.0.1:8000/docs)
+Schema is [here](http://127.0.0.1:8000/openapi.json)
+
+For curl, you may want to follow redirects:
+
+```
+curl --location http://127.0.0.1:8000/example
+```
+
+Request bodies use [pydantic](https://docs.pydantic.dev/)

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


+ 107 - 0
api/main.py

@@ -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

+ 8 - 0
api/start.sh

@@ -0,0 +1,8 @@
+#! /bin/bash
+. ../env/bin/activate
+
+
+# main: the file main.py (the Python "module").
+# app: the object created inside of main.py with the line app = FastAPI().
+# --reload: make the server restart after code changes. Only use for development.
+uvicorn main:app --reload

+ 2 - 0
requirements.txt

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