はじめに
普段業務ではJavascript、Typescriptを用いたフロントエンドの画面ばかりを取り扱っているので、あまりバックエンドの機能に触れる機会がありませんでした。
なのでアプリの一つでも作ってみて勉強するべきだなぁと、普段から考えていました。
とはいっても作りたいものが特にないので、知り合いに聞いたところ「ファイルアップローダー」を自前で作れるようになるとフルスタックな知識が学べるようなので、今回は画像アップローダーを作成することにしました。
環境
React v18
express.js
multer
バックエンドはサーバーを借りて動かそうと思いましたが、無料で使えるよさげなのがなさそうなので(昔は色々あった気が...)止む無しでローカルに立ち上げます。
成果
画像を選択し、アップロードボタンを押すことで画像がサーバーへアップロードされます。
解説
特に複雑な事はしていないのですが、
frontend
フロントエンド部分はコンポーネントライブラリのMUIを使用してデザインしています。
<div className="App">
<Stack direction={"column"} sx={{ mt: 4, mb: 6 }}>
<Box>
<Button variant="contained" color="primary" component="label">
<input accept="image/*" type="file" onChange={(e) => { setFile(e.target.files[0]); setFileName(e.target.files[0].name) }} style={{ display: 'none' }}/>
画像を選択
</Button>
<Typography sx={{ mt: 2 }}>
{fileName}
</Typography>
</Box>
<Box sx={{ mt: 4 }}>
<Button variant="outlined" type="button" onClick={upload} startIcon={<FileUploadIcon />} disabled={!file}>
アップロード
</Button>
</Box>
</Stack>
<ImageList cols={3} rowHeight={200} sx={{ height: "700px" }}>
{imgData && imgData.images.map((item) => (
<ImageListItem key={item}>
<img
srcSet={`${imgUrl}${item}?w=164&h=164&fit=crop&auto=format&dpr=2 2x`}
src={`${imgUrl}${item}?w=164&h=164&fit=crop&auto=format`}
loading="lazy"
/>
</ImageListItem>
))}
</ImageList>
</div>
backend
バックエンドでは、API "/upload"でファイルの送信リクエストを受け取りストレージに保存し、"/images"で保存されているファイル名一覧を取得して送り返しています。
const express = require("express")
const cors = require("cors")
const multer = require("multer")
const fs = require('fs');
const path = require('path');
const port = 3001
const app = express()
app.use(cors())
app.use(express.json())
app.use('/img', express.static(__dirname + '/public/Files'))
const storage = multer.diskStorage({
destination: function(req, file, cb) {
return cb(null, "./public/Files")
},
filename: function(req, file, cb) {
return cb(null, `${Date.now()}_${file.originalname}`)
}
})
const upload = multer({storage, fileFilter: (req, file, cb) => {
if(file.mimetype.includes("image")) {
cb(null, true);
return;
}
cb(new TypeError("Invalid File Type"));
}})
app.post("/upload", upload.single("file"), (req, res) => {
console.log(req.body)
console.log(req.file)
res.status(200).send("uploaded")
})
app.get("/images", (req, res) => {
fs.readdir("./public/Files", (err, files) => {
if (err) {
console.error('Error reading directory:', err);
return res.status(500).json({ error: 'Failed to read directory' });
}
// ファイルを画像ファイルにフィルタリング
const imageFiles = files.filter(file => {
const ext = path.extname(file).toLowerCase();
return ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif';
});
res.status(200).json({ images: imageFiles });
});
})
app.listen(port, () => {
console.log("Server is running")
})
Github https://github.com/gigadeli/prac_img_uploader
おわりに
バックエンドはローカル環境かつ、expressで作成したので、当たり前ですが難易度は高くなかったです。
もっとこうDBを用意してCRUD機能も付けて... でやりたかったのですが
多分作りきる前に燃え尽きるので、今回はやりきることを目標にしました