1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-09-20

qiita post

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

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

完動,最小版は,

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から

唯一成功したのが,これ.

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で投稿してみた に記述があるけど,tagが不可欠,しかもややこい.

ACCESS_TOKEN

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

localでの検証

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

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/httpsとかはrubyではrequireを変えるでけではなくて,

http.use_ssl = true

だけは入れいます.でもあとは,普通に.

json

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

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

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

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

#+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は

で,

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

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

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

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
1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?