istio.io/istio@v0.0.0-20240520182934-d79c90f27776/samples/bookinfo/src/details/details.rb (about) 1 #!/usr/bin/ruby 2 # 3 # Copyright Istio Authors 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 require 'webrick' 18 require 'json' 19 require 'net/http' 20 21 if ARGV.length < 1 then 22 puts "usage: #{$PROGRAM_NAME} port" 23 exit(-1) 24 end 25 26 port = Integer(ARGV[0]) 27 28 server = WEBrick::HTTPServer.new :BindAddress => '*', :Port => port 29 30 trap 'INT' do server.shutdown end 31 32 server.mount_proc '/health' do |req, res| 33 res.status = 200 34 res.body = {'status' => 'Details is healthy'}.to_json 35 res['Content-Type'] = 'application/json' 36 end 37 38 server.mount_proc '/details' do |req, res| 39 pathParts = req.path.split('/') 40 headers = get_forward_headers(req) 41 42 begin 43 begin 44 id = Integer(pathParts[-1]) 45 rescue 46 raise 'please provide numeric product id' 47 end 48 details = get_book_details(id, headers) 49 res.body = details.to_json 50 res['Content-Type'] = 'application/json' 51 rescue => error 52 res.body = {'error' => error}.to_json 53 res['Content-Type'] = 'application/json' 54 res.status = 400 55 end 56 end 57 58 # TODO: provide details on different books. 59 def get_book_details(id, headers) 60 if ENV['ENABLE_EXTERNAL_BOOK_SERVICE'] === 'true' then 61 # the ISBN of one of Comedy of Errors on the Amazon 62 # that has Shakespeare as the single author 63 isbn = '0486424618' 64 return fetch_details_from_external_service(isbn, id, headers) 65 end 66 67 return { 68 'id' => id, 69 'author': 'William Shakespeare', 70 'year': 1595, 71 'type' => 'paperback', 72 'pages' => 200, 73 'publisher' => 'PublisherA', 74 'language' => 'English', 75 'ISBN-10' => '1234567890', 76 'ISBN-13' => '123-1234567890' 77 } 78 end 79 80 def fetch_details_from_external_service(isbn, id, headers) 81 uri = URI.parse('https://www.googleapis.com/books/v1/volumes?q=isbn:' + isbn) 82 http = Net::HTTP.new(uri.host, ENV['DO_NOT_ENCRYPT'] === 'true' ? 80:443) 83 http.read_timeout = 5 # seconds 84 85 # DO_NOT_ENCRYPT is used to configure the details service to use either 86 # HTTP (true) or HTTPS (false, default) when calling the external service to 87 # retrieve the book information. 88 # 89 # Unless this environment variable is set to true, the app will use TLS (HTTPS) 90 # to access external services. 91 unless ENV['DO_NOT_ENCRYPT'] === 'true' then 92 http.use_ssl = true 93 end 94 95 request = Net::HTTP::Get.new(uri.request_uri) 96 headers.each { |header, value| request[header] = value } 97 98 response = http.request(request) 99 100 json = JSON.parse(response.body) 101 book = json['items'][0]['volumeInfo'] 102 103 language = book['language'] === 'en'? 'English' : 'unknown' 104 type = book['printType'] === 'BOOK'? 'paperback' : 'unknown' 105 isbn10 = get_isbn(book, 'ISBN_10') 106 isbn13 = get_isbn(book, 'ISBN_13') 107 108 return { 109 'id' => id, 110 'author': book['authors'][0], 111 'year': book['publishedDate'], 112 'type' => type, 113 'pages' => book['pageCount'], 114 'publisher' => book['publisher'], 115 'language' => language, 116 'ISBN-10' => isbn10, 117 'ISBN-13' => isbn13 118 } 119 120 end 121 122 def get_isbn(book, isbn_type) 123 isbn_dentifiers = book['industryIdentifiers'].select do |identifier| 124 identifier['type'] === isbn_type 125 end 126 127 return isbn_dentifiers[0]['identifier'] 128 end 129 130 def get_forward_headers(request) 131 headers = {} 132 133 # Keep this in sync with the headers in productpage and reviews. 134 incoming_headers = [ 135 # All applications should propagate x-request-id. This header is 136 # included in access log statements and is used for consistent trace 137 # sampling and log sampling decisions in Istio. 138 'x-request-id', 139 140 # Lightstep tracing header. Propagate this if you use lightstep tracing 141 # in Istio (see 142 # https://istio.io/latest/docs/tasks/observability/distributed-tracing/lightstep/) 143 # Note: this should probably be changed to use B3 or W3C TRACE_CONTEXT. 144 # Lightstep recommends using B3 or TRACE_CONTEXT and most application 145 # libraries from lightstep do not support x-ot-span-context. 146 'x-ot-span-context', 147 148 # Datadog tracing header. Propagate these headers if you use Datadog 149 # tracing. 150 'x-datadog-trace-id', 151 'x-datadog-parent-id', 152 'x-datadog-sampling-priority', 153 154 # W3C Trace Context. Compatible with OpenCensusAgent and Stackdriver Istio 155 # configurations. 156 'traceparent', 157 'tracestate', 158 159 # Cloud trace context. Compatible with OpenCensusAgent and Stackdriver Istio 160 # configurations. 161 'x-cloud-trace-context', 162 163 # Grpc binary trace context. Compatible with OpenCensusAgent nad 164 # Stackdriver Istio configurations. 165 'grpc-trace-bin', 166 167 # b3 trace headers. Compatible with Zipkin, OpenCensusAgent, and 168 # Stackdriver Istio configurations. 169 'x-b3-traceid', 170 'x-b3-spanid', 171 'x-b3-parentspanid', 172 'x-b3-sampled', 173 'x-b3-flags', 174 175 # SkyWalking trace headers. 176 'sw8', 177 178 # Application-specific headers to forward. 179 'end-user', 180 'user-agent', 181 182 # Context and session specific headers 183 'cookie', 184 'authorization', 185 'jwt' 186 ] 187 188 request.each do |header, value| 189 if incoming_headers.include? header then 190 headers[header] = value 191 end 192 end 193 194 return headers 195 end 196 197 server.start