@kyanny's blog

My life. Opinions are my own.

drakma:http-request の返り値を変数に束縛する

(quicklisp:quickload :drakma)

(let* ((drakma:*text-content-types* '(("application" . "json")))
       (token "helloworld")
       (authorization (concatenate 'string "token" " " token)))
  (multiple-value-bind (body status headers)
      (drakma:http-request "https://httpbin.org/get"
                           :user-agent "my user agent"
                           :additional-headers `(("Authorization" . ,authorization)))
    (print body)
    (print "----")
    (print status)
    (print "----")
    (print headers)
    nil))

drakma:http-request は多値を返すので multiple-value-bind を使って変数束縛する。

リファレンス http://www.lispworks.com/documentation/HyperSpec/Body/m_multip.htm

CL-USER> (let* ((drakma:*text-content-types* '(("application" . "json")))
       (token "helloworld")
       (authorization (concatenate 'string "token" " " token)))
  (multiple-value-bind (body status headers)
      (drakma:http-request "https://httpbin.org/get"
                           :user-agent "my user agent"
                           :additional-headers `(("Authorization" . ,authorization)))
    (print body)
    (print "----")
    (print status)
    (print "----")
    (print headers)
    nil))

"{
  \"args\": {}, 
  \"headers\": {
    \"Accept\": \"*/*\", 
    \"Authorization\": \"token helloworld\", 
    \"Connection\": \"close\", 
    \"Host\": \"httpbin.org\", 
    \"User-Agent\": \"my user agent\"
  }, 
  \"origin\": \"42.148.188.233\", 
  \"url\": \"https://httpbin.org/get\"
}
" 
"----" 
200 
"----" 
((:CONNECTION . "close") (:SERVER . "meinheld/0.6.1")
 (:DATE . "Thu, 17 Aug 2017 18:26:19 GMT") (:CONTENT-TYPE . "application/json")
 (:ACCESS-CONTROL-ALLOW-ORIGIN . "*")
 (:ACCESS-CONTROL-ALLOW-CREDENTIALS . "true") (:X-POWERED-BY . "Flask")
 (:X-PROCESSED-TIME . "0.00106692314148") (:CONTENT-LENGTH . "260")
 (:VIA . "1.1 vegur")) 
NIL

Drakma で Authorization ヘッダを送信する(トークンをハードコーディングしない)

(quicklisp:quickload :drakma)

(let* ((drakma:*text-content-types* '(("application" . "json")))
       (token "helloworld")
       (authorization (concatenate 'string "token" " " token)))
  (drakma:http-request "https://httpbin.org/get"
                       :user-agent "my user agent"
                       :additional-headers `(("Authorization" . ,authorization))))

雰囲気でバッククォートとカンマを使ってみたらうまくいった。こういう形にしないと “Authorization: AUTHORIZATION” というヘッダが送信されてしまってうまくいかない。

token が評価された後に authorization を評価しないといけない(評価される順序が大事)なので let ではなく let* を使う。

CL-USER> (let* ((drakma:*text-content-types* '(("application" . "json")))
       (token "helloworld")
       (authorization (concatenate 'string "token" " " token)))
  (drakma:http-request "https://httpbin.org/get"
                       :user-agent "my user agent"
                       :additional-headers `(("Authorization" . ,authorization))))
"{
  \"args\": {}, 
  \"headers\": {
    \"Accept\": \"*/*\", 
    \"Authorization\": \"token helloworld\", 
    \"Connection\": \"close\", 
    \"Host\": \"httpbin.org\", 
    \"User-Agent\": \"my user agent\"
  }, 
  \"origin\": \"42.148.188.233\", 
  \"url\": \"https://httpbin.org/get\"
}
"
200
((:CONNECTION . "close") (:SERVER . "meinheld/0.6.1")
 (:DATE . "Thu, 17 Aug 2017 18:21:49 GMT") (:CONTENT-TYPE . "application/json")
 (:ACCESS-CONTROL-ALLOW-ORIGIN . "*")
 (:ACCESS-CONTROL-ALLOW-CREDENTIALS . "true") (:X-POWERED-BY . "Flask")
 (:X-PROCESSED-TIME . "0.000737905502319") (:CONTENT-LENGTH . "260")
 (:VIA . "1.1 vegur"))
#<PURI:URI https://httpbin.org/get>
#<FLEXI-STREAMS:FLEXI-IO-STREAM {100599E4A3}>
T
"OK"

Drakma で HTTP リクエストヘッダを送信する

(quicklisp:quickload :drakma)

(let ((drakma:*text-content-types* '(("application" . "json"))))
  (drakma:http-request "https://httpbin.org/get"
                       :user-agent "my user agent"
                       :additional-headers '(("X-Hello-World" . "Hello World"))))

いくつかのヘッダは直接 :user-agent のようにオプション引数?で指定できるが、 X- で始まる任意のヘッダなどを追加したい場合は :additional-headers を使う。

:additional-headers の値にはこういうリストを渡す。

'(
  ("Header Name 1" . "Header Value 1")
  ("Header Name 2" . "Header Value 2")
  )
CL-USER> (let ((drakma:*text-content-types* '(("application" . "json"))))
  (drakma:http-request "https://httpbin.org/get"
                       :user-agent "my user agent"
                       :additional-headers '(("X-Hello-World" . "Hello World"))))
"{
  \"args\": {}, 
  \"headers\": {
    \"Accept\": \"*/*\", 
    \"Connection\": \"close\", 
    \"Host\": \"httpbin.org\", 
    \"User-Agent\": \"my user agent\", 
    \"X-Hello-World\": \"Hello World\"
  }, 
  \"origin\": \"42.148.188.233\", 
  \"url\": \"https://httpbin.org/get\"
}
"
200
((:CONNECTION . "close") (:SERVER . "meinheld/0.6.1")
 (:DATE . "Thu, 17 Aug 2017 18:15:07 GMT") (:CONTENT-TYPE . "application/json")
 (:ACCESS-CONTROL-ALLOW-ORIGIN . "*")
 (:ACCESS-CONTROL-ALLOW-CREDENTIALS . "true") (:X-POWERED-BY . "Flask")
 (:X-PROCESSED-TIME . "0.00119519233704") (:CONTENT-LENGTH . "255")
 (:VIA . "1.1 vegur"))
#<PURI:URI https://httpbin.org/get>
#<FLEXI-STREAMS:FLEXI-IO-STREAM {10057DA113}>
T
"OK"

Drakma で JSON API にアクセスする

(quicklisp:quickload :drakma)

(let ((drakma:*text-content-types* '(("application" . "json")))) ;; おまじない
  (drakma:http-request "https://httpbin.org/get"))

返り値は順に body status-code headers uri など(使いそうなのはこのへんまで)。

リファレンス http://weitz.de/drakma/#http-request

CL-USER> (let ((drakma:*text-content-types* '(("application" . "json"))))
  (drakma:http-request "https://httpbin.org/get"))
"{
  \"args\": {}, 
  \"headers\": {
    \"Accept\": \"*/*\", 
    \"Connection\": \"close\", 
    \"Host\": \"httpbin.org\", 
    \"User-Agent\": \"Drakma/2.0.3 (SBCL 1.3.20; Darwin; 16.7.0; http://weitz.de/drakma/)\"
  }, 
  \"origin\": \"42.148.188.233\", 
  \"url\": \"https://httpbin.org/get\"
}
"
200
((:CONNECTION . "close") (:SERVER . "meinheld/0.6.1")
 (:DATE . "Thu, 17 Aug 2017 18:10:23 GMT") (:CONTENT-TYPE . "application/json")
 (:ACCESS-CONTROL-ALLOW-ORIGIN . "*")
 (:ACCESS-CONTROL-ALLOW-CREDENTIALS . "true") (:X-POWERED-BY . "Flask")
 (:X-PROCESSED-TIME . "0.00083589553833") (:CONTENT-LENGTH . "272")
 (:VIA . "1.1 vegur"))
#<PURI:URI https://httpbin.org/get>
#<FLEXI-STREAMS:FLEXI-IO-STREAM {100575E1A3}>
T
"OK"

(8/75) Java Tutorial for Complete Beginners

標準入力から読み込む。

Scanner が期待する型と違うデータを入力するとエラーになるのを堅牢にせよ、というお題にたいする解。

import java.util.Scanner;

public class Application {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        
        System.out.println("Enter an float: ");

        if (input.hasNextInt()) {
            int value = input.nextInt();
            System.out.println("You entered int: " + value);
        } else if (input.hasNextDouble()) {
            double value = input.nextDouble();
            System.out.println("You entered double: " + value);
        } else {
            String line = input.nextLine();
            System.out.println("You entered string: " + line);
        }
    }
}

Eclipse の使い方に少し慣れてきた。 Perspective とか、 Git の GUI とか。

体調悪くて寝込んだりしてて数日空いた。

並行して Common Lisp のチュートリアルなどもやっているが Java のほうが(まだ)ずいぶん簡単に感じる。