1

当使用 Octokit 向 graphql 端点发送请求时,如何设置自定义Accept:标头以打开“预览”API?

我需要做一个 GraphQL 查询,它是 API 预览的一部分,所以它需要我将Accept标头设置为application/vnd.github.starfox-preview+json(请参阅GitHub API 文档)。

我在 Rails 项目中使用 Octokit (4.15.0),并且使用 v3 和 v4 (GraphQL) API 成功地进行了正常查询(不是预览模式)。

对于普通查询(不是 API 预览),我的代码看起来像这样,并且可以完美运行。在这里,该方法graphql_query_string形成了正确的查询字符串,并且是 Octokit对象github_machine_user的一个​​实例。Client

有效的代码(当Accept:不需要自定义标头时)

   def perform_graphql_query(repo_name, org_name, after="")
      graphql_query_string = graphql_query(repo_name, org_name, after)
      options = { query: graphql_query_string }.to_json
      github_machine_user.post '/graphql', options
    end

这导致使用默认Accept标头,这显然是"application/vnd.github.v3+json"(更多关于我如何在下面了解这一点。)

我尝试了几种添加自定义Accept:标题的方法,但没有一种方法有效。这是我尝试过的:

不成功的尝试#1:

  def perform_graphql_query(repo_name, org_name, after="")
      graphql_query_string = graphql_query(repo_name, org_name, after)
      options = {:query => graphql_query_string, 
        :headers => {:accept => "application/vnd.github.starfox-preview+json"}
      }.to_json
      github_machine_user.post('/graphql', options)
      
    end

不成功的尝试#2:

   def perform_graphql_query(repo_name, org_name, after="")
      graphql_query_string = graphql_query(repo_name, org_name, after)
      options = {
          :query => graphql_query_string, 
          :accept => "application/vnd.github.starfox-preview+json"
      }.to_json
      github_machine_user.post('/graphql', options)
    end

这些都没有设置正确的标题。从post方法和底层请求方法的源代码中,我希望这可以工作。这就是它们的样子。

    # Make a HTTP POST request
    #
    # @param url [String] The path, relative to {#api_endpoint}
    # @param options [Hash] Body and header params for request
    # @return [Sawyer::Resource]
    def post(url, options = {})
      request :post, url, options
    end
     def request(method, path, data, options = {})
      if data.is_a?(Hash)
        options[:query]   = data.delete(:query) || {}
        options[:headers] = data.delete(:headers) || {}
        if accept = data.delete(:accept)
          options[:headers][:accept] = accept
        end
      end

是我,还是 Octokit 中的错误?

我可以告诉标题没有被设置,不仅仅是因为我得到了指示的结果Field 'project' doesn't exist on type 'AddedToProjectEvent',因为我还遵循了 Octokit 文档中关于打开调试信息的建议,并且我可以看到我的请求中的标题。

以下是它们的显示方式(除编辑凭据外)

I, [2020-07-24T12:26:37.989030 #64350]  INFO -- request: POST https://api.github.com/graphql
I, [2020-07-24T12:26:37.989109 #64350]  INFO -- request: Accept: "application/vnd.github.v3+json"
User-Agent: "Octokit Ruby Gem 4.15.0"
Content-Type: "application/json"
Authorization: "token REDACTED_FOR_STACK_OVERFLOW_POST"

所以我设置接受标头的请求没有得到尊重。

我确实验证了使用curl,我能够通过传递正确的Accept标头使查询正常工作。因此,graphQl 查询已正确形成,并且当 Accept 标头正确放入查询时,一切都很好。但我似乎无法弄清楚如何让 Octokit 在设置 Accept 标头时尊重我的意愿。我什至查看了源代码,看来我正在做的事情应该有效。

任何人都可以帮忙吗?

更新:也作为问题发布在 Octokit 的 GitHub Repo 上

更新 #2:我尝试删除to_json. 不幸的是,这给出了如下所示的堆栈跟踪。

如果我删除to_json然后通过{:accept => "application/vnd.github.starfox-preview+json"}然后它确实设置了正确的标题。但是,如果尝试包含:query在该散列中,则会导致以下错误,除非我to_json在散列上有 。我只是似乎无法获胜。

NoMethodError undefined method `each' for #<String:0x00007fb05be10b00>
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/utils/params_hash.rb:28:in `update'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/sawyer-0.8.2/lib/sawyer/agent.rb:99:in `block in call'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/connection.rb:489:in `block in run_request'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/connection.rb:506:in `block in build_request'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/request.rb:55:in `block in create'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/request.rb:54:in `tap'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/request.rb:54:in `create'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/connection.rb:502:in `build_request'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/connection.rb:484:in `run_request'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/faraday-1.0.0/lib/faraday/connection.rb:279:in `post'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/sawyer-0.8.2/lib/sawyer/agent.rb:94:in `call'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/octokit-4.18.0/lib/octokit/connection.rb:156:in `request'
/Users/pconrad/.rvm/gems/ruby-2.6.5/gems/octokit-4.18.0/lib/octokit/connection.rb:28:in `post'
/Users/pconrad/github/project-anacapa/anacapa-github-linker/app/jobs/course/course_github_repo_get_sdlc_events.rb:105:in `perform_graphql_query'

更新#3:在下面添加了我自己的答案,但看起来很老套。我不得不调用一个私有方法,这是不应该做的,而且绝对不应该“必须做”。所以,还是希望有更好的解决方案。

4

2 回答 2

1

这就是最终奏效的方法。我不得不“弄脏”并调用一个.send不理想的私有方法。

graphql_query_string = graphql_query(repo_name, org_name, after).gsub("\n","")

data = {
    :query => graphql_query_string, 
}.to_json
options = {
  :headers => {
  :accept => Octokit::Preview::PREVIEW_TYPES[:project_card_events]
  }
}
github_machine_user.send :request, :post, '/graphql', data,options

如果有更好的方法,欢迎提出建议。我同意其他海报说传递to_json数据部分没有任何意义,但没有它,我会得到关于each未在字符串上定义的堆栈跟踪。

于 2020-07-25T21:39:28.210 回答
0

删除调用#to_jsonoptions您将 String 传递给#postas optionsoptions被放入#requestas data。如果它是 a#request会做它的事情,但由于它是一个字符串,它不会填充传递给客户端的新的.dataHashoptions#request

于 2020-07-25T05:41:51.197 回答