|
| 1 | +"""Copyright 2024 PythonistaGuild |
| 2 | +
|
| 3 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +you may not use this file except in compliance with the License. |
| 5 | +You may obtain a copy of the License at |
| 6 | +
|
| 7 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +
|
| 9 | +Unless required by applicable law or agreed to in writing, software |
| 10 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +See the License for the specific language governing permissions and |
| 13 | +limitations under the License. |
| 14 | +""" |
| 15 | + |
| 16 | +from __future__ import annotations |
| 17 | + |
| 18 | +import asyncio |
| 19 | +import random |
| 20 | + |
| 21 | +import uvicorn |
| 22 | + |
| 23 | +import starlette_plus |
| 24 | + |
| 25 | + |
| 26 | +class APIView(starlette_plus.View, prefix="api"): |
| 27 | + # By default all routes in a View are prefixed with the Views class name... |
| 28 | + # We have two options to control this: |
| 29 | + # 1.) We can set a custom prefix on the View as shown above with the prefix="api" keyword-argument. |
| 30 | + # 2.) Routes can disable the prefix by passing prefix=False to the route decorator. |
| 31 | + # If we didn't set the prefix="api" the prefix for this View would be "/apiview" |
| 32 | + |
| 33 | + def __init__(self, app: App) -> None: |
| 34 | + # This is our App class we make below... |
| 35 | + # We pass this to the view when we create it... |
| 36 | + self.app: App = app |
| 37 | + |
| 38 | + self.some_state: str = "Some cool thing only I know!" |
| 39 | + |
| 40 | + @starlette_plus.route("/random", methods=["GET"]) |
| 41 | + # Remember: This route has a View prefix, so the full path is /api/random |
| 42 | + async def random_roll(self, request: starlette_plus.Request) -> starlette_plus.Response: |
| 43 | + return starlette_plus.JSONResponse({"roll": random.randint(1, 100)}) |
| 44 | + |
| 45 | + @starlette_plus.route("/test", methods=["GET"], prefix=False) |
| 46 | + # This route does NOT have a view prefix, so the full route is just: /test |
| 47 | + async def test_route(self, request: starlette_plus.Request) -> starlette_plus.Response: |
| 48 | + # One of the benefits of having the option to disable the prefix is being able to place routes in classes |
| 49 | + # that contain similar functions or state that may be required |
| 50 | + return starlette_plus.Response(f"Hello from APIView: {self.some_state}") |
| 51 | + |
| 52 | + |
| 53 | +class App(starlette_plus.Application): |
| 54 | + def __init__(self) -> None: |
| 55 | + # Add our View: |
| 56 | + # You can put and contain views in their own files, and import them |
| 57 | + # We pass this application to our View, this is optional but often useful. |
| 58 | + super().__init__(access_log=True, views=[APIView(self)]) |
| 59 | + |
| 60 | + @starlette_plus.route("/") |
| 61 | + async def home(self, request: starlette_plus.Request) -> starlette_plus.Response: |
| 62 | + return starlette_plus.HTMLResponse("""<a href="/test">/test</a><br/><a href="/api/random">/api/random</a>""") |
| 63 | + |
| 64 | + |
| 65 | +async def main() -> None: |
| 66 | + starlette_plus.setup_logging(level=20, root=True) |
| 67 | + app: App = App() |
| 68 | + |
| 69 | + config: uvicorn.Config = uvicorn.Config(app=app, host="localhost", port=8000, access_log=False) |
| 70 | + server: uvicorn.Server = uvicorn.Server(config) |
| 71 | + |
| 72 | + await server.serve() |
| 73 | + |
| 74 | + |
| 75 | +asyncio.run(main()) |
0 commit comments