docs: def parse_form_and_query_params(req_params: dict, sig_params: dict) -> dict:
      """Uses the parameter annotations to coerce string params.
  
      This is used for HTTP requests, in which the form parameters are all
      strings, but need to be converted to the appropriate types before
      validating them.
  
      :param dict req_params: The parameters specified in the request.
      :param dict sig_params: The logic function's signature parameters.
      :returns: a dict of params parsed from the input dict.
      :raises TypeSystemError: If there are errors parsing values.
      """
      # Importing here to prevent circular dependencies.
      from doctor.types import SuperType, UnionType
      errors = {}
      parsed_params = {}
      for param, value in req_params.items():
          # Skip request variables not in the function signature.
          if param not in sig_params:
              continue
          # Skip coercing parameters not annotated by a doctor type.
          if not issubclass(sig_params[param].annotation, SuperType):
              continue
  
          # Check if the type has a custom parser for the parameter.
          custom_parser = sig_params[param].annotation.parser
          if custom_parser is not None:
              if not callable(custom_parser):
                  warnings.warn(
                      'Parser `{}` is not callable, using default parser.'.format(
                          custom_parser))
                  custom_parser = None
  
          try:
              if custom_parser is not None:
                  parsed_params[param] = custom_parser(value)
              else:
                  if issubclass(sig_params[param].annotation, UnionType):
                      json_type = [
                          _native_type_to_json[_type.native_type]
                          for _type in sig_params[param].annotation.types
                      ]
                  else:
                      native_type = sig_params[param].annotation.native_type
                      json_type = [_native_type_to_json[native_type]]
                  # If the type is nullable, also add null as an allowed type.
                  if sig_params[param].annotation.nullable:
                      json_type.append('null')
                  _, parsed_params[param] = parse_value(value, json_type)
          except ParseError as e:
              errors[param] = str(e)
  
      if errors:
          raise TypeSystemError(errors, errors=errors)
  
      return parsed_params