def __init__(self, bot: Bot): self.bot = bot self.metrics = {} self.app = Application() self.routes = RouteTableDef() self.metrics["queue_size"] = { "help": "Simp for maize", "type": "gauge", "value": 1.0 } self.routes.get("/metrics")(self.get_metrics) self.app.add_routes(self.routes) self.bot.loop.create_task(self.start())
async def test_decorator_limiter_called_correctly(self, limit_class): app = Application() routes = RouteTableDef() async def test_view(request): return json_response("bad", status=400) async def test_view2(request): return json_response("bad", status=429) @routes.get("/") @aiopylimit("root_view", (60, 1), limit_reached_view=test_view) async def test(request): return json_response({"test": True}) app.add_routes(routes) request = UserDict() request.app = UserDict() request.app['limit_global_namespace_prefix'] = "aiohttp" request.app['limit_key_func'] = lambda x: "key" request.app['limit_reached_view'] = test_view2 ret = await test(request) limit_class.assert_called_once_with(60, 1) self.assertEqual(ret.status, 400)
def _build_control_routes( integration_context: 'IntegrationContext') -> 'RouteTableDef': routes = RouteTableDef() def _get_status(request: 'Request'): return { **asdict(integration_context.get_status()), 'log_level': get_log_level(), 'log_level_options': get_log_level_options(), '_self': str(request.url) } @routes.get('/integration/{integration_id}/healthz') @auth_level(AuthorizationLevel.ANY_PARTY) async def get_container_health(request: 'Request') -> 'Response': response_dict = {**_get_status(request), '_self': str(request.url)} return json_response(response_dict) @routes.get('/integration/{integration_id}/status') @auth_level(AuthorizationLevel.ANY_PARTY) async def get_container_status(request: 'Request') -> 'Response': return json_response(_get_status(request)) @routes.post('/integration/{integration_id}/log-level') @auth_level(AuthorizationLevel.ANY_PARTY) async def set_level(request: 'Request') -> 'Response': body = await request.json() set_log_level(int(body['log_level'])) return json_response(body) # The control routes are duplicated at paths that are not # qualified by an '/integration/{integration_id}' prefix. Due to # the lack of the prefix, these are private URLs that are only # addressible within the cluster. They have historically been used # to allow the console access to integration controls via a # secured proxy. As integrations migrate to model where security # is implemented internally, these will be deprecated and replaced # entirely with the secured external endpoints above. @routes.get('/healthz') async def internal_get_container_health(request): return await get_container_health(request) @routes.get('/status') async def internal_get_container_status(request): return await get_container_status(request) @routes.post('/log-level') async def internal_set_level(request): return await set_level(request) return routes
class Analytics(Cog): def __init__(self, bot: Bot): self.bot = bot self.metrics = {} self.app = Application() self.routes = RouteTableDef() self.metrics["queue_size"] = { "help": "Simp for maize", "type": "gauge", "value": 1.0 } self.routes.get("/metrics")(self.get_metrics) self.app.add_routes(self.routes) self.bot.loop.create_task(self.start()) async def start(self): await _run_app(self.app, port=8080) def format_response(self): response = "" for metric_name, metric_data in self.metrics.items(): response += f"# HELP {metric_name} {metric_data['help']}\n" response += f"# TYPE {metric_name} {metric_data['type']}\n" response += f"{metric_name} {metric_data['value']}\n" return response async def get_metrics(self, request: Request): return Response(body=self.format_response()) def update_metric(self, name, value, description): if self.metrics.get(name, None) is None: self.metrics[name] = { "type": "gauge", "description": description, "value": 0 } self.metrics[name]["value"] = value
async def test_decorator_success(self, attempt, is_rate_limited): app = Application() routes = RouteTableDef() @routes.get("/") @aiopylimit("root_view", (60, 1)) # 1 per 60 seconds async def test(request): return json_response({"test": True}) app.add_routes(routes) request = UserDict() request.app = UserDict() request.app['limit_global_namespace_prefix'] = "aiohttp" request.app['limit_key_func'] = lambda x: "key" request.app['limit_reached_view'] = None ret = await test(request) self.assertEqual(ret.status, 200) attempt.assert_called_once_with('aiohttp-root_view-key') is_rate_limited.assert_called_once_with('aiohttp-root_view-key')
def __init__(self): self._tasks = Tasks() self._router = RouteTableDef() self._routes = [] self._methods = AsyncRolesMethods()
def routes(route: web.RouteTableDef): return [ route.get('/', get_users), route.get('/{id}', get_one_user), route.post('/', create_user) ]
from megumi.db import DAO, get_db from megumi.rss import rss import unqlite import asyncio import os from datetime import datetime from aiohttp.web import RouteTableDef, Response from .utils.mock_server import get_mock_server router = RouteTableDef() @router.get('/') def rsssrv(req): with open('./tests/assests/test.xml') as f: txt = f.read() return Response(text=txt, content_type='application/xml', charset='utf-8') test_server = get_mock_server(router) async def test_rss(test_server): db = get_db(mem_db=True) dao = DAO.get_instance() db.collection('jobs').store([{ 'lastPubTime': datetime.now().timestamp() - 1000, 'url':
""" The file that serves static files from the root directory, for a whole bunch of reasons like Google Crawling, Sitemaps, etc """ from aiohttp.web import Response, RouteTableDef, Request, StaticResource # The thingo FileRoutes = RouteTableDef() handled_files = [ "js/service-worker.js", "js/upup.min.js", "js/upup.sw.min.js", "robots.txt", "sitemap.xml", ] # @FileRoutes.get("/{file}") async def handler(request: Request): file = request.match_info["file"] if file not in handled_files: return with open(f"./static/{file}") as p: bits = str(request).split("/") url = f"https://{bits[2]}" # Thingo routes @FileRoutes.get("/service-worker.js") async def sw(request): with open("./static/js/service-worker.js") as j: return Response(body=j.read(), content_type="application/javascript")
from aiohttp.client_exceptions import (ClientResponseError) from aiohttp.web import HTTPFound, RouteTableDef from aiohttp_session import get_session from structlog import get_logger from app.employee_view_functions import get_employee_information, get_employee_history_information, get_employee_device from app.employee_view_router import get_employee_tabs from app.historytab import history_tab from app.tabutils import format_to_uk_dates from app.microservice_views import get_views, get_html from . import (NEED_TO_SIGN_IN_MSG, NO_EMPLOYEE_DATA) from . import saml from . import role_matchers from .flash import flash employee_routes = RouteTableDef() logger = get_logger('fsdr-ui') @employee_routes.view("/employeeinformation/{employee_id}") class EmployeeInformation(): @aiohttp_jinja2.template('employee-information.html') async def get(self, request): employee_id = request.match_info['employee_id'] session = await get_session(request) await saml.ensure_logged_in(request) role_id = await saml.get_role_id(request) role = role_matchers.get_role(role_id)
from aiohttp.web import RouteTableDef, Request import jsonschema import logging from .database import get_db, asyncpg from .resp_validation import validated_json_response db_pool: asyncpg.pool.Pool routers = RouteTableDef() @routers.delete('/') async def drop_all_handler(request: Request): """ Удаляет все данные """ async with db_pool.acquire() as conn: await conn.execute("DELETE FROM products") await conn.execute("DELETE FROM CSLinks") await conn.execute("DELETE FROM staff") await conn.execute("DELETE FROM companies") return validated_json_response({}) @routers.post('/companies') async def company_add_handler(request: Request): """ Добавляет компанию
from aiohttp.web import View, RouteTableDef, json_response from aiohttp_cors import CorsViewMixin from models.comments import Comment as CommentModel from utils.decorators import authorize from utils.helpers import comment_tuple_to_json as to_json, get_user_from_token from utils.responses import success_response, failure_response, server_error_response from utils.queries import select_from_news_where_title, select_comments_where_title,\ select_from_users_where_email, insert_new_comment, select_comment_by_id,\ delete_comment_by_id, update_comment_by_id comment = RouteTableDef() @comment.view('/comments') class Comment(View, CorsViewMixin): @authorize async def get(self) -> json_response: try: title = self.request.rel_url.query['title'] if title is None: return failure_response(400, 'No title param') if 60 < len(title) < 4: return failure_response(400, 'Invalid title length') pool = self.request.app['pool'] async with pool.acquire() as conn: async with conn.cursor() as c: await c.execute(select_from_news_where_title(title)) n = await c.fetchone() if n is None:
from aiohttp.web import View, FileResponse, RouteTableDef, Response from .Maze import Maze from .Table import Table import pathlib this_path = str(pathlib.Path(__file__).parent.absolute()) routes = RouteTableDef() routes.static('/static', this_path + '/static') @routes.view('/') @routes.view('/index.html') class Index(View): async def get(self): return FileResponse(path=this_path + '/index.html', status=200) async def post(self): data = await self.request.post() maze_file = data['maze'] filename = maze_file.filename if '.txt' not in filename: raise Exception txt_file = maze_file.file content = txt_file.read().decode("utf-8") maze = Maze(content) solution = maze.solve() web_solution = Table(maze.maze, solution) site_generated = web_solution.generate_html() return Response(body=site_generated, status=200, content_type='text/html')
from aiohttp.web import View, RouteTableDef, json_response from aiohttp_cors import CorsViewMixin from models.news import New as New_Model from utils.decorators import authorize from utils.helpers import get_user_from_token, new_tuple_to_json from utils.responses import success_response, failure_response, server_error_response from utils.queries import select_from_news_where_title, select_from_users_where_email, insert_new_post, \ select_from_news_where_url, select_from_news_where_author_and_title as find, \ delete_new_by_title, update_news_where_title new = RouteTableDef() @new.view('/new') class New(View, CorsViewMixin): @authorize async def get(self) -> json_response: try: url = self.request.rel_url.query['url'] print('remote' + self.request.remote) if url is not None: if 60 > len(url) < 4: return failure_response(400, 'Invalid url length') pool = self.request.app['pool'] async with pool.acquire() as conn: async with conn.cursor() as c: await c.execute(select_from_news_where_url(url)) n = await c.fetchone() if n is not None: return success_response(200, 'OK',
from aiohttp.web import RouteTableDef # This class in imported in all entry points. # And then linked via decorator PhaazeWebIndex: RouteTableDef = RouteTableDef()
from structlog import get_logger from . import (WEBFORM_MISSING_COUNTRY_MSG, WEBFORM_MISSING_CATEGORY_MSG, WEBFORM_MISSING_DESCRIPTION_MSG, WEBFORM_MISSING_NAME_MSG, WEBFORM_MISSING_EMAIL_EMPTY_MSG, WEBFORM_MISSING_EMAIL_INVALID_MSG, WEBFORM_MISSING_COUNTRY_MSG_CY, WEBFORM_MISSING_CATEGORY_MSG_CY, WEBFORM_MISSING_DESCRIPTION_MSG_CY, WEBFORM_MISSING_NAME_MSG_CY, WEBFORM_MISSING_EMAIL_EMPTY_MSG_CY, WEBFORM_MISSING_EMAIL_INVALID_MSG_CY) from .flash import flash from .utils import View from .service_calls.rhsvc import RHSvc logger = get_logger('respondent-home') web_form_routes = RouteTableDef() @web_form_routes.view(r'/' + View.valid_display_regions + '/web-form/') class WebForm(View): @aiohttp_jinja2.template('web-form.html') async def get(self, request): display_region = request.match_info['display_region'] if display_region == 'cy': page_title = 'Gwe-ffurflen' if request.get('flash'): page_title = View.page_title_error_prefix_cy + page_title locale = 'cy' else: page_title = 'Web form' if request.get('flash'):
import aiohttp_jinja2 from aiohttp.web import HTTPFound, RouteTableDef from datetime import datetime, date from structlog import get_logger from pytz import timezone, utc from .flash import flash from .utils import View logger = get_logger('respondent-home') webchat_routes = RouteTableDef() bank_holidays = [ date(2021, 4, 2), date(2021, 4, 5), date(2021, 5, 3), date(2021, 5, 31) ] census_saturday = date(2021, 3, 20) census_sunday = date(2021, 3, 21) census_saturday_open = 16 census_saturday_close = 20 census_sunday_open = 16 census_sunday_close = 20 saturday_open = 8
class IntegrationWebhookContext(IntegrationWebhookRoutes): def __init__(self, queue: 'IntegrationDeferralQueue', client: 'AIOPartyClient'): self.route_table = RouteTableDef() self.client = client self.routes = [] # type: List[WebhookRouteStatus] def _with_resp_handling(self, status: 'InvocationStatus', fn): @wraps(fn) async def wrapped(request): return get_http_response(await fn(request)) return wrapped def _notice_hook_route(self, url_path: str, method: str, label: 'Optional[str]') -> 'WebhookRouteStatus': LOG.info('Registered hook (label: %s): %s %r', label, method, url_path) route_status = \ WebhookRouteStatus( index=len(self.routes), url_path=url_path, method=method, label=label, command_count=0, use_count=0, error_count=0, error_message=None, error_time=None) self.routes.append(route_status) return route_status def _url_path(self, url_suffix: 'Optional[str]'): return '/integration/{integration_id}' + (url_suffix or '') def post(self, url_suffix: 'Optional[str]' = None, label: 'Optional[str]' = None, auth: 'Optional[AuthorizationLevel]' = AuthorizationLevel.PUBLIC): path = self._url_path(url_suffix) hook_status = self._notice_hook_route(path, 'post', label) def wrap_method(func): return set_handler_auth( self.route_table.post(path=path)(self._with_resp_handling( hook_status, as_handler_invocation(self.client, hook_status, func))), auth) return wrap_method def get(self, url_suffix: 'Optional[str]' = None, label: 'Optional[str]' = None, auth: 'Optional[AuthorizationLevel]' = AuthorizationLevel.PUBLIC): path = self._url_path(url_suffix) hook_status = self._notice_hook_route(path, 'get', label) def wrap_method(func): return set_handler_auth( self.route_table.get(path=path)(self._with_resp_handling( hook_status, as_handler_invocation(self.client, hook_status, func))), auth) return wrap_method def get_status(self) -> 'Sequence[WebhookRouteStatus]': return self.routes
"""Client served for development purposes.""" from pathlib import Path from aiohttp.web import FileResponse, Request, RouteTableDef routes = RouteTableDef() client_path = Path('client') assets_path = client_path / 'assets' @routes.get('/') async def get_index(request: Request) -> FileResponse: return FileResponse(assets_path / 'pages' / 'index.html') routes.static('/app', client_path / 'dist' / 'app') routes.static('/pages', assets_path / 'pages') routes.static('/styles', assets_path / 'styles') routes.static('/vendor', client_path / 'dist' / 'vendor') dev_routes = routes
def __init__(self, queue: 'IntegrationDeferralQueue', client: 'AIOPartyClient'): self.route_table = RouteTableDef() self.client = client self.routes = [] # type: List[WebhookRouteStatus]
from aiohttp_session import get_session from structlog import get_logger from . import (BAD_CODE_MSG, INVALID_CODE_MSG, NO_SELECTION_CHECK_MSG, BAD_CODE_MSG_CY, INVALID_CODE_MSG_CY, NO_SELECTION_CHECK_MSG_CY, START_PAGE_TITLE_EN, START_PAGE_TITLE_CY) from .eq import EqLaunch from .exceptions import InvalidForEqTokenGeneration, InvalidAccessCode, ExerciseClosedError, InactiveCaseError from .flash import flash from .security import remember, get_permitted_session, get_sha256_hash, invalidate from .service_calls.rhsvc import RHSvc from .session import get_session_value from .utils import View logger = get_logger('respondent-home') start_routes = RouteTableDef() user_journey = 'start' class StartCommon(View): @staticmethod def uac_hash(uac, expected_length=16): if uac: combined = uac.upper().replace(' ', '') else: combined = '' uac_validation_pattern = re.compile(r'^[A-Z0-9]{16}$') if (len(combined) < expected_length) or not (uac_validation_pattern.fullmatch(combined)): # yapf: disable raise TypeError
from aiohttp.web import View, RouteTableDef, json_response from aiohttp_cors import CorsViewMixin from cloudinary import config from cloudinary.uploader import upload as save from config import CLOUD_NAME, API_KEY, API_SECRET from utils.decorators import authorize from utils.responses import success_response, failure_response, server_error_response upload = RouteTableDef() config(cloud_name=CLOUD_NAME, api_key=API_KEY, api_secret=API_SECRET) @upload.view('/upload') class Upload(View, CorsViewMixin): @authorize async def post(self) -> json_response: try: form_data = await self.request.post() file = form_data['file'].file if file is not None: result = save(file=file) return success_response(200, 'OK', data=result['url']) return failure_response(400, 'You did not send file') except Exception as e: return server_error_response(e)
# from graphql import GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString # # schema = GraphQLSchema( # query=GraphQLObjectType( # name='RootQueryType', # fields={ # 'hello': GraphQLField( # GraphQLString, # resolve=lambda obj, info: 'world') # })) # print graphql schema to frontend/schema.graphql (needed by frontend Relay) schema_file = Path(__file__).parent / '../frontend/schema.graphql' schema_file.write_text(print_schema(schema)) routes = RouteTableDef() # aiohttp handlers table @routes.get('/') async def index_handler(request): return Response(text='Hello World!\n') def main(): p = ArgumentParser() p.add_argument('--port', '-p', type=int, default=5000) args = p.parse_args() setup_logging() asyncio.run(async_main(args=args)) logger.debug('Done')
from pathlib import Path from time import time from aiohttp.web import ( Application, RouteTableDef, Response, json_response, ) from .http_store import http_store from .cors import cors_factory __all__ = [ 'alpaca', ] routes = RouteTableDef() @routes.get('/') async def index(request): path = Path(__file__).with_name('html') / 'index.html' return Response( content_type='text/html', text=path.read_text(), ) @routes.post('/timesync') async def timesync(request): body = await request.json()
def aiohttp_channel_service_routes(handler: ChannelServiceHandler, base_url: str = "") -> RouteTableDef: # pylint: disable=unused-variable routes = RouteTableDef() @routes.post(base_url + "/v3/conversations/{conversation_id}/activities") async def send_to_conversation(request: Request): activity = await deserialize_from_body(request, Activity) result = await handler.handle_send_to_conversation( request.headers.get("Authorization"), request.match_info["conversation_id"], activity, ) return get_serialized_response(result) @routes.post(base_url + "/v3/conversations/{conversation_id}/activities/{activity_id}" ) async def reply_to_activity(request: Request): activity = await deserialize_from_body(request, Activity) result = await handler.handle_reply_to_activity( request.headers.get("Authorization"), request.match_info["conversation_id"], request.match_info["activity_id"], activity, ) return get_serialized_response(result) @routes.put(base_url + "/v3/conversations/{conversation_id}/activities/{activity_id}") async def update_activity(request: Request): activity = await deserialize_from_body(request, Activity) result = await handler.handle_update_activity( request.headers.get("Authorization"), request.match_info["conversation_id"], request.match_info["activity_id"], activity, ) return get_serialized_response(result) @routes.delete( base_url + "/v3/conversations/{conversation_id}/activities/{activity_id}") async def delete_activity(request: Request): await handler.handle_delete_activity( request.headers.get("Authorization"), request.match_info["conversation_id"], request.match_info["activity_id"], ) return Response() @routes.get( base_url + "/v3/conversations/{conversation_id}/activities/{activity_id}/members") async def get_activity_members(request: Request): result = await handler.handle_get_activity_members( request.headers.get("Authorization"), request.match_info["conversation_id"], request.match_info["activity_id"], ) return get_serialized_response(result) @routes.post(base_url + "/") async def create_conversation(request: Request): conversation_parameters = deserialize_from_body( request, ConversationParameters) result = await handler.handle_create_conversation( request.headers.get("Authorization"), conversation_parameters) return get_serialized_response(result) @routes.get(base_url + "/") async def get_conversation(request: Request): # TODO: continuation token? result = await handler.handle_get_conversations( request.headers.get("Authorization")) return get_serialized_response(result) @routes.get(base_url + "/v3/conversations/{conversation_id}/members") async def get_conversation_members(request: Request): result = await handler.handle_get_conversation_members( request.headers.get("Authorization"), request.match_info["conversation_id"], ) return get_serialized_response(result) @routes.get(base_url + "/v3/conversations/{conversation_id}/pagedmembers") async def get_conversation_paged_members(request: Request): # TODO: continuation token? page size? result = await handler.handle_get_conversation_paged_members( request.headers.get("Authorization"), request.match_info["conversation_id"], ) return get_serialized_response(result) @routes.delete(base_url + "/v3/conversations/{conversation_id}/members/{member_id}") async def delete_conversation_member(request: Request): result = await handler.handle_delete_conversation_member( request.headers.get("Authorization"), request.match_info["conversation_id"], request.match_info["member_id"], ) return get_serialized_response(result) @routes.post(base_url + "/v3/conversations/{conversation_id}/activities/history") async def send_conversation_history(request: Request): transcript = deserialize_from_body(request, Transcript) result = await handler.handle_send_conversation_history( request.headers.get("Authorization"), request.match_info["conversation_id"], transcript, ) return get_serialized_response(result) @routes.post(base_url + "/v3/conversations/{conversation_id}/attachments") async def upload_attachment(request: Request): attachment_data = deserialize_from_body(request, AttachmentData) result = await handler.handle_upload_attachment( request.headers.get("Authorization"), request.match_info["conversation_id"], attachment_data, ) return get_serialized_response(result) return routes
import json import tempfile from pathlib import Path from aiohttp.web import RouteTableDef from aiohttp.web_fileresponse import FileResponse from aiohttp.web_response import json_response, Response from tests.conftest import ANALYSIS_TEST_FILES_DIR from tests.api.mocks.utils import not_found, read_file_from_request mock_routes = RouteTableDef() TEST_SAMPLE_PATH = Path(__file__).parent / "mock_sample.json" with TEST_SAMPLE_PATH.open('r') as f: TEST_SAMPLE = json.load(f) TEST_SAMPLE_ID = TEST_SAMPLE["id"] TEST_CACHE = { "id": "test_cache", "created_at": None, "files": list(), "key": "test_cache", "legacy": False, "missing": False, "paired": TEST_SAMPLE["paired"], "ready": False, "sample": { "id": TEST_SAMPLE_ID } }
import aiohttp_jinja2 from aiohttp.web import RouteTableDef, json_response, HTTPFound from structlog import get_logger from . import VERSION from .security import forget from .utils import View logger = get_logger('respondent-home') static_routes = RouteTableDef() @static_routes.view('/info', use_prefix=False) class Info(View): async def get(self, request): info = { 'name': 'respondent-home-ui', 'version': VERSION, } if 'check' in request.query: info['ready'] = await request.app.check_services() return json_response(info) @static_routes.view(r'/' + View.valid_display_regions + '/start/launch-eq/') class LaunchEQ(View): @aiohttp_jinja2.template('start-launch-eq.html') async def get(self, request): display_region = request.match_info['display_region'] self.log_entry(request, display_region + '/start/launch-eq')
from aiohttp.web import HTTPFound, RouteTableDef from aiohttp_utils.routing import add_resource_context, add_route_context from pathlib import Path from structlog import get_logger from .employeehandler import employee_routes from .handler import static_routes from .saml import saml_routes from .downloadshandler import downloads_routes from .microserviceshandler import microservices_handler_routes from .customsqlhandler import customsql_handler_routes from .customsqlchoicehandler import customsql_choice_handler_routes extra_routes = RouteTableDef() logger = get_logger('fsdr-ui') @extra_routes.get('/') async def root(request): raise HTTPFound(request.app.router['sso'].url_for()) def setup(app, url_path_prefix): """Set up routes as resources so we can use the `Index:get` notation for URL lookup.""" combined_routes = [ *extra_routes, *employee_routes, *static_routes, *saml_routes,
import json from aiohttp.web import Application, run_app, RouteTableDef, Request, Response, json_response from asyncio import Queue, create_subprocess_shell, create_task, subprocess, set_event_loop, sleep, gather from dominate import document from dominate.tags import meta, div, script from dominate.util import raw import RPi.GPIO as GPIO routes = RouteTableDef() queue = Queue(5) f_pin, b_pin, l_pin, r_pin = [None] * 4 @routes.get('/') async def index(request: Request): doc = document(title='Онлайн') with doc.head: meta(charset="utf-8") meta(http_equiv="X-UA-Compatible", content="IE=edge") meta(name="viewport", content="width=device-width, initial-scale=1") with doc: div(id='main', style='width: 100vw; height: 100vh;') script( raw(''' const main = document.getElementById('main'); let x = null, y = null; main.onmousedown = e => { x = e.screenX; y = e.screenY; } main.onmouseup = e => {
from aiohttp.web import ( RouteTableDef, Application, Response, WebSocketResponse, run_app, ) from asyncio import sleep import aiohttp_jinja2 import jinja2 import aiohttp_dashboard from os.path import dirname, abspath app = Application() route = RouteTableDef() @route.get('/') @aiohttp_jinja2.template('index.html') async def index(request): return {} @route.get('/demo-html') @route.post('/demo-html') @route.delete('/demo-html') async def html(request): return Response(body=b'Hello, World!')