Trong bài viết này, chúng tôi sẽ hướng dẫn bạn từng bước về cách sử dụng nút-postgres với Node.js Express. Chúng tôi sẽ áp dụng nó vào một dự án thực tế, làm cho nó dễ hiểu, linh hoạt và có thể mở rộng. Chúng tôi cũng sẽ triển khai một số cơ chế quan trọng như singleton, kho lưu trữ, truy vấn trên hai cơ sở dữ liệu để đọc và ghi cũng như cơ chế kết nối lại khi bị ngắt kết nối khỏi cơ sở dữ liệu.
Giới thiệu về Node-Postgres
Node-Postgres là một thư viện máy khách PostgreSQL phổ biến cho Node.js. Nó cho phép bạn tương tác với cơ sở dữ liệu PostgreSQL một cách dễ dàng và hiệu quả. Với API đơn giản của nó, bạn có thể thực hiện các truy vấn, quản lý giao dịch và sử dụng tổng hợp kết nối để có hiệu suất tốt hơn.
Cấu trúc nguồn
Dưới đây là tổng quan về cấu trúc nguồn cho dự án này:
1 2 3 4 5 6 7 8 9 10 11 12 | node-postgres-demo/ |-- initdb/ | |-- init.sql |-- repositories/ | |-- userRepository.js |-- .env |-- db.js |-- docker-compose.yml |-- Dockerfile |-- index.js |-- package.json |
Thiết lập dự án
Trước khi đi sâu vào mã, hãy đảm bảo bạn đã cài đặt phần sau:
- Node.js (14.x trở lên)
- PostgreSQL (9.6 trở lên)
Nếu bạn có docker, bạn cũng có thể chạy dự án này mà không cần những thứ này.
Đầu tiên, tạo một thư mục mới cho dự án của bạn và điều hướng đến nó:
1 2 3 | <span class="token function">mkdir</span> node-postgres-demo <span class="token builtin class-name">cd</span> node-postgres-demo |
Khởi tạo dự án Node.js mới và cài đặt các phụ thuộc cần thiết:
1 2 3 4 | <span class="token function">npm</span> init -y <span class="token function">npm</span> <span class="token function">install</span> express pg dotenv <span class="token function">npm</span> <span class="token function">install</span> nodemon --save-dev |
Tạo nhóm kết nối Singleton
Nhóm kết nối là bộ nhớ cache của các kết nối cơ sở dữ liệu được duy trì để cải thiện hiệu suất. Để tạo nhóm kết nối đơn lẻ, chúng tôi sẽ sử dụng gói pg
và mẫu thiết kế Singleton.
Tạo một tệp mới có tên db.js
và dán đoạn mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token keyword">const</span> <span class="token punctuation">{</span> Pool <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'pg'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">{</span> <span class="token function">constructor</span> <span class="token punctuation">(</span> <span class="token parameter">connectionString</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> Singleton <span class="token punctuation">.</span> instances <span class="token punctuation">)</span> <span class="token punctuation">{</span> Singleton <span class="token punctuation">.</span> instances <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> Singleton <span class="token punctuation">.</span> instances <span class="token punctuation">[</span> connectionString <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> pool <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> <span class="token function">createPool</span> <span class="token punctuation">(</span> connectionString <span class="token punctuation">)</span> <span class="token punctuation">;</span> Singleton <span class="token punctuation">.</span> instances <span class="token punctuation">[</span> connectionString <span class="token punctuation">]</span> <span class="token operator">=</span> pool <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">getInstance</span> <span class="token punctuation">(</span> <span class="token parameter">connectionString</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Singleton <span class="token punctuation">.</span> instances <span class="token punctuation">[</span> connectionString <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">createPool</span> <span class="token punctuation">(</span> <span class="token parameter">connectionString</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> pool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Pool</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> connectionString <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> pool <span class="token punctuation">.</span> <span class="token function">on</span> <span class="token punctuation">(</span> <span class="token string">'error'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">err <span class="token punctuation">,</span> client</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> <span class="token string">'Unexpected error on idle client: '</span> <span class="token punctuation">,</span> connectionString <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTimeout</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Attempting to reconnect...: '</span> <span class="token punctuation">,</span> connectionString <span class="token punctuation">)</span> <span class="token punctuation">;</span> Singleton <span class="token punctuation">.</span> instances <span class="token punctuation">[</span> connectionString <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> <span class="token function">createPool</span> <span class="token punctuation">(</span> connectionString <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">5000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> pool <span class="token punctuation">.</span> <span class="token function">on</span> <span class="token punctuation">(</span> <span class="token string">'connect'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Connected to the database'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> pool <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> Singleton <span class="token punctuation">;</span> |
Bây giờ, bạn có thể sử dụng lớp Singleton
để lấy một phiên bản nhóm kết nối trong các phần khác của ứng dụng của bạn.
Triển khai mẫu kho lưu trữ
Mẫu kho lưu trữ giúp trừu tượng hóa logic truy cập dữ liệu, làm cho nó dễ bảo trì và kiểm tra hơn. Tạo một thư mục mới có tên là repositories
và tạo một tệp mới bên trong nó có tên userRepository.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token keyword">const</span> Singleton <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'../db'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">UserRepository</span> <span class="token punctuation">{</span> <span class="token function">constructor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> readPool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span> <span class="token punctuation">(</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">READ_DATABASE_URL</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">getInstance</span> <span class="token punctuation">(</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">READ_DATABASE_URL</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> writePool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span> <span class="token punctuation">(</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">WRITE_DATABASE_URL</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">getInstance</span> <span class="token punctuation">(</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">WRITE_DATABASE_URL</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token function">getUserById</span> <span class="token punctuation">(</span> <span class="token parameter">id</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> readPool <span class="token punctuation">.</span> <span class="token function">query</span> <span class="token punctuation">(</span> <span class="token string">'SELECT * FROM users WHERE id = $1'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> id <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> rows <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token function">createUser</span> <span class="token punctuation">(</span> <span class="token parameter">user</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> writePool <span class="token punctuation">.</span> <span class="token function">query</span> <span class="token punctuation">(</span> <span class="token string">'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> user <span class="token punctuation">.</span> name <span class="token punctuation">,</span> user <span class="token punctuation">.</span> email <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> rows <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token function">updateUser</span> <span class="token punctuation">(</span> <span class="token parameter">id <span class="token punctuation">,</span> user</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> writePool <span class="token punctuation">.</span> <span class="token function">query</span> <span class="token punctuation">(</span> <span class="token string">'UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> user <span class="token punctuation">.</span> name <span class="token punctuation">,</span> user <span class="token punctuation">.</span> email <span class="token punctuation">,</span> id <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> rows <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token function">deleteUser</span> <span class="token punctuation">(</span> <span class="token parameter">id</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> writePool <span class="token punctuation">.</span> <span class="token function">query</span> <span class="token punctuation">(</span> <span class="token string">'DELETE FROM users WHERE id = $1 RETURNING *'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> id <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> res <span class="token punctuation">.</span> rows <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> UserRepository <span class="token punctuation">;</span> |
Cấu hình môi trường
Tạo tệp .env
trong thư mục gốc của dự án để lưu trữ các biến môi trường:
1 2 3 4 | READ_DATABASE_URL=postgres://user:password@db_read:5432/db_read WRITE_DATABASE_URL=postgres://user:password@db_write:5432/db_write PORT=3000 |
Đảm bảo thay thế your_read_db_connection_string
và your_write_db_connection_string
bằng các chuỗi kết nối PostgreSQL thực tế của bạn.
Package.json và Điểm đầu vào
Bạn cũng có thể sửa đổi tệp package.json
trong thư mục gốc của dự án với nội dung sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token punctuation">{</span> <span class="token key atrule">"name"</span> <span class="token punctuation">:</span> <span class="token string">"node-postgres-demo"</span> <span class="token punctuation">,</span> <span class="token key atrule">"version"</span> <span class="token punctuation">:</span> <span class="token string">"1.0.0"</span> <span class="token punctuation">,</span> <span class="token key atrule">"description"</span> <span class="token punctuation">:</span> <span class="token string">""</span> <span class="token punctuation">,</span> <span class="token key atrule">"main"</span> <span class="token punctuation">:</span> <span class="token string">"index.js"</span> <span class="token punctuation">,</span> <span class="token key atrule">"scripts"</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">"start"</span> <span class="token punctuation">:</span> <span class="token string">"node index.js"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token key atrule">"keywords"</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token key atrule">"author"</span> <span class="token punctuation">:</span> <span class="token string">""</span> <span class="token punctuation">,</span> <span class="token key atrule">"license"</span> <span class="token punctuation">:</span> <span class="token string">"ISC"</span> <span class="token punctuation">,</span> <span class="token key atrule">"dependencies"</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">"dotenv"</span> <span class="token punctuation">:</span> <span class="token string">"^10.0.0"</span> <span class="token punctuation">,</span> <span class="token key atrule">"express"</span> <span class="token punctuation">:</span> <span class="token string">"^4.17.1"</span> <span class="token punctuation">,</span> <span class="token key atrule">"pg"</span> <span class="token punctuation">:</span> <span class="token string">"^8.7.1"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Nếu bạn đã sửa đổi tệp package.json
, hãy chạy lại lệnh này:
1 2 | <span class="token function">npm</span> i |
Tạo một tệp index.js
trong thư mục gốc của dự án:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> UserRepository <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./repositories/userRepository'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'dotenv'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">config</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> express <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> userRepository <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserRepository</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/users/:id'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token keyword">await</span> userRepository <span class="token punctuation">.</span> <span class="token function">getUserById</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> params <span class="token punctuation">.</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> user <span class="token punctuation">)</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> user <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">404</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'User not found'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">500</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Internal server error'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token string">'/users'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newUser <span class="token operator">=</span> <span class="token keyword">await</span> userRepository <span class="token punctuation">.</span> <span class="token function">createUser</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> body <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">201</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> newUser <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">500</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Internal server error'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">put</span> <span class="token punctuation">(</span> <span class="token string">'/users/:id'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> updatedUser <span class="token operator">=</span> <span class="token keyword">await</span> userRepository <span class="token punctuation">.</span> <span class="token function">updateUser</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> params <span class="token punctuation">.</span> id <span class="token punctuation">,</span> req <span class="token punctuation">.</span> body <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> updatedUser <span class="token punctuation">)</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> updatedUser <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">404</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'User not found'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">500</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Internal server error'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">delete</span> <span class="token punctuation">(</span> <span class="token string">'/users/:id'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> deletedUser <span class="token operator">=</span> <span class="token keyword">await</span> userRepository <span class="token punctuation">.</span> <span class="token function">deleteUser</span> <span class="token punctuation">(</span> req <span class="token punctuation">.</span> params <span class="token punctuation">.</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> deletedUser <span class="token punctuation">)</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> deletedUser <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">404</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'User not found'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">status</span> <span class="token punctuation">(</span> <span class="token number">500</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Internal server error'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">PORT</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token constant">PORT</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Server is running on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Giờ đây, bạn đã có một ứng dụng Node.js Express hoàn chỉnh bằng cách sử dụng nút-postgres, với nhóm kết nối đơn lẻ, mẫu kho lưu trữ, truy vấn nhiều cơ sở dữ liệu cho các thao tác đọc và ghi cũng như cơ chế kết nối lại khi bị ngắt kết nối khỏi cơ sở dữ liệu.
Để chạy ứng dụng, hãy sử dụng lệnh sau nếu bạn có sẵn DB Postgres nếu không thì bước tiếp theo:
1 2 | <span class="token function">npm</span> start |
Cấu hình Docker và khởi tạo dữ liệu mẫu
Để khởi tạo dữ liệu mẫu cho bảng users
, chúng ta có thể sử dụng tập lệnh SQL chạy khi bộ chứa PostgreSQL khởi động. Tạo một thư mục mới có tên initdb
trong thư mục gốc của dự án của bạn và bên trong thư mục initdb
, hãy tạo một tệp có tên init.sql
với nội dung sau:
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">CREATE</span> <span class="token keyword">TABLE</span> <span class="token keyword">IF</span> <span class="token operator">NOT</span> <span class="token keyword">EXISTS</span> users <span class="token punctuation">(</span> id <span class="token keyword">SERIAL</span> <span class="token keyword">PRIMARY</span> <span class="token keyword">KEY</span> <span class="token punctuation">,</span> name <span class="token keyword">VARCHAR</span> <span class="token punctuation">(</span> <span class="token number">255</span> <span class="token punctuation">)</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token punctuation">,</span> email <span class="token keyword">VARCHAR</span> <span class="token punctuation">(</span> <span class="token number">255</span> <span class="token punctuation">)</span> <span class="token keyword">UNIQUE</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">INSERT</span> <span class="token keyword">INTO</span> users <span class="token punctuation">(</span> name <span class="token punctuation">,</span> email <span class="token punctuation">)</span> <span class="token keyword">VALUES</span> <span class="token punctuation">(</span> <span class="token string">'Alice'</span> <span class="token punctuation">,</span> <span class="token string">'alice@example.com'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token string">'Bob'</span> <span class="token punctuation">,</span> <span class="token string">'bob@example.com'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token string">'Charlie'</span> <span class="token punctuation">,</span> <span class="token string">'charlie@example.com'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Tập lệnh này sẽ tạo bảng users
nếu nó không tồn tại và chèn ba người dùng mẫu vào bảng.
Hãy tạo một tệp mới có tên Dockerfile
và dán đoạn mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token instruction"><span class="token keyword">FROM</span> node:16</span> <span class="token instruction"><span class="token keyword">WORKDIR</span> /app</span> <span class="token instruction"><span class="token keyword">COPY</span> package*.json ./</span> <span class="token instruction"><span class="token keyword">RUN</span> npm install</span> <span class="token instruction"><span class="token keyword">COPY</span> . .</span> <span class="token instruction"><span class="token keyword">EXPOSE</span> 3000</span> <span class="token instruction"><span class="token keyword">CMD</span> [ <span class="token string">"npm"</span> , <span class="token string">"start"</span> ]</span> |
Bây giờ, hãy tạo một tệp mới có tên docker-compose.yml
và dán đoạn mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token key atrule">version</span> <span class="token punctuation">:</span> <span class="token string">'3.9'</span> <span class="token key atrule">services</span> <span class="token punctuation">:</span> <span class="token key atrule">app</span> <span class="token punctuation">:</span> <span class="token key atrule">build</span> <span class="token punctuation">:</span> . <span class="token key atrule">ports</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">'${PORT}:${PORT}'</span> <span class="token key atrule">depends_on</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> db_read <span class="token punctuation">-</span> db_write <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> READ_DATABASE_URL=$ <span class="token punctuation">{</span> READ_DATABASE_URL <span class="token punctuation">}</span> <span class="token punctuation">-</span> WRITE_DATABASE_URL=$ <span class="token punctuation">{</span> WRITE_DATABASE_URL <span class="token punctuation">}</span> <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> . <span class="token punctuation">:</span> /app <span class="token key atrule">db_read</span> <span class="token punctuation">:</span> <span class="token key atrule">image</span> <span class="token punctuation">:</span> postgres <span class="token punctuation">:</span> 12 <span class="token punctuation">-</span> alpine <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> POSTGRES_USER=user <span class="token punctuation">-</span> POSTGRES_PASSWORD=password <span class="token punctuation">-</span> POSTGRES_DB=db_read <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> ./initdb <span class="token punctuation">:</span> /docker <span class="token punctuation">-</span> entrypoint <span class="token punctuation">-</span> initdb.d <span class="token key atrule">db_write</span> <span class="token punctuation">:</span> <span class="token key atrule">image</span> <span class="token punctuation">:</span> postgres <span class="token punctuation">:</span> 12 <span class="token punctuation">-</span> alpine <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> POSTGRES_USER=user <span class="token punctuation">-</span> POSTGRES_PASSWORD=password <span class="token punctuation">-</span> POSTGRES_DB=db_write <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> ./initdb <span class="token punctuation">:</span> /docker <span class="token punctuation">-</span> entrypoint <span class="token punctuation">-</span> initdb.d |
Để chạy ứng dụng với Docker Compose, hãy sử dụng lệnh sau:
1 2 | docker-compose up |
Khi vùng chứa khởi động, bảng users
sẽ được tạo và điền dữ liệu mẫu. Và ứng dụng nút cũng được bắt đầu trong vùng chứa.
Phần kết luận
Trong bài viết này, chúng tôi đã đề cập đến cách sử dụng node-postgres
với Node.js Express
, triển khai nhóm kết nối đơn lẻ, mẫu kho lưu trữ, truy vấn nhiều cơ sở dữ liệu cho hoạt động đọc và ghi cũng như cơ chế kết nối lại. Bằng cách làm theo hướng dẫn này, bạn có thể xây dựng một ứng dụng linh hoạt, có thể mở rộng và có thể bảo trì bằng node-postgres
.
Và cuối cùng
Như mọi khi, tôi hy vọng bạn thích bài viết này và học được điều gì đó mới. Xin cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo!
Nếu các bạn thích bài viết này thì hãy cho mình 1 like và subscribe để ủng hộ mình nhé. Cảm ơn.