qiita apiに投げる，apiのデバッグ(post to Qiita api v2)



# qiita post

localにあるorgファイルをapiでqiitaにあげられないかというのがお題．

ハマったけどダメ．Bad requestしか返ってこなくって(07/22 10:00ごろ)．その直後にcurlからのを見つけて，全てうまくいく．

完動，最小版は，

```ruby:post_min.rb
require "net/https"
require "json"

lines = File.readlines("README.md")
qiita = 'https://qiita.com/'
path = 'api/v2/items'
uri = URI.parse(qiita+path)

http_req = Net::HTTP.new(uri.host, uri.port)
http_req.use_ssl = uri.scheme === "https"

params = {
  "body": "# テスト", #lines.join, 
  "private": true,
  "title": "テスト",
  "tags":[
    {
      "name": "hoge",
      "versions": []
    }
  ]
  }
ACCESS_TOKEN = ENV["QIITA_WRITE_TOKEN"]

headers = {"Authorization" => "Bearer #{ACCESS_TOKEN}",
  "Content-Type" => "application/json"}
res = http_req.post(uri.path, params.to_json, headers)
p res.message
p res.body
p res.response
```

結論は，「やっぱりtag」でした．やれやれ．動くまでにweb APIとのconnectionの流儀でだいぶ悩んだんで，それについても書いておきます．

コツは，

-   **短いの:** 必要最小限の「やりとり」を用意する．
-   **interactive:** 通信の様子を見るために，ターミナルで直接やりとりする．curlを使え．
-   **確認:** どんな通信が来てるかを直接見る, webrickを立ち上げてlocalと通信する
-   **net/https, json:** libのおきてにお任せがいいよね．
-   **faraday:** 慣れるとfaradayなんかは綺麗にかけて，出力もリッチでいいけど，'Bad request'の本質を解決してくれるわけではない．net/httpでいい．

です．順を追って解説します．


# curlから

唯一成功したのが，これ．

-   [Qiita API v2を利用してcurlで投稿してみた](https://qiita.com/kai_kou/items/663d3f7bbc4da4ccf62d)

```bash
curl -v -X POST "https://qiita.com/api/v2/items" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"body\": \"# テスト\",\"private\": true,\"title\": \"テスト\",\"tags\":[{\"name\": \"hoge\",\"versions\": []}]}"
```

めちゃくちゃ簡単なんやけど．．．できた．<https://qiita.com/daddygongon/private/01b62c9f716573b18e61>

この-dの後の後ろのごちゃごちゃに気が付いたんがえらい．ここが本質でした．


## tag

[Qiita API v2を利用してcurlで投稿してみた](https://qiita.com/kai_kou/items/663d3f7bbc4da4ccf62d) に記述があるけど，tagが不可欠，しかもややこい．


## ACCESS\_TOKEN

group/user, read/writeそれぞれで違うtokenが発行される．この影響があったかも．


# localでの検証

-   [Ruby 標準ライブラリの WEBrick で Web サーバを作る](https://qiita.com/niwasawa/items/9713adaa3e82b695bce7)

ruby webrick.rbで立ち上げて，<http://localhost:8000/> で確認．qiitaに投稿する代わりにlocalに投げた場合，

```ruby
require "net/https"
require "json"

url = 'http://localhost:8000/'
path = 'api/v2/items'
uri = URI.parse(url+path)

http_req = Net::HTTP.new(uri.host, uri.port)

params = {
  "body": "# test",
  "private": true,
  "title": "test",
  "tags":[
    "hoge"
  ]
  }

ACCESS_TOKEN = 'ACCESS_TOKEN'
post_req = Net::HTTP::Post.new(uri.path)
post_req["Authorization"] = "Bearer #{ACCESS_TOKEN}"
post_req["Content-Type"] = "application/json"
post_req.body = params.to_json
res = http_req.request(post_req)

p res.message
p res.body
p res.response
```

    ruby post_local.rb                                                                            380ms
    "OK "
    "<html><body>\nPOST /api/v2/items HTTP/1.1\r\n<br>{&quot;body&quot;:&quot;# test&quot;,&quot;private&quot;:true,&quot;title&quot;:&quot;test&quot;,&quot;tags&quot;:[&quot;hoge&quot;]}\n</body></html>\n"
    #<Net::HTTPOK 200 OK  readbody=true>

と返って来ます．webrick側での表示は

    > ruby webrick.rb
    [2020-07-23 07:32:04] INFO  WEBrick 1.4.2
    [2020-07-23 07:32:04] INFO  ruby 2.6.5 (2019-10-01) [x86_64-darwin17]
    [2020-07-23 07:32:04] INFO  WEBrick::HTTPServer#start: pid=8161 port=8000
    ========== 2020-07-23 07:32:08 +0900 ==========
    POST /api/v2/items HTTP/1.1
    
    Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
    Accept: */*
    User-Agent: Ruby
    Authorization: Bearer ACCESS_TOKEN
    Content-Type: application/json
    Connection: close
    Host: localhost:8000
    Content-Length: 63
    
    {"body":"# test","private":true,"title":"test","tags":["hoge"]}

です．


# net/https, json


## net/http, https

net/httpとかの流儀は，

-   [Net::HTTP#postとNet::HTTP::Postインスタンスを利用したpost(Net::HTTP#request)の違い](https://qiita.com/mashvalue1/items/8ff658342cfbae2a73b6)
-   [RubyのHTTPリクエストをできるだけシンプルに実装する](https://qiita.com/takano-h/items/dd10818eb7e09161bc29)

です．net/httpsとかはrubyではrequireを変えるでけではなくて，

    http.use_ssl = true

だけは入れいます．でもあとは，普通に．

-   [net/httpsでWebAPIにPOSTリクエストを投げる](https://qiita.com/seisonshi/items/c23c0154c45ccbfa9999)


## json

jsonが返って来てなくて，これがなんなのかわからなかった．多分，nginxがweb serverでそのdefaultでerrorが返ってくるときはhtmlみたい．さらに型判定が通ってrequestが上にあげられるとjsonが返ってくる．

-   [nginxでPOSTメソッドのリダイレクトを行う](https://qiita.com/pickles/items/6ac6ade6d51d30c63d65)

うまくいくようになると，

```ruby
p res.message
JSON.parse(res.body).each do |key, cont|
  if key == 'rendered_body' or key == 'body'
    puts "%20s brabrabra..." % key
    next 
  end
  print "%20s %s\n" % [key, cont]
end
p JSON.parse(res.body)["url"]
```

などとして，

    "Created"
           rendered_body brabrabra...
                    body brabrabra...
               coediting false
          comments_count 0
              created_at 2020-07-24T12:43:03+09:00
                   group 
                      id 277d42b24f195ce09471
             likes_count 0
                 private true
         reactions_count 0
                    tags [{"name"=>"hoge", "versions"=>[]}]
                   title テスト
              updated_at 2020-07-24T12:43:03+09:00
                     url https://qiita.com/daddygongon/private/277d42b24f195ce09471
                    user {"description"=>"Ruby, VASP, Maple, boundary, nucleation, Al, Ti, Mg, SiC, Si", "facebook_id"=>"", "followees_count"=>7, "followers_count"=>7, "github_login_name"=>"daddygongon", "id"=>"daddygongon", "items_count"=>30, "linkedin_id"=>"", "location"=>"Japan", "name"=>"", "organization"=>"Kwansei Gakuin University", "permanent_id"=>151211, "profile_image_url"=>"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/151211/1b7c18530785a67592309af94197e19e74c6aba2/x_large.png?1584337585", "team_only"=>false, "twitter_screen_name"=>nil, "website_url"=>""}
        page_views_count 
    "https://qiita.com/daddygongon/private/277d42b24f195ce09471"

とできます．


# Faraday

-   [Ruby HTTPクライアントの比較表](https://qiita.com/aosho235/items/559603ef98587ae4cfc1)
-   [Faradayの使い方 59のレシピ](http://nekorails.hatenablog.com/entry/2018/09/28/152745#015-JSONをPOSTする)

faradayは綺麗で，出力もリッチだけど本質ではない．httpsに投げるとredirectが返ってくるだけ．でbad requestが治ったわけではない．

```ruby
#+name: post_faraday.rb
require "net/http"
require "json"

lines = File.readlines("README.md")
qiita = 'https://qiita.com/'
path = 'api/v2/items'
uri = URI.parse(qiita+path)

require 'faraday'
require 'json'

param = {
  body: '#sample', coediting: false, gist: false, private: true,
  tags: [], title: 'sample', tweet: false
}

url = 'http://qiita.com'
conn = Faraday.new(url: url) do |builder|
  builder.request :url_encoded
  builder.response :logger
  builder.adapter :net_http #Faraday.default_adapter
end

ACCESS_TOKEN = ENV["QIITA_ACCESS_TOKEN"]

response = conn.post do |request|
  request.url '/api/v2/items'
  request.headers = {
    'Authorization' => "Bearer #{ACCESS_TOKEN}",
    'Content-Type' => 'application/json'
  }
  request.body = JSON.generate(param)
end

p response

puts JSON.pretty_generate(JSON.parse(response.body))
#json = JSON.parser.new(response.body)


```


# auto化

orgから一挙に行きたいですよね．keyは

-   [Org-modeからQiita準拠のMarkdownをexportするパッケージを作ってみました](https://qiita.com/0x60df/items/3cde67967e3db30d9afe#comment-ff4bab1d202aa156e6c4)

で，

    emacs README.org --batch -l ~/.emacs.d/site_lisp/ox-qmd -f org-qmd-export-to-markdown --kill

と-lでelファイルを指定して，その中にある関数を機能させる．

それとともに，tagやtitleをorgから取ってくる.以下は，全てを自動化したversion.

```ruby:post_final.rb抜粋
def get_title_tags(src)
  conts = File.read(src)
  title =  conts.match(/\#\+(TITLE|title|Title): (.+)/)[2] || "テスト"
  m = []
  tags = if m =  conts.match(/\#\+(TAG|tag|Tag|tags|TAGS|Tags): (.+)/)
	   m[2].split(',').inject([]) do |l, c|
      l << {name: c.strip, versions: []}
    end
	 else
	   [{ name: "hoge", versions: [] }]
	 end
  p tags
  return title,tags
end

src = ARGV[0] || 'README.org'
title, tags = get_title_tags(src)
p title
p tags

system "emacs #{src} --batch -l ~/.emacs.d/site_lisp/ox-qmd -f org-qmd-export-to-markdown --kill"

params = {
  "body": lines.join, #"# テスト",
  "private": true,
  "title": title,
  "tags": tags
}
```

あと，teamsに投げる．これはurlとaccess\_token

    qiita = 'https://nishitani.qiita.com/'
    ACCESS_TOKEN = ENV['QIITA_TEAM_WRITE_TOKEN']

を少しいじるだけでできる．



------
 - **source** ~/git_hub/ruby_docs/qiita/qiita_post/README.org