Google Closure CompilerのREST APIを呼ぶコードをPythonからJSに書き直した時にハマったので備忘録
元コード(Python)
元々動いていたソースでは、こんな感じでリクエスト作って投げていた。
jsCodeには、すでにコンパイル対象のJavascript文字列が入っているものとする。
params = urllib.urlencode([
('js_code',jsCode),
('compilation_level', 'SIMPLE_OPTIMIZATIONS'),
('output_format', 'json'),
('output_info', 'compiled_code'),
('output_info', 'warnings'),
('output_info', 'errors'),
])
headers = { "Content-type": "application/x-www-form-urlencoded" }
conn = httplib.HTTPConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
data = response.read()
conn.close()
ここで、"output_info"パラメータが3つあるが、リクエストではこんな感じになる。
移植先コード - ダメな例(JavaScript)
JSにさっくりと書き直したもの。ブラウザで走らせるのでjQueryを使っている。
(node.jsのhttpで書いてもほぼ同じことになると思うが。)
var params = {
"js_code" : jsCode,
"compilation_level": "SIMPLE_OPTIMIZATIONS",
"output_format": "json",
"output_info": ["compiled_code", "warnings", "errors"]
};
$.ajax({
url : "http://closure-compiler.appspot.com/compile",
type : "POST",
contentType : "application/x-www-form-urlencoded",
data : params,
dataType : "json"
}).done(function(res){...}).fail(function(e){...});
これは、こんな感じでoutput_infoが配列になる。selectとかでよくあるパターンだけど、Closure Compiler様はデリケートなので、これはエラーになる。
具体的には"ServerError"が返ってきて、「"output_info[]"なんてパラメータは知らん。出直せ」と言われる。
移植先コード - 泥臭く直した例(JavaScript)
公式ドキュメント見たりいろいろ探したけどクリティカルな解決策が見つからなかったので、とりあえず基本に立ち返って、自分でシリアライズする。
var params = [
{ key : "js_code", val : jsCode },
{ key : "compilation_level", val : "SIMPLE_OPTIMIZATIONS" },
{ key : "output_format", val : "json" },
{ key : "output_info", val : "compiled_code" },
{ key : "output_info", val : "warnings" },
{ key : "output_info", val : "errors" }
];
paramStr = $.map(params, function(n){
return encodeURIComponent(n.key) + "=" + encodeURIComponent( n.val )
}).join("&").replace(/%20/g, "+");
$.ajax({
url : "http://closure-compiler.appspot.com/compile",
type : "POST",
contentType : "application/x-www-form-urlencoded",
data : paramStr,
processData : false,
dataType : "json"
}).done(function(res){...}).fail(function(e){...});
泥臭いけど、これは動く。
とりあえずめでたし。
でも、すっきりしないー。
(2/20追記) 正解
smzkさんから情報いただきました。1.4から追加になった traditional オプションを有効にすると、シリアライズ時の深い整形処理をやらずに、古い形式で出してくれるようだ。
var params = [
{ key : "js_code", val : jsCode },
{ key : "compilation_level", val : "SIMPLE_OPTIMIZATIONS" },
{ key : "output_format", val : "json" },
{ key : "output_info", val : "compiled_code" },
{ key : "output_info", val : "warnings" },
{ key : "output_info", val : "errors" }
];
paramStr = $.param(params, true);//traditionalオプション付きでシリアライズ
長いので該当箇所だけ。
いや、すっきりしました。