Exemple #1
0
    def transform_rest_request(self, orig_request, params, method_parameters):
        """Translates a Rest request into an apiserving request.

    This makes a copy of orig_request and transforms it to apiserving
    format (moving request parameters to the body).

    The request can receive values from the path, query and body and combine
    them before sending them along to the SPI server. In cases of collision,
    objects from the body take precedence over those from the query, which in
    turn take precedence over those from the path.

    In the case that a repeated value occurs in both the query and the path,
    those values can be combined, but if that value also occurred in the body,
    it would override any other values.

    In the case of nested values from message fields, non-colliding values
    from subfields can be combined. For example, if '?a.c=10' occurs in the
    query string and "{'a': {'b': 11}}" occurs in the body, then they will be
    combined as

    {
      'a': {
        'b': 11,
        'c': 10,
      }
    }

    before being sent to the SPI server.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      params: A dict with URL path parameters extracted by the config_manager
        lookup.
      method_parameters: A dictionary containing the API configuration for the
        parameters for the request.

    Returns:
      A copy of the current request that's been modified so it can be sent
      to the SPI.  The body is updated to include parameters from the
      URL.
    """
        request = orig_request.copy()
        body_json = {}

        # Handle parameters from the URL path.
        for key, value in params.items():
            # Values need to be in a list to interact with query parameter values
            # and to account for case of repeated parameters
            body_json[key] = [value]

        # Add in parameters from the query string.
        if request.parameters:
            # For repeated elements, query and path work together
            for key, value in request.parameters.items():
                if key in body_json:
                    body_json[key] = value + body_json[key]
                else:
                    body_json[key] = value

        # Validate all parameters we've merged so far and convert any '.' delimited
        # parameters to nested parameters.  We don't use iteritems since we may
        # modify body_json within the loop.  For instance, 'a.b' is not a valid key
        # and would be replaced with 'a'.
        for key, value in list(body_json.items()):
            current_parameter = method_parameters.get(key, {})
            repeated = current_parameter.get('repeated', False)

            if not repeated:
                body_json[key] = body_json[key][0]

            # Order is important here.  Parameter names are dot-delimited in
            # parameters instead of nested in dictionaries as a message field is, so
            # we need to call transform_parameter_value on them before calling
            # _add_message_field.

            body_json[key] = parameter_converter.transform_parameter_value(
                key, body_json[key], current_parameter)
            # Remove the old key and try to convert to nested message value
            message_value = body_json.pop(key)
            self._add_message_field(key, message_value, body_json)

        # Add in values from the body of the request.
        if request.body_json:
            self._update_from_body(body_json, request.body_json)

        request.body_json = body_json
        request.body = json.dumps(request.body_json)
        return request
  def transform_rest_request(self, orig_request, params, method_parameters):
    """Translates a Rest request into an apiserving request.

    This makes a copy of orig_request and transforms it to apiserving
    format (moving request parameters to the body).

    The request can receive values from the path, query and body and combine
    them before sending them along to the SPI server. In cases of collision,
    objects from the body take precedence over those from the query, which in
    turn take precedence over those from the path.

    In the case that a repeated value occurs in both the query and the path,
    those values can be combined, but if that value also occurred in the body,
    it would override any other values.

    In the case of nested values from message fields, non-colliding values
    from subfields can be combined. For example, if '?a.c=10' occurs in the
    query string and "{'a': {'b': 11}}" occurs in the body, then they will be
    combined as

    {
      'a': {
        'b': 11,
        'c': 10,
      }
    }

    before being sent to the SPI server.

    Args:
      orig_request: An ApiRequest, the original request from the user.
      params: A dict with URL path parameters extracted by the config_manager
        lookup.
      method_parameters: A dictionary containing the API configuration for the
        parameters for the request.

    Returns:
      A copy of the current request that's been modified so it can be sent
      to the SPI.  The body is updated to include parameters from the
      URL.
    """
    request = orig_request.copy()
    body_json = {}

    # Handle parameters from the URL path.
    for key, value in params.iteritems():
      # Values need to be in a list to interact with query parameter values
      # and to account for case of repeated parameters
      body_json[key] = [value]

    # Add in parameters from the query string.
    if request.parameters:
      # For repeated elements, query and path work together
      for key, value in request.parameters.iteritems():
        if key in body_json:
          body_json[key] = value + body_json[key]
        else:
          body_json[key] = value

    # Validate all parameters we've merged so far and convert any '.' delimited
    # parameters to nested parameters.  We don't use iteritems since we may
    # modify body_json within the loop.  For instance, 'a.b' is not a valid key
    # and would be replaced with 'a'.
    for key, value in body_json.items():
      current_parameter = method_parameters.get(key, {})
      repeated = current_parameter.get('repeated', False)

      if not repeated:
        body_json[key] = body_json[key][0]

      # Order is important here.  Parameter names are dot-delimited in
      # parameters instead of nested in dictionaries as a message field is, so
      # we need to call transform_parameter_value on them before calling
      # _add_message_field.

      body_json[key] = parameter_converter.transform_parameter_value(
          key, body_json[key], current_parameter)
      # Remove the old key and try to convert to nested message value
      message_value = body_json.pop(key)
      self._add_message_field(key, message_value, body_json)

    # Add in values from the body of the request.
    if request.body_json:
      self._update_from_body(body_json, request.body_json)

    request.body_json = body_json
    request.body = json.dumps(request.body_json)
    return request