Thông thường, mọi người sẽ xử lý hình upload lên với các thư viện như Multer và lưu trữ trực tiếp hình ảnh trong hệ thống tệp (của server) hoặc trong CSDL. Cách làm này có khá nhiều hạn chế, như tăng thêm khối lượng công việc, requests mà server cần xử lý, hay nếu muốn xử lý hình ảnh như crop, scale, … thì công việc triển khai cũng khá vất vả. Trong bài viết này, mình sẽ hướng dẫn mọi người upload hình ảnh lên Cloudinary, giúp giảm tải công việc cho server cũng như tận dụng được các tính năng liên quan đến AI để xử lý hình ảnh tải lên

Cloudinary là gì?

Cloudinary là một dịch vụ upload ảnh và video (SaaS) giúp quản lý tất cả hình ảnh, video của ứng dụng Web hoặc ứng dụng di động, cung cấp các giải pháp như tải lên, lưu trữ, thao tác, tối ưu hóa và phân phối nội dung.

Bạn có thể dễ dàng tải hình ảnh lên với Cloudinary, tự động hóa các thao tác xử lý hình ảnh bằng AI mà không cần cài đặt bất kỳ phần mềm hay phải viết thêm đoạn mã nào, sau đó, hình ảnh cũng được phân phối qua CDN giúp tối ưu tốc độ tải nội dung cũng như hạn chế request đến server 👍

Upload hình ảnh lên Cloudinary

Trước hết chúng ta cần tạo một server Node.js đơn giản cho ví dụ này

Tạo thư mục dự án

mkdir upload-to-cloudinary-example
cd upload-to-cloudinary-example

Khởi tạo dự án và cài đặt dependencies

npm init -y

npm i express dotenv multer streamifier cloudinary
npm i -D typescript ts-node-dev @types/node @types/express @types/multer @types/streamifier

Giải thích một số packages được cài đặt:

  • express: Framework để tạo webserver
  • dotenv: Load environment variables từ file .env
  • multer: Xử lý hình ảnh upload lên server
  • streamifier: Convert file buffer trong request thành Readable Stream
  • cloudinary: SDK để tích hợp với dịch vụ Cloudinary
  • ts-node-dev: Chạy trực tiếp tệp TypeScript thay vì phải biên dịch

Và một số packages khác liên quan đến TypeScript, do dự án này mình sẽ sử dụng TypeScript, vì thế cần khởi tạo tệp tsconfig.json

npx tsc --init

Chỉnh sửa thư mục output khi build trong tsconfig.json

{ 
   // ... other options
   "outDir": "dist"
   // ... other options
}
tsconfig.json

Thêm script khởi chạy server trong package.json

{
   // ... other options
   "scripts": {
    "start": "node dist/server.js",
    "dev": "ts-node-dev src/server.ts",
    "build": "tsc",
  }
   // ... other options
}
package.json

Tạo server

Trước hết, cùng tạo một server đơn giản

import express from "express";
import dotenv from "dotenv";

dotenv.config();

const app = express()
    .use(express.urlencoded({ extended: true }))
    .use(express.json());

app.get("/", (req, res, next) => {
    return res.json({ message: "Hello!" });
});

app.listen(8080, () => {
    console.log("Server listening on port 8080");
});
src/server.ts

Dùng Postman để test trước đã

Test server với Postman

Xử lý hình ảnh upload với Multer

Bước đầu đã xong, tiếp theo chúng ta tạo API để upload hình ảnh

// other imports
import multer from "multer";

const upload = multer({
    storage: multer.memoryStorage(),
    limits: {
        fileSize: 2 * 1024 * 1024, // 2 MB
        files: 1,
    },
});

// others endpoints
app.post("/upload", upload.single("file"), (req, res, next) => {
    if (!req.file) {
        return res.status(400).json({ error: "No file uploaded" });
    }

    return res.json({
        filename: req.file.originalname,
        fileSize: req.file.size,
        mimetype: req.file.mimetype,
    });
});
src/server.ts

Hỉnh ảnh tải lên chỉ cần lưu tạm vào bộ nhớ do chúng ta sẽ upload lên Cloudinary, kích thước tối đa là 2MB, những tùy chọn này mọi người có thể điều chỉnh cho phù hợp

Xong, test với Postman trước đã

Test upload API với Postman

Cloudinary API Key

Trước khi upload hình ảnh lên Cloudinary, tất nhiên chúng ta cần đăng ký tài khoản và lấy API Key từ Cloudinary đã, truy cập vào https://cloudinary.com/ để đăng ký tài khoản

Bước hướng dẫn đăng ký tài khoản mình bỏ qua, sau khi đăng ký thành công, trên màn hình Dashboard, mọi người chỉ cần copy Cloudinary URL Environment được tạo sẵn và paste vào file .env là được

Cloudinary API Key

Paste vào .env

CLOUDINARY_URL=YOUR_CLOUDINARY_URL
.env

Upload hình ảnh lên Cloudinary

Đã đến bước cuối cùng, hình ảnh trước đó đã xử lý bằng Multer bây giờ có thể upload lên Cloudinary rồi

Tạo module upload lên Cloudinary

import { UploadApiResponse, v2 as cloudinary } from "cloudinary";
import streamifier from "streamifier";

const uploadToCloudinary = (file: Express.Multer.File) => {
    return new Promise<UploadApiResponse>((resolve, reject) => {
        let stream = cloudinary.uploader.upload_stream((error, result) => {
            if (result) {
                resolve(result);
            } else {
                reject(error);
            }
        });

        streamifier.createReadStream(file.buffer).pipe(stream);
    });
};

export default uploadToCloudinary;
src/utils/cloudinary.ts

Trong request handler, upload hình ảnh đã xử lý trước đó với Multer lên Cloudinary

// other imports
dotenv.config();

// import sau câu lệnh dotenv.config()
import uploadToCloudinary from "./utils/cloudinary";

// other endpoints
app.post("/upload", upload.single("file"), async (req, res, next) => {
    if (!req.file) {
        return res.status(400).json({ error: "No file uploaded" });
    }

    try {
        const result = await uploadToCloudinary(req.file);

        return res.status(201).json({
            url: result.url,
        });
    } catch (err) {
        return res.status(500).json({ error: err });
    }
});
src/server.ts

❕ Lưu ý: Do Cloudinary SDK tự động lấy API Key từ environment, nên ở bước này, cần import uploadToCloudinary sau câu lệnh dotenv.config(), nếu không sẽ báo lỗi thiếu API Key

Và thế là xong 💥 cùng test với Postman

Test upload lên Cloudinary với Postman

Sau khi tải lên Cloudinary, kết quả trả về bao gồm URL hình ảnh, kích thước, … lúc này thì mọi người biết làm gì tiếp theo rồi đúng không 🤣 (cho bạn nào vẫn chưa biết thì tiếp theo có thể là lưu URL vào database chẳng hạn)

Thao tác với hình ảnh

Bước cuối cùng của cuối cùng, Cloudinary cung cấp rất nhiều tính năng, trong đó có tự động thực hiện chuỗi thao tác với hình ảnh mà chúng ta tải lên, mọi người có thể áp dụng thao tác trong câu lệnh tải lên, hoặc áp dụng trong cài đặt upload trên giao diện Web

Cài đặt

Tiếp theo chọn tab Upload

Tab Upload

Kéo xuống Upload presets và chọn edit

Upload presets

Trong tab Upload Manipulation, có rất nhiều tùy chọn thao tác với hình ảnh

Upload manipulation

Trong ví dụ này, mình để scale hình ảnh về kích thước 256x256, mọi người có thể khám phá các chức năng khác ở đây (bao gồm cả chỉnh sửa ảnh bằng AI đẹp lung linh nữa luôn 🤟), các cài đặt sẽ này tự động áp dụng cho các hình ảnh tải lên

Tổng kết

Trong ví dụ vừa rồi, mình đã hướng dẫn mọi người upload hình ảnh lên Cloudinary thông qua Node.js, mọi người có thể tham khảo thêm thông qua một số link sau: