# [GDSC] NodeJS (2)
[TOC]
> 我不是 Javascript 專業,講錯歡迎指教
---
## HTTP Request Method (REST)
#### Protocol
- HTTP
- REST / RESTful
#### Dependency
- `npm install mongodb mongoose dotenv`
- Create database, open [Atlas](https://cloud.mongodb.com/v2#/org/6589537fa4947020c782e44b/)
1. build a project (free plan) with sample data
2. choose `Drivers` option to build connection
3. connection link should be like
`mongodb+srv://<username>:<password>@cluster0.c0ikn.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0`
4. Click `Collection` column, a sample database named `sample_mflix`
5. Replace connection link with your username and password, add database name `sample_mflix` behind the base link **(or use `dbName` option with mongoose)**
6. mainly use `user` table in this course
#### Load .env
File path: `app.js`
```javascript=
require('dotenv').config();
const dbLink = process.env.MONGODB_API;
```
#### Connect to database
File path: `app.js`
```javascript=
// Add dependency
const mongoose = require('mongoose');
// Connect to ODM with driver link
mongoose.connect(dbLink, {
dbName: "sample_mflix",
});
// Event listener
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
db.once('open', function () {
console.log('Connected to MongoDB');
});
```
#### Schema
File path: `models/user.js`
```javascript=
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// syntax: mongoose.model(modelName, schema)
const User = mongoose.model('User', userSchema);
module.exports = User;
```
:question: 為什麼知道 schema 長這樣呢? 我又不會通靈
:a: 答案是去 Atlas 看已經建立好的 sample data 樣貌!
**API**
[`mongoose.Schema()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.Schema())
[`mongoose.model()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.model())
### GET
**用途**
從伺服器 (server) 取得特定資源
**範例**
File path: `routes/users.js`
Route: `/users`
```javascript=
router.get('/', async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
```
File path: `routes/users.js`
Route: `/users/:id`
```javascript=
router.get('/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
```
**API**
[`Model.find()`](https://mongoosejs.com/docs/api/model.html#Model.find())
### POST
**用途**
將數據發送到伺服器
**範例**
File path: `routes/users.js`
Route: `/users`
```javascript=
router.post('/', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
```
**API**
[`Model.prototype.save()`](https://mongoosejs.com/docs/api/model.html#Model.prototype.save())
### PUT
**用途**
更新伺服器中的指定數據,通常是全部更新
> 如果是部分更新,使用 `PATCH`
**範例**
File path: `routes/users.js`
Route: `/users/:id`
```javascript=
router.put('/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
```
**API**
[`Model.findByIdAndUpdate()`](https://mongoosejs.com/docs/api/model.html#Model.findByIdAndUpdate())
### DELETE
**用途**
刪除伺服器中的指定數據
**範例**
File path: `routes/users.js`
Route: `/users/:id`
```javascript=
router.delete('/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json({ message: 'User deleted' });
} catch (error) {
res.status(500).json({ message: error.message });
}
});
```
**API**
[`Model.findByIdAndDelete()`](https://mongoosejs.com/docs/api/model.html#Model.findByIdAndDelete())
### OPTIONS
**用途**
設定請求資訊, including mehtod, headers, status code...
**範例**
```javascript=
app.options('/users', (req, res) => {
res.setHeader('Allow', 'GET, POST, PUT, DELETE, OPTIONS');
res.status(204).send();
});
```
**API**
GeeksforGeeks - [Node response.setHeader() Method](https://www.geeksforgeeks.org/node-js-response-setheader-method/)
> [!Note] More details
> - MDN - [HTTP request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
> - MDN - [HTTP response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
### Manual Testing
#### Prerequisite
- Install vscode plugin **Thunder Client**
---
## Websocket
1. 使用 `express-generator` 生成專案後,在 `/bin/www` 設定
```javascript=
/**
* Import websocket package
*/
const WebSocket = require('ws');
/**
* Create a websocket instance
*/
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
console.log('A new client connected');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send(`Server received: ${message}`);
});
ws.on('close', () => {
console.log('Client disconnected');
});
ws.send('Welcome to the WebSocket server!');
});
```
2. Add a file named `ws-client.html` under `/public/we-client.html`
```html=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Client</title>
</head>
<body>
<h1>WebSocket Client</h1>
<input id="message" type="text" placeholder="Type a message">
<button onclick="sendMessage()">Send</button>
<div id="messages"></div>
<script>
const ws = new WebSocket(`ws://${window.location.host}`);
ws.onopen = function() {
document.getElementById('messages').innerHTML += '<p>Connected to the server</p>';
};
ws.onmessage = function(event) {
document.getElementById('messages').innerHTML += `<p>Server: ${event.data}</p>`;
};
ws.onclose = function() {
document.getElementById('messages').innerHTML += '<p>Disconnected from the server</p>';
};
function sendMessage() {
const message = document.getElementById('message').value;
ws.send(message);
document.getElementById('messages').innerHTML += `<p>You: ${message}</p>`;
}
</script>
</body>
</html>
```
3. Access `http://localhost:3000/ws-client.html`