OpenAPITools / OpenAPITools/openapi-generator
[REQ] [RUBY] Add support for streaming responses to ruby clients
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Is your feature request related to a problem? Please describe.
I'm currently working on a kubernetes API client for ruby using Faraday and I'd like to implement support for watching for changes. On kubernetes side this is basically implemented via streaming.
Both supported by openapi-generator http clients have support for streaming:
Describe the solution you'd like
Python's client for kubernetes which is also created with help of openapi-generator provides an API to make it possible:
from kubernetes import client, config, watch
# Configs can be set in Configuration class directly or using helper utility
config.load_kube_config()
v1 = client.CoreV1Api()
count = 10
w = watch.Watch()
for event in w.stream(v1.list_namespace, _request_timeout=60):
print("Event: %s %s" % (event['type'], event['object'].metadata.name))
count -= 1
if not count:
w.stop()
print("Ended.")
I've checked the generated ruby source code and couldn't find a way to hook into the request process and define a custom options.on_data callback (in case of Faraday). I assume it can be done somewhere here. The Api::Client#call_api method could receive a block and call it right after build_request. In this case all generated methods that call Api::Client#call_api should also receive a block and pass it to Api::Client#call_api. It will make it possible to hook into every single request made by the client and give enough flexibility to implement streaming. It will also be fully backwards compatible. Something like
Generated Api client:
def call_api(http_method, path, opts = {}, &block)
begin
response = connection(opts).public_send(http_method.to_sym.downcase) do |req|
build_request(http_method, path, req, opts)
block.call(http_method, path, req, opts)
end
...
end
Generated client for CoreV1Api:
def list_core_v1_namespace(opts = {}, &block)
data, _status_code, _headers = list_core_v1_namespace_with_http_info(opts, &block)
data
end
def list_core_v1_namespace_with_http_info(opts = {}, &block)
...
data, status_code, headers = @api_client.call_api(:GET, local_var_path, new_options, &block)
...
end
Client code, somewhat similar to python's example
v1 = CoreV1Api.new
w = Watcher.new
w.stream(v1, :list_core_v1_namespace) do |event|
pp(event)
end
Watcher under the hood will call CoreV1Api#list_core_v1_namespace with modified arguments, pass a block into it and hook into the request process to receive the streamed response, parse it, wrap it into objects and yield it to the client.
Describe alternatives you've considered
With raw Faraday this can be achieved this way
conn = Faraday.new("http://127.0.0.1:8001") # kubectl proxy for simplicity
# inspired by https://github.com/kubernetes-client/python/blob/release-26.0/kubernetes/base/watch/watch.py#L54
prev = ""
conn.get("/api/v1/namespaces", { watch: 1 }) do |req|
req.options.on_data = proc do |seg, _overall_received_bytes, _env|
prev += seg
lines = prev.split("\n")
if seg.end_with?("\n")
prev = ""
else
*lines, prev = lines
end
lines.each do |line|
pp(JSON.parse(line, symbolize_names: true))
end
end
end
Additional context
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/openapi-generator/src/main/resources/ruby-client/api_client_faraday_partial.mustache and trace generated Api::Client#call_api calls from methods such as CoreV1Api#list_core_v1_namespace. Review how Faraday exposes streaming callbacks and how generated methods could propagate a block. Done means Ruby clients can receive streamed response data through the generated API while preserving existing calls.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- api
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100