diff --git a/README.md b/README.md index 0fd648c..e49e379 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,17 @@ This is an API for anime-girls-and-computers [github repo](https://github.com/TH How to host your own AGAC API instance ### 🐬 Docker Method (recommended) -Coming Soonβ„’ +1. Pull the image +```sh +docker pull r3tr0ananas/agac-api:latest +``` +2. Then launch a container with this command. +> *you don't really need to mount a volume but it's recommended* +```sh +docker run -p 8000:8000/tcp -v ./cached_images:/app/assets/cache r3tr0ananas/agac-api:latest +``` +3. Now visit ``localhost:8000`` in your browser and there you go! πŸ‘ +> *if you wanna use docker-compose, [this file](./docker-compose.yml) might be useful to you* ### 🐍 Native Method (recommended for development) @@ -41,8 +51,8 @@ make ```sh make get-repo ``` -5. Run that sh#t. +5. Run. ```sh make run ``` -6. Visit ``localhost:8083`` in your browser, then all should be good! 🌈 +6. Visit ``localhost:8083`` in your browser, then all should be good! 🌈 \ No newline at end of file diff --git a/api/__init__.py b/api/__init__.py index 5da0b9a..f74f503 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -1 +1 @@ -__version__ = "1.1.2" \ No newline at end of file +__version__ = "1.1.3" \ No newline at end of file diff --git a/api/errors.py b/api/errors.py index 8e1b3ba..e87e2ad 100644 --- a/api/errors.py +++ b/api/errors.py @@ -54,12 +54,27 @@ class ImageMetadataNotFound(BaseModel): } } +class RateLimited(BaseModel): + error: str + message: str + + model_config = { + "json_schema_extra": { + "examples": [ + { + "error": "RateLimited", + "message": "Rate limit exceeded: 3 per 1 second (Follow the rates: https://github.com/r3tr0ananas/agac-api/wiki#-rate-limiting)" + } + ] + } + } + def rate_limit_handler(request: Request, exc: RateLimitExceeded): response = JSONResponse( status_code = 429, content = { "error": "RateLimited", - "message": f"Rate limit exceeded: {exc.detail} (Follow the rates: https://github.com/r3tr0ananas/agac-api/wiki#rate-limiting)" + "message": f"Rate limit exceeded: {exc.detail} (Follow the rates: https://github.com/r3tr0ananas/agac-api/wiki#-rate-limiting)" } ) diff --git a/api/main.py b/api/main.py index e9569c0..f717f92 100644 --- a/api/main.py +++ b/api/main.py @@ -19,16 +19,43 @@ ROOT_PATH = (lambda x: x if x is not None else "")(environ.get("ROOT_PATH")) +TAGS_METADATA = [ + { + "name": "image", + "description": "The main endpoints that allow you to get images." + }, + { + "name": "other", + "description": "Other endpoints." + } +] + +DESCRIPTION = """ +
+ + + + The **anime-girls-and-computers** API! + + This is an API for anime-girls-and-computers [github repo](https://github.com/THEGOLDENPRO/anime-girls-and-computers). + + Report bugs [over here](https://github.com/r3tr0ananas/agac-api/issues). + +
+ +Rate limiting applies to the ``/random`` and ``/get`` endpoints. Check out the rate limits [over here](https://github.com/r3tr0ananas/agac-api/wiki#-rate-limiting). +""" + + limiter = Limiter(key_func=get_remote_address, headers_enabled = True) app = FastAPI( title = "AGAC-API", - description = "", + description = DESCRIPTION, license_info = { - "name": "MIT", + "name": "License: MIT", "identifier": "MIT", - }, + }, version = f"v{__version__}", - root_path = ROOT_PATH ) app.state.limiter = limiter @@ -38,9 +65,9 @@ @app.get( "/", - tags = ["misc"] + tags = ["other"] ) -async def root(request: Request): +async def root(): return RedirectResponse(f"{ROOT_PATH}/docs") @app.get( @@ -49,7 +76,7 @@ async def root(request: Request): tags = ["other"] ) async def info(): - """Returns repository information like image count and etc.""" + """Returns repository information like image count and etc.""" return { "version": __version__, "image_count": len(agac.images) @@ -67,7 +94,7 @@ async def info(): } }, ) -async def all(request: Request): +async def all(): return [ image.to_dict() for image in agac.images ] @@ -89,6 +116,10 @@ async def all(request: Request): "model": errors.ImageNotFound, "description": "The image was not Found." }, + 429: { + "model": errors.RateLimited, + "description": "Rate Limit exceeded" + } }, ) @limiter.limit(f"{RATE_LIMIT}/second") @@ -122,7 +153,7 @@ async def get(request: Request, id: str, raw: bool = False): }, }, ) -async def get_metadata(request: Request, id: str): +async def get_metadata(id: str): image = agac.get(id) if image is not None: @@ -140,6 +171,7 @@ async def get_metadata(request: Request, id: str): "/random", name = "Get a random image", tags = ["image"], + description = "To retrieve metadata for a random image, check the `x-image-id` header for the search ID.", response_class = FileResponse, responses = { 200: { @@ -149,6 +181,10 @@ async def get_metadata(request: Request, id: str): }, "description": "Returned an image successfully. 😁", }, + 429: { + "model": errors.RateLimited, + "description": "Rate Limit exceeded" + } }, ) @limiter.limit(f"{RATE_LIMIT}/second") @@ -170,7 +206,6 @@ async def random_image(request: Request, category: str = None, raw: bool = False }, ) async def search( - request: Request, query: str, category: str = None, limit: int = 10 @@ -199,7 +234,7 @@ async def search( "/search/advanced", name = "Advanced Search for images.", tags = ["image"], - description = "You add multiple tags by adding \",\" after each tag", + description = "You can add multiple tags by adding \",\" after each tag", response_class = JSONResponse, responses = { 200: { @@ -209,7 +244,6 @@ async def search( }, ) async def search_advanced( - request: Request, tags: str = "", author: str = None, limit: int = 10 @@ -247,7 +281,5 @@ async def search_advanced( }, }, ) -async def categories(request: Request): - return list(agac.categories.keys()) - - +async def categories(): + return list(agac.categories.keys()) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9893baa --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +services: + agac-api: + image: r3tr0ananas/agac-api:latest + volumes: + - ./cached_images:/app/assets/cache + environment: + ROOT_PATH: "" + restart: unless-stopped \ No newline at end of file