Home Assistant Unofficial Reference 2024.12.1
data_validator.py
Go to the documentation of this file.
1 """Decorator for view methods to help with data validation."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Awaitable, Callable, Coroutine
6 from functools import wraps
7 from http import HTTPStatus
8 import logging
9 from typing import Any, Concatenate
10 
11 from aiohttp import web
12 import voluptuous as vol
13 
14 from homeassistant.helpers.typing import VolDictType
15 
16 from .view import HomeAssistantView
17 
18 _LOGGER = logging.getLogger(__name__)
19 
20 
22  """Decorator that will validate the incoming data.
23 
24  Takes in a voluptuous schema and adds 'data' as
25  keyword argument to the function call.
26 
27  Will return a 400 if no JSON provided or doesn't match schema.
28  """
29 
30  def __init__(
31  self, schema: VolDictType | vol.Schema, allow_empty: bool = False
32  ) -> None:
33  """Initialize the decorator."""
34  if isinstance(schema, dict):
35  schema = vol.Schema(schema)
36 
37  self._schema_schema = schema
38  self._allow_empty_allow_empty = allow_empty
39 
40  def __call__[_HassViewT: HomeAssistantView, **_P](
41  self,
42  method: Callable[
43  Concatenate[_HassViewT, web.Request, dict[str, Any], _P],
44  Awaitable[web.Response],
45  ],
46  ) -> Callable[
47  Concatenate[_HassViewT, web.Request, _P],
48  Coroutine[Any, Any, web.Response],
49  ]:
50  """Decorate a function."""
51 
52  @wraps(method)
53  async def wrapper(
54  view: _HassViewT, request: web.Request, *args: _P.args, **kwargs: _P.kwargs
55  ) -> web.Response:
56  """Wrap a request handler with data validation."""
57  raw_data = None
58  try:
59  raw_data = await request.json()
60  except ValueError:
61  if not self._allow_empty_allow_empty or (await request.content.read()) != b"":
62  _LOGGER.error("Invalid JSON received")
63  return view.json_message("Invalid JSON.", HTTPStatus.BAD_REQUEST)
64  raw_data = {}
65 
66  try:
67  data: dict[str, Any] = self._schema_schema(raw_data)
68  except vol.Invalid as err:
69  _LOGGER.error("Data does not match schema: %s", err)
70  return view.json_message(
71  f"Message format incorrect: {err}", HTTPStatus.BAD_REQUEST
72  )
73 
74  return await method(view, request, data, *args, **kwargs)
75 
76  return wrapper
None __init__(self, VolDictType|vol.Schema schema, bool allow_empty=False)
web.Response wrapper(_HassViewT view, web.Request request, *_P.args args, **_P.kwargs kwargs)