Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gapic-common/gapic-common.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rake", ">= 12.0"
spec.add_development_dependency "redcarpet", "~> 3.0"
spec.add_development_dependency "yard", "~> 0.9"
spec.add_development_dependency "debug"
end
1 change: 1 addition & 0 deletions gapic-common/lib/gapic/grpc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
require "gapic/grpc/errors"
require "gapic/grpc/service_stub"
require "gapic/grpc/status_details"
require "gapic/routing_headers"
2 changes: 2 additions & 0 deletions gapic-common/lib/gapic/rest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@
require "gapic/rest/paged_enumerable"
require "gapic/rest/server_stream"
require "gapic/rest/threaded_enumerator"
require "gapic/routing_headers"
require "json"

15 changes: 15 additions & 0 deletions gapic-common/lib/gapic/routing_headers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "gapic/routing_headers/headers_extractor"
41 changes: 41 additions & 0 deletions gapic-common/lib/gapic/routing_headers/header_binding.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module Gapic
module RoutingHeaders
class HeadersExtractor
##
# @private
class HeaderBinding
attr_reader :field
attr_reader :header_name
attr_reader :regex

def initialize field, header_name=nil, regex=nil
@field = field
@header_name = header_name
@regex = regex
end

##
# @private
# Creates a new HeaderBinding.
#
def self.create field:, header_name: nil, regex: nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we're creating this separate factory method rather than just writing the constructor with this signature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symmetry with the routing headers extractor/binding

HeaderBinding.new field, header_name, regex
end
end
end
end
end
80 changes: 80 additions & 0 deletions gapic-common/lib/gapic/routing_headers/headers_extractor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "gapic/routing_headers/header_binding"

module Gapic
module RoutingHeaders
class HeadersExtractor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless this class is @private we need documentation for the class and its public methods.

Copy link
Member Author

@viacheslav-rostovtsev viacheslav-rostovtsev Feb 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be @private

attr_accessor :bindings

def initialize bindings = nil
@bindings = bindings || []
end

def with_bindings(field:, header_name: nil, regex: nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be okay without the parens

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

binding = HeaderBinding.create(field: field, header_name: header_name, regex: regex)
HeadersExtractor.new @bindings + [binding]
end

def extract_headers request
header_params = {}

unless request
err_msg = "Incorrect header extraction request: request is nil."
raise ::Gapic::Common::Error, err_msg
end

@bindings.each do |header_binding|
field_value = get_field_val request, header_binding.field
next unless field_value

if header_binding.regex && !field_value.is_a?(::String)
err_msg = "Header binding configuration is incorrect: regex" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you probably want a space after regex.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

"is given with a non-string field #{field}.\n" \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean #{field_value}?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, good catch

"When the regex is present the field in the regex must be a ::String."
raise ::Gapic::Common::Error, err_msg
end

header_name = header_binding.header_name || header_binding.field

header_value = if header_binding.regex
match = header_binding.regex.match field_value
match[1] if match
else
field_value.to_s
end

header_params[header_name] = header_value if header_value && !header_value.empty?
end

header_params
end

private

def get_field_val request, field
field_path = field.split "."

curr_submessage = request
field_path.each do |curr_field|
return nil unless curr_submessage.respond_to? curr_field
curr_submessage = curr_submessage.send curr_field
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit more idiomatic would be to use Enumerable#reduce for the above:

final_submessage = field_path.reduce request do |curr_submessage, curr_field|
  return nil unless curr_submessage.respond_to? curr_field
  curr_submessage.send curr_field
end

Followed by:

final_submessage&.to_s

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


return curr_submessage.to_s if curr_submessage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably replace this line with simply curr_submessage&.to_s

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

end
end
end
end
Loading