概要
Node.jsとexpressを使って作成したWebAPIで、ファイルの書き出しとファイルの読込を行いたい。
環境
Windows 10
Node.js v8.9.1
npm 5.5.1
express 4.16.0
express-generator
Google Chrome 71.0.3578.98
Visual Studio Code
前提
前回の記事で、Node.jsとexpressで簡単なWebAPIを作成・動作確認できていること。
Node.jsとexpressを使って簡単なWebAPIを作成する
ファイルへの書き出し(簡単編)
Nodeのfsモジュールに入っているfs.writeFile()
でファイルへの書き出しを行う。
コード
const express = require('express');
const app = express();
const fs = require('fs');
// ルート設定
app.get('/', (req, res) => res.send('Hello World'));
// api-create-request-fileの設定
app.get('/api/v1/create-request-file', (req, res) =>{
fs.writeFile("C:/test/request.txt" , "書き込みデータ" , (err) => {
if(err){
return res.status(500).send("エラーが発生しました");
}
else{
return res.status(200).send("ファイルが正常に書き出しされました");
}
});
});
// イベント待機
app.listen(3000, () => console.log('Listening on port 3000'));
実行結果
正常に書き出せた場合
正常にファイルに書き込みができた場合、ステータスコード200(正常)がHTTPレスポンスとして返される。
正常に書き出せなかった場合
指定されたパスが無いなど、正常に書き出せなかった場合はステータスコード500(サーバエラー)がHTTPレスポンスとして返される。
ファイルへの書き出し(ちゃんとチェックする編)
簡単編ではフォルダの存在有無やアクセス権をチェックせず、writeFileでいきなりファイルの書き込みを行っているが、実際にはフォルダの存在有無やアクセス権をチェックした方がよい。
コード
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
// ルート設定
app.get('/', (req, res) => res.send('Hello World'));
// api-create-request-fileの設定
app.get('/api/v1/create-request-file', (req, res) =>{
var filePath = "C:/test/request.txt"
var dirName = path.dirname(filePath);
fs.access(dirName, fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
if (err.code === "ENOENT") {
fs.mkdirSync(dirName);
console.log("フォルダ " + dirName + " を作成しました");
} else {
console.log("フォルダ " + dirName + " の書き込み権限がありません");
return res.status(500).send("エラーが発生しました");
}
}
fs.writeFile(filePath , "書き込みデータ" , (err) => {
if(err){
return res.status(500).send("エラーが発生しました");
}
else{
return res.status(200).send("ファイルが正常に書き出しされました");
}
});
});
});
// イベント待機
app.listen(3000, () => console.log('Listening on port 3000'));
コードの解説
fs.stat() or fs.access()
Nodeでディレクトリの有無を確かめるにはfs.stat()
かfs.access()
を使用するが、書き込みを行うのであれば書き込み権限もまとめてチェックできた方がいいので今回はfs.access()
を使用している。
fs.access()
は第一引数にpath、第二引数(オプション)にmodeを指定し、コールバックで結果(err)が返ってくる。
fs.access()のmodeに指定する値
デフォルトではfs.constants.F_OK
となっている。
fs.constants.F_OK
は指定されたpathの存在有無しかチェックしてくれないので、権限も含めてチェックしたい場合はmodeも指定することになる。
定数 | 説明 |
---|---|
fs.constants.F_OK | リソースが存在するか(読み書きの権限についてはチェックしない) |
fs.constants.R_OK | リソースが読み取り可能か |
fs.constants.W_OK | リソースが書き込み可能か |
fs.constants.X_OK | リソースが実行可能か(Windows環境の場合はF_OKと同じ動作となる) |
今回はファイルの読み取りと書き込みが可能かをチェックしたいので、fs.access()
のmodeにはfs.constants.R_OK
とfs.constants.W_OK
をパイプ(|
)でつないで、fs.constants.R_OK | fs.constants.W_OK
と指定することになる。
コールバック(err)の扱い
modeで指定したチェック内容に対してエラー(存在しない、読み取り不可、書き込み不可など)がある場合、コールバックのerrに情報が詰められて返される。
err.codeに格納されたエラーコードでエラーの内容がわかる。エラーコードはLinuxのファイルシステムのエラーコードに則っているらしい。
nodejs.org - Common System Errors
Errors: Linux System Errors
err.codeの値 | 説明 |
---|---|
ENOENT | 指定されたリソースが存在しない |
EPERM | 指定されたリソースが存在するが権限が不足している |
EBUSY | 指定されたリソースがビジー状態(他のプロセスで使用されている) |
今回はfs.constants.R_OK | fs.constants.W_OK
でエラーが返された場合、フォルダが無い場合はフォルダを作成したい。
そのためerr.code
の値がENOENT
の場合(指定したフォルダが存在しない場合)はfs.mkdirSync()
でフォルダを作成している。
ファイルの読み込み
ファイルの読み込みはNodeのfsモジュールに組み込まれているfs.readFile()
で行う。
コード
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
// ルート設定
app.get('/', (req, res) => res.send('Hello World'));
// api-create-request-fileの設定
app.get('/api/v1/create-request-file', (req, res) =>{
var filePath = "C:/test/request.txt"
var dirName = path.dirname(filePath);
fs.access(dirName, fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
if (err.code === "ENOENT") {
fs.mkdirSync(dirName);
console.log("フォルダ " + dirName + " を作成しました");
} else {
console.log("フォルダ " + dirName + " の書き込み権限がありません");
return res.status(500).send("エラーが発生しました");
}
}
fs.writeFile(filePath , "書き込みデータ" , (err) => {
if(err){
return res.status(500).send("エラーが発生しました");
}
else{
return res.status(200).send("ファイルが正常に書き出しされました");
}
});
});
});
// api-read-response-fileの設定
app.get('/api/v1/read-response-file', (req, res) =>{
var filePath = "C:/test/response.txt"
var dirName = path.dirname(filePath);
fs.access(dirName, fs.constants.R_OK, (err) => {
if (err) {
if (err.code === "ENOENT") {
console.log("フォルダ " + dirName + " が存在しません");
} else{
console.log("フォルダ " + dirName + " の読み取り権限がありません");
}
return res.status(500).send("エラーが発生しました");
}
fs.readFile(filePath , "utf8", (err, data) => {
if(err){
return res.status(500).send("エラーが発生しました");
}
else{
return res.status(200).send(data);
}
});
});
});
// イベント待機
app.listen(3000, () => console.log('Listening on port 3000'));
読み込むファイルの内容
読み込みデータ
実行結果
正常に読み込めた場合
正常にファイルを読み込めた場合、ステータスコード200(正常)で読み込んだdataがHTTPレスポンスとして返される。
正常に読み込めなかった場合
指定されたパスが無いなど、正常に読み込めなかった場合はステータスコード500(サーバエラー)がHTTPレスポンスとして返される。