def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'mreschke.wiki.http.api' # Include dynamic model CRUD API endpoints (the "auto API")! @route.group() #@route.group(scopes=['x']) # These scopes are APPENDED to auto api acopes, user must have both #def autoapi(): #def autoapi(scopes=['authenticated']): def autoapi(): # These scopes are used instead of auto api scopes route.include(ModelRouter, options={'scopes': []}) # This sets NO scopes, meaning fully public API #route.include(ModelRouter, options={'scopes': []}) # Use default auto api scopes (posts.read, posts.create...) #route.include(ModelRouter) #route.controller('post', tags=['Post']) # Return router return route
def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'acme.appstub.http.api' # Include dynamic model CRUD API endpoints (the "auto API")! @route.group() def autoapi(): #def autoapi(scopes=['authenticated']): route.include(ModelRouter) # Public Routes route.controller('welcome') # Example of Private Routes # @route.group(scopes=['authenticated']) # def private_routes(): # route.controller('private_controller') # Return router return route
def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'uvicore.auth.http.api' @route.group(tags=['Auth']) def private_routes(): @route.get('/auth/userinfo') def userinfo(): return {'hi': 'there'} # Return router return route
def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'uvicore.auth.http.api' @route.group(tags=['Auth'], scopes=['authenticated']) def authenticated_routes(): @route.get('/userinfo') def userinfo(request: Request) -> UserInfo: """Detailed User Info Including Roles and Permissions""" # HTTP example # TOKEN=$(fa-api tgb-local login wiki-vue-app token) # http GET 'https://wiki-api-local.triglobal.io/api/auth/userinfo' Authorization:"Bearer $TOKEN" # Get the user from the request user: UserInfo = request.scope['user'] # uvicore.auth.user_info.UserInfo( # id=2, # uuid='823003ad-6e1f-42ed-a024-f45f400c1b30', # username='******', # email='*****@*****.**', # first_name='Matthew', # last_name='Reschke', # title='', # avatar='', # groups=['Administrator'], # roles=['Administrator'], # permissions=['authenticated', 'admin'], # superadmin=True, # authenticated=True # ) # Return UserInfo return user # Return router return route
def register(self, route: ApiRouter): # ---------------------------------------------------------------------- # Example: Basic route responding with a view dict to JSON blob # ---------------------------------------------------------------------- @route.get('/example1', tags=['Examples']) async def example1() -> Dict: """This docstring shows up in openapi""" return {'welcome': 'to uvicore API!'} # ---------------------------------------------------------------------- # Example: Route returning a Model schema with python return type hint # ---------------------------------------------------------------------- @route.get('/example2', tags=['Examples']) async def example2()) -> List[models.Post]: """This docstring shows up in openapi""" return await models.Post.query().get() # ---------------------------------------------------------------------- # Example: Route returning a Model schema using response_model # ---------------------------------------------------------------------- @route.get('/example3', response_model=List[models.Post], tags=['Examples']) async def example3(): return await models.Post.query().get() # ---------------------------------------------------------------------- # Example: Auth guard using scopes shortcut # ---------------------------------------------------------------------- @route.get('/example4/{id}', scopes=['authenticated'], tags=['Examples']) async def example4(id: int) -> models.Post: return await models.Post.query().find(id) # ---------------------------------------------------------------------- # Example: Auth guard using auth shortcut # ---------------------------------------------------------------------- @route.get('/example5/{id}', auth=Guard(['authenticated']), tags=['Examples']) async def example5(id: int) -> models.Post: return await models.Post.query().find(id) # ---------------------------------------------------------------------- # Example: Auth guard while also getting the current user # Also accepts an optional GET parameter (?name=matthew) # ---------------------------------------------------------------------- @route.get('/example6/{id}', tags=['Examples']) async def example6(id: int, name: Optional[str], user: UserInfo = Guard(['authenticated'])) -> models.Post: dump(name, user) return await models.Post.query().find(id) # ---------------------------------------------------------------------- # Example: Auth guard using middleware # Get the current user with request.scope['user'] # Also accepts an optional GET parameter (?name=matthew) # ---------------------------------------------------------------------- @route.get('/example6a/{id}', middleware=[ Guard(['authenticated', 'manager']), # Any other route based middleware here ], tags=['Examples']) async def example6a(request: Request, id: int, name: Optional[str]) -> models.Post: user = request.scope['user'] dump(name, user) return await models.Post.query().find(id) # ---------------------------------------------------------------------- # Example: Other types of responses # ---------------------------------------------------------------------- @route.get('/example6b') async def example6b(request: Request): return response.Text('Text Here') return response.HTML('<b>HTML</b> here') return response.JSON({'json':'here'}) return response.UJSON({'json':'here'}) # requires ujson dependency # and more ... see uvicore/http/response.py # ---------------------------------------------------------------------- # Example: Changing the route name # Each route is given a name automatically. A name is what you can use # to reference the route in your code and view templates. Try to use the # route name instead of the path as paths WILL change as other users use # your library because they can tweak the BASE PATH. Views should be using # {{ url('xx_appname.ex7')}}, never /example7 # If you don't specify a name, uvicore makes a name automatically # from the path, even nested paths from groups. Name always starts # with your apps name, ie: xx_appname. # ---------------------------------------------------------------------- @route.get('/example7', name='ex7') async def example2a(request: Request): # Route name is xx_appname.ex7 instead of default xx_appname.example7 return response.Text('example7') # ---------------------------------------------------------------------- # Example: Override the naming autoprefix # When you define a custom route name, a prefix of xx_appname. is # automatically added keeping your route scoped to this package. # In order to set a full name you must set autoprefix=False. # This is handy when you want to override a route from another package. # ---------------------------------------------------------------------- @route.get('/example8', name='someother.app.ex8', autoprefix=False) async def example8(request: Request): # Route name is someother.app.ex8 return response.Text('example8') # ---------------------------------------------------------------------- # Example: POST a model with validation # ---------------------------------------------------------------------- @route.post('/example9') async def example9(post: models.Post): models.Post.insert(post) # ---------------------------------------------------------------------- # Example raise proper HTTP Exception # ---------------------------------------------------------------------- @route.get('/example9a') async def example9a(): raise HTTPException(404, 'bad stuff') # ---------------------------------------------------------------------- # Example: Grouping routes for common paths and scopes # Routes will be /group1/example10 and /group1/subgroup1/example11 # with scopped permissions on both routes. # IF you also set name='g1', all route names will be # xx_appname.g1.example19 instead of autonamed xx_appname.group1.example10 # ---------------------------------------------------------------------- @route.group('/group1', scopes=['authenticated'], tags=['Group']) def group1(): # Route will be under both Group and Example TAG @route.get('/example10', tags=['Example']) async def example10(request: Request): return response.Text("example10") @route.group('/subgroup1') def subgroup1(): @route.get('/example11') async def example11(request: Request): return response.Text("example11") # ---------------------------------------------------------------------- # Example: Routes as method callbacks (no decorators) # ---------------------------------------------------------------------- def example12(request: Request): return response.Text('example12') route.get('/example12', example12) # ---------------------------------------------------------------------- # Example: Groups and routes as method callbacks (no decorators) # ---------------------------------------------------------------------- def example13(request: Request, id: int) -> models.Post: return await models.Post.query().find(id) def example14(request: Request, email: str) -> List[models.Post]: return await models.Post.query().where('email', email).get() route.group('/group2', scopes=['authenticated', 'post_manager'], routes=[ route.get('/example13', example13), route.get('/example14', example14), ]) # ---------------------------------------------------------------------- # Example: Including other route files and controllers # Technically, there is no difference between your routes files # in http/routes/web.py and http/routes/api.py and your controllers # or api controllers. They are all just one huge nested router. # They are only split up for logical convenience. Just as you included # controlers from your http/routes/web.py, you can also include other # routes here. # ---------------------------------------------------------------------- route.controller('xx_vendor.xx_appname.http.controllers.some.other.Other') # Also, route.controller and route.include are aliases of each other, same thing. route.include('xx_vendor.xx_appname.http.controllers.some.other2.Other2') # Instead of typing the full module path, if route.controllers is defined # Then all .controller() and .include() can use relative paths route.controllers = 'xx_vendor.xx_appname.http.controllers' # Looks for Class in xx_vendor.xx_appname.http.controllers.some.Some route.controller('some') # Leading period means APPEND path to defined route.controllers # So this looks for xx_vendor.xx_appname.http.controllers.other3.Other3 route.controller('.other3.Other3') # If no leading . but other . exists, then it is assuming a full path, # regardless if route.controllers is defined or not. # Return router # Must always return the router at the end of every controller and routes file # as this is one infinitely recursive nested router configuration. return route
def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'acme.appstub.http.api' # Public Routes route.controller('welcome') # Include dynamic model CRUD API endpoints (the "auto API")! # These routes are automatically protected by model.crud style permissions. route.include(ModelRouter, options=uvicore.config.app.api.auto_api) # ---------------------------------------------------------------------- # Example: Routes vs controllers vs api controllers # Technically, there is no difference between your routes files # and controllers or api controllers. They are all just one huge nested # router. This means you could have ALL your routes right here in this # file, or you can break them out into controllers using the # .controller() or its alias .include() methods # ---------------------------------------------------------------------- # route.controller('acme.appstub.http.controllers.some.other.Other') # Also, route.controller and route.include are aliases of each other, same thing. # route.include('acme.appstub.http.controllers.some.other2.Other2') # Instead of typing the full module path, if route.controllers is defined # Then all .controller() and .include() can use relative paths # route.controllers = 'acme.appstub.http.controllers' # Looks for Class in acme.appstub.http.controllers.some.Some # route.controller('some') # Leading period means APPEND path to defined route.controllers # So this looks for acme.appstub.http.controllers.other3.Other3 # route.controller('.other3.Other3') # If no leading . but other . exists, then it is assuming a full path, # regardless if route.controllers is defined or not. # ---------------------------------------------------------------------- # Example: Private routes protected by scopes (permissions) # ---------------------------------------------------------------------- # route.group(scopes=['authenticated']) # def private(): # route.controller('posts') # ---------------------------------------------------------------------- # Example: Grouping routes for common paths and scopes # ---------------------------------------------------------------------- # route.group('/group1', scopes=['authenticated'], tags=['Group1']) # def group1(): # # All routes in these sub controllers will have Tag=Group1 and path # # prefix of /group1/* with route name appstub.group1.* # route.controller('users') # route.controller('tags') # # Nested groups work as expected # route.group('/subgroup1', scopes=['admin'], tags=['Subgroup1']) # def subgroup1(): # # Routes here have merged scopes ['authenticated', 'admin'] # # Will show up in tags Group1 and Subgroup1 # # Will have path of /group1/subgroup1.* # # Will be route names appstub.group1.subgroup1.* # route.controller('hashtags') # ---------------------------------------------------------------------- # Example: controller() and include() methods also accept prefix and tags # Must like a @route.group() would. It does not accept scopes, auth or # other route based middleware, use groups for that. # ---------------------------------------------------------------------- # route.include('admin', prefix='/admin', tags=['Admin']) # ---------------------------------------------------------------------- # Example: Changing the route name # Each route is given a name automatically. A name is what you can use # to reference the route in your code and view templates. Try to use the # route name instead of the path as paths WILL change as other users use # your library because they can tweak the BASE PATH. Views should be using # {{ url('acme.ex0')}}, never /example0 # If you don't specify a name, uvicore makes a name automatically # from the path, even nested paths from groups. Name always starts # with your apps name, ie: acme. # ---------------------------------------------------------------------- # Names work on include() or its alias controller(), or in groups #route.include('example0', name='ex0' prefix='/profile', tags=['Admin']) # @route.group('/group2', name='g2'): # def group2(): # # Name will be acme.g2.ex0 instead of the auto named acme.group2.example0 # route.get('/example0', example0_method, name='ex0'), # ---------------------------------------------------------------------- # Example: Using route methods instead of decorators # Don't like route decorators anywhere? Thats fine, you can use a large # route dictionary style. # ---------------------------------------------------------------------- # route.get('/example1', some_method) # route.group('/group3', scopes=['authenticated'], routes=[ # route.get('/example2', some_method2), # route.get('/example3', some_method3), # ]) # ---------------------------------------------------------------------- # Example: Auto model API. Remove auto.crud scopes. Setting scopes # to [] makes the auto API wide open (no permissions required) # ---------------------------------------------------------------------- # route.include(ModelRouter, options={ # 'scopes': [] # }) # ---------------------------------------------------------------------- # Example: Auto model API. Set scopes manually, no auto.crud scopes used. # ---------------------------------------------------------------------- # route.include(ModelRouter, options={ # 'scopes': ['autoapi_user'] # }) # ---------------------------------------------------------------------- # Example: Auto model API. APPEND these scopes to the auto.crud scopes # So ends up being something like ['post.read', 'and_this_scope'] # ---------------------------------------------------------------------- # @route.group(scopes=['and_this_scope']) # def autoapi(): # route.include(ModelRouter) # Return router # Must always return the router at the end of every controller and routes file # as this is one infinitely recursive nested router configuration. return route
def register(self, route: ApiRouter): """Register API Route Endpoints""" # Define controller base path route.controllers = 'app1.http.api' # Include dynamic model CRUD API endpoints (the "auto API")! #@route.group(auth=Guard(['scope-AUTO'], guard='api')) #@route.group(scopes=['authenticated', 'api.access']) #@route.group(scopes=['authenticated']) @route.group() def autoapi(): # I should add a flag to NOT auto add Guard() to each model endpoint # If I wanted a fully public model router #route.include(ModelRouter, options={'scopes': ['authenticated']}) route.include(ModelRouter) pass async def get_method() -> Post: #return response.Text('Get API Method Here!') return await Post.query().find(1) # # Raw add with methods # #route.add('/get_method1', get_method, ['GET'], response_model=Post) # Or infer response_model route.add('/get_method1', get_method, ['GET']) @route.group(scopes=['posts.read']) #@route.group(auth=Guard(['scope1', 'scope2'], guard='api')) #@route.group(scopes=['scope1', 'scope2']) def ping_group(): #@route.get('/ping', auth=Guard(['scope32'])) #@route.get('/ping', middleware=[Guard('scope323')]) @route.get('/ping') #@route.get('/ping', scopes=['posts.create']) #def ping(request: Request, user: User = Guard(['scope4'])): def ping(request: Request, user: User = Guard(['posts.read'])): #def ping(request: Request, user: User): # If I hacked FastAPI dep code #def ping(request: Request, user: User = User()): # If I made a depends Class like my old Guard() #user: User = request.user dump('PING USER', user) #user = request.scope.get('user') #dump(user) #dump(user.name) #dump(user.permissions) #dump(user.can(['posts.read', 'comments.read'])) #if user.can('posts.read'): # dump('yes user can posts.read') return { 'message': 'pong {}'.format(datetime.now()), #'user': user } @route.group() def test(): route.include('post') # @route.get('/ping2') # def ping(): # return {'message': 'pong {}'.format(datetime.now())} @route.group() def public_api(): @route.get('/public') def pub(request: Request): user = request.scope.get('user') return {'message': 'public endpoint here', 'user': user} # #@route.get('/post2', tags=["Post"], middleware=[Guard(['admin'])]) # @route.get('/post2', tags=["Post"]) # #async def post2(request: Request) -> Post: # Request injected! # #async def post2(user: User = BasicAuth(['admin'])): # #async def post2(user: User = self.auth(['admin'], guard='api')): # #async def post2(user: User = Guard()(['admin'])): # #async def post2(user: User = Guard(['admin'])): # #async def post2(user: User = self.user): # async def post2(): # #return await Post.query().find(1) # return '/post2' # # # BUG FOUND, if /post2 exists above, it replaces it with this one below # # route.group('/group1', routes=[ # # route.get('/post2', post3) # # ]) # @route.group('/group1') # # @route.group('/group1', middleware=[ # # Guard(['asdf'], guard='api') # # ]) # def group1(): # @route.get('/post3') # #async def post3(user: User = self.user): # async def post3(request: Request): # #async def post3(request: Request, user: User = Guard(['asdf'])): # #return '/group1/post3' # user: User = request.scope.get('user') # return user # route.controller(PostController) # Return router return route
from typing import List from app1 import models from uvicore.auth import models as auth_models from uvicore.http.routing import ApiRouter route = ApiRouter() @route.post('/hastags2') def post(entity): return {'hi': 'there'} # @route.get('/auth_groups', response_model=List[auth_models.Group]) # async def auth_groups(): # return await auth_models.Group.query().get() # @route.get('/auth_user_info', response_model=List[auth_models.UserInfo]) # async def auth_user_info(): # return await auth_models.UserInfo.query().get() # @route.get('/auth_users', response_model=List[auth_models.User]) # async def auth_users(): # return await auth_models.User.query().get() # There were two of these, probably why it errored # @route.get('/auth_users', response_model=List[auth_models.User]) # async def auth_users(): # return await auth_models.User.query().get()