fetchは、HTTP呼び出しで標準的に使っていますが、Content-Typeに従った呼び出し方をいつも忘れてしまうので、備忘録として残しておきます。
実動作の確認のためのソースコードを以下のGitHubに上げておきました。
https://github.com/poruruba/fetch_laboratory
Javascriptからの呼び出しを中心に示しますが、同じコードがそのままNode.jsでも動作します。
ちょっとだけ、Lambdaでの動作も示しておきます。
呼び出し方法の種類
今回扱う呼び出し方法は以下の通りです。
・Get呼び出し
HTMLのページ取得でおなじみです。パラメータをQueryStringに指定します。例えば、以下のような呼び出しです。
http://localhost:10080/api?param1=abcd
・Post(Content-Type: application/json)呼び出し
パラメータをBody部にJSONで指定するWebAPI呼び出しでは一番一般的ですね。
・Post(Content-Type: application/x-www-form-urlencoded)呼び出し
フォームでSumitするときの方法です。例えば、以下のような呼び出しです。
<form action="http://localhost:10080/post-urlencoded" method="post">
・Post(Content-Type: multipart/form-data)呼び出し
フォームでmultipart指定でSumitするときの方法です。例えば、以下のような呼び出しです。
<form action="http://localhost:10080/post-formdata" method="post" enctype="multipart/form-data">
Javascriptの場合
まずは、Javascriptから。
Post(Content-Type: application/json)呼び出し
function do_post(url, body) {
const headers = new Headers({ "Content-Type": "application/json" });
return fetch(url, {
method: 'POST',
body: JSON.stringify(body),
headers: headers
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
});
}
Post(Content-Type: application/x-www-form-urlencoded)呼び出し
function do_post_urlencoded(url, params) {
const headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
var body = new URLSearchParams(params);
return fetch(url, {
method: 'POST',
body: body,
headers: headers
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
})
}
Post(Content-Type: multipart/form-data)呼び出し
function do_post_formdata(url, params){
var body = Object.entries(params).reduce( (l, [k,v])=> { l.append(k, v); return l; }, new FormData());
return fetch(url, {
method : 'POST',
body: body,
})
.then((response) => {
if( !response.ok )
throw new Error('status is not 200');
return response.json();
});
}
GET呼び出し
function do_get(url, qs) {
var params = new URLSearchParams(qs);
var params_str = params.toString();
var postfix = (params_str == "") ? "" : ((url.indexOf('?') >= 0) ? ('&' + params_str) : ('?' + params_str));
return fetch(url + postfix, {
method: 'GET',
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
});
}
Node.jsの場合
Node.jsでも呼び出し方は同じです。
ポイントは、以下のnpmモジュールを利用するところです。
・node-fetch
https://github.com/node-fetch/node-fetch
・form-data
https://github.com/form-data/form-data
以下を先頭に記述することで、ほぼJavascriptと同じ記述で同じ動作となります。
const FormData = require('form-data');
const { URL, URLSearchParams } = require('url');
const fetch = require('node-fetch');
const Headers = fetch.Headers;
実験のためのサンプルページ
以下のようなページから、各呼び出し方法を確認します。
F11を押して、DevToolsを開くと、通信内容を詳しく見ることができます。
先ほど示した関数群を呼び出しているだけでして、詳細はGitHubのソースコードを参照ください。
参考までに、リクエストを受け付けるサーバ側のソースも示しておきます。
'use strict';
const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/';
const Response = require(HELPER_BASE + 'response');
const Redirect = require(HELPER_BASE + 'redirect');
// Lambda+API Gatewayの場合に必要
//const { URLSearchParams } = require('url');
//const multipart = require('aws-lambda-multipart-parser');
exports.handler = async (event, context, callback) => {
if( event.path == '/post-json'){
console.log(event.body);
var body = JSON.parse(event.body);
var response = {
path : event.path,
param: {
param1: body.param1,
param2: body.param2,
}
};
return new Response(response);
}else
if( event.path == '/post-urlencoded'){
// Lambda+API Gatewayの場合はこちら
//var body = {};
//for( var pair of new URLSearchParams(event.body).entries() ) body[pair[0]] = pair[1];
// swagger_nodeの場合はこちら
var body = JSON.parse(event.body);
var response = {
path : event.path,
param: {
param1: body.param1,
param2: body.param2,
}
};
return new Response(response);
}else
if( event.path == '/post-formdata' ){
// Lambda+API Gatewayの場合はこちら
//var body = multipart.parse(event);
// swagger_nodeの場合はこちら
var body = JSON.parse(event.body);
console.log(body);
var response = {
path : event.path,
param: {
param1: body.param1,
param2: body.param2,
}
};
return new Response(response);
}else
if( event.path == '/get-qs'){
console.log(event.queryStringParameters);
var response = {
path : event.path,
param: {
param1: event.queryStringParameters.param1,
param2: event.queryStringParameters.param2,
}
};
return new Response(response);
}
};
一方で、Node.jsでの呼び出しも確認したかったので、Node.js側の確認のためのソースも示しておきます。
動作としては、いったん、サーバ側でリクエストを受け付けたのち、パラメータで指定されたbody.typeの値によって、各呼び出し方法に従った呼び出しをNode.jsで行っています。
コードを見ていただくと、Javascriptでの呼び出しと同じであることがわかります。
'use strict';
const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/';
const Response = require(HELPER_BASE + 'response');
const Redirect = require(HELPER_BASE + 'redirect');
const FormData = require('form-data');
const fetch = require('node-fetch');
const { URL, URLSearchParams } = require('url');
const Headers = fetch.Headers;
const baseurl = 'http://localhost:10080';
exports.handler = async (event, context, callback) => {
if( event.path == '/node'){
console.log(event.body);
var body = JSON.parse(event.body);
if( body.type == "post-json"){
var params = {
param1: body.param1,
param2: body.param2,
};
return do_post(baseurl + '/post-json', params)
.then(json => {
console.log(json);
return new Response({ type: body.type, resposne: json });
})
.catch(error => {
console.log(error);
return new Response(error);
});
}else
if( body.type == "post-urlencoded"){
var params = {
param1: body.param1,
param2: body.param2,
};
return do_post_urlencoded(baseurl + '/post-urlencoded', params)
.then(json => {
console.log(json);
return new Response({ type: body.type, resposne: json });
})
.catch(error => {
console.log(error);
return new Response(error);
});
}else
if( body.type == "post-formdata"){
var params = {
param1: body.param1,
param2: body.param2,
};
return do_post_formdata(baseurl + '/post-formdata', params)
.then(json => {
console.log(json);
return new Response({ type: body.type, resposne: json });
})
.catch(error => {
console.log(error);
return new Response(error);
});
}else
if( body.type == 'get-qs'){
var qs = {
param1: body.param1,
param2: body.param2,
}
return do_get(baseurl + '/get-qs', qs)
.then(json => {
console.log(json);
return new Response({ type: body.type, resposne: json });
})
.catch(error => {
console.log(error);
return new Response(error);
});
}
var response = {
type : body.type,
param: {
param1: body.param1,
param2: body.param2,
}
};
return new Response(response);
}
};
function do_post(url, body) {
const headers = new Headers({ "Content-Type": "application/json; charset=utf-8" });
return fetch(url, {
method: 'POST',
body: JSON.stringify(body),
headers: headers
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
});
}
function do_get(url, qs) {
var params = new URLSearchParams(qs);
return fetch(url + `?` + params.toString(), {
method: 'GET',
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
});
}
function do_post_urlencoded(url, params) {
const headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
var body = new URLSearchParams(params);
return fetch(url, {
method: 'POST',
body: body,
headers: headers
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
})
}
function do_post_formdata(url, params) {
var body = Object.entries(params).reduce((l, [k, v]) => {
l.append(k, v);
return l;
}, new FormData());
return fetch(url, {
method: 'POST',
body: body,
})
.then((response) => {
if (!response.ok)
throw new Error('status is not 200');
return response.json();
});
}
補足
※レスポンスの型
最近レスポンスはJSONで返されることが多くなっていますので、すべてJSONで返ってくることを想定しています。もし、単なるテキストで返ってくる場合には以下の部分を変更します。
(変更前) return response.json();
→
(変更後) return response.text();
以上