# สัปดาห์ที่ 10.1 - Fetch API

## บทนำ

**Fetch API** เป็น API ที่ใช้ขอข้อมูลจากเซิร์ฟเวอร์ผ่าน HTTP requests ได้อย่างง่ายและทรงพลัง มันเป็นการแทนที่ XMLHttpRequest ที่ใช้มาก่อนหน้านี้ และสนับสนุน Promise ที่ทำให้เขียนโค้ดได้ง่ายกว่า

---

## 1. แนวคิดพื้นฐาน

### HTTP Requests คืออะไร?

HTTP (HyperText Transfer Protocol) คือโปรโตคอลสำหรับสื่อสารบนอินเทอร์เน็ต

- **Request**: เบราว์เซอร์ส่งข้อมูลไปยังเซิร์ฟเวอร์
- **Response**: เซิร์ฟเวอร์ส่งข้อมูลกลับมาให้เบราว์เซอร์

### ประเภท HTTP Methods

```javascript
// GET - ขอข้อมูล (ไม่ส่งข้อมูลใหญ่ๆ)
fetch("https://api.example.com/users");

// POST - ส่งข้อมูล เพื่อสร้างรายการใหม่
fetch("https://api.example.com/users", {
  method: "POST",
  body: JSON.stringify({ name: "John" }),
});

// PUT - อัปเดตข้อมูลทั้งหมด
fetch("https://api.example.com/users/1", {
  method: "PUT",
  body: JSON.stringify({ name: "Jane" }),
});

// DELETE - ลบข้อมูล
fetch("https://api.example.com/users/1", {
  method: "DELETE",
});
```

---

## 2. Fetch API - ไวยากรณ์พื้นฐาน

### ตัวอย่างที่ 1: GET Request ง่ายๆ

```javascript
fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json()) // แปลงเป็น JSON
  .then((data) => console.log(data)) // ใช้ข้อมูล
  .catch((error) => console.error("Error:", error)); // จัดการ error
```

**ผลลัพธ์**:

```json
{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident...",
  "body": "quia et suscipit..."
}
```

---

### ตัวอย่างที่ 2: ใช้ Async/Await (ทันสมัยกว่า)

```javascript
async function getPost() {
  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts/1",
    );
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error("Error:", error);
  }
}

getPost();
```

---

## 3. Response Object

เมื่อ Fetch API ส่งกลับข้อมูล จะส่งกลับ Response Object ที่มีเมธอดต่างๆ:

```javascript
async function showResponse() {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");

  // ตรวจสอบสถานะ
  console.log("Status:", response.status); // 200, 404, 500 etc.
  console.log("OK?", response.ok); // true หรือ false

  // ดูหัวข้อ (Headers)
  console.log("Content-Type:", response.headers.get("content-type"));

  // แปลงข้อมูล
  const data = await response.json(); // JSON
  // const text = await response.text();           // Text
  // const blob = await response.blob();           // Binary data
}
```

---

## 4. POST Request - ส่งข้อมูล

```javascript
async function createPost() {
  const newPost = {
    title: "Hello World",
    body: "This is a new post",
    userId: 1,
  };

  const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
    method: "POST",
    headers: {
      "Content-Type": "application/json", // บอกว่าเราส่ง JSON
    },
    body: JSON.stringify(newPost), // แปลงเป็น JSON string
  });

  const data = await response.json();
  console.log("Created:", data);
}

createPost();
```

---

## 5. PUT Request - อัปเดตข้อมูล

```javascript
async function updatePost(id, newData) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(newData),
    },
  );

  const data = await response.json();
  console.log("Updated:", data);
}

updatePost(1, { title: "Updated Title", body: "Updated body" });
```

---

## 6. DELETE Request - ลบข้อมูล

```javascript
async function deletePost(id) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    {
      method: "DELETE",
    },
  );

  if (response.ok) {
    console.log("Post deleted successfully");
  } else {
    console.log("Failed to delete");
  }
}

deletePost(1);
```

---

## 7. Error Handling

```javascript
async function fetchWithErrorHandling() {
  try {
    const response = await fetch("https://invalid-url.com/data");

    // ตรวจสอบ HTTP errors
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();
    console.log(data);
  } catch (error) {
    // Network errors หรือ JSON parsing errors
    console.error("Error:", error.message);
  }
}
```

---

## 8. Headers - ส่วนหัวของ Request

Headers ใช้ในการส่งข้อมูลเพิ่มเติมกับ request:

```javascript
async function fetchWithHeaders() {
  const response = await fetch("https://api.example.com/protected", {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer YOUR_TOKEN", // ใช้สำหรับ authentication
      "User-Agent": "MyApp/1.0",
    },
  });

  const data = await response.json();
  console.log(data);
}
```

---

## 9. Fetch Options ตัวอื่นๆ

```javascript
const fetchOptions = {
  method: "GET",
  headers: {},
  body: null,
  mode: "cors", // 'cors', 'no-cors', 'same-origin'
  credentials: "include", // ส่ง cookies
  cache: "default", // 'default', 'no-cache', 'reload'
  redirect: "follow", // 'follow', 'error', 'manual'
  signal: AbortSignal.timeout(5000), // timeout ใน milliseconds
};
```

---

## 10. ตัวอย่างจริง: ดึงข้อมูลผู้ใช้

```html
<!DOCTYPE html>
<html lang="th">
  <head>
    <meta charset="UTF-8" />
    <title>Fetch API Example</title>
    <style>
      body {
        font-family: Arial;
        margin: 20px;
      }
      .user {
        border: 1px solid #ccc;
        padding: 10px;
        margin: 10px 0;
      }
      .loading {
        color: blue;
      }
      .error {
        color: red;
      }
    </style>
  </head>
  <body>
    <h1>ดึงข้อมูลผู้ใช้</h1>
    <button onclick="fetchUser()">ดึงข้อมูล User ID 1</button>
    <div id="result"></div>

    <script>
      async function fetchUser() {
        const resultDiv = document.getElementById("result");
        resultDiv.innerHTML = '<p class="loading">กำลังโหลด...</p>';

        try {
          const response = await fetch(
            "https://jsonplaceholder.typicode.com/users/1",
          );

          if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
          }

          const user = await response.json();

          resultDiv.innerHTML = `
          <div class="user">
            <h2>${user.name}</h2>
            <p><strong>Email:</strong> ${user.email}</p>
            <p><strong>Phone:</strong> ${user.phone}</p>
            <p><strong>Website:</strong> ${user.website}</p>
            <p><strong>Company:</strong> ${user.company.name}</p>
          </div>
        `;
        } catch (error) {
          resultDiv.innerHTML = `<p class="error">Error: ${error.message}</p>`;
        }
      }
    </script>
  </body>
</html>
```

---

## 11. Tips & Best Practices

| ✅ ควรทำ                                     | ❌ อย่าทำ                      |
| -------------------------------------------- | ------------------------------ |
| ตรวจสอบ `response.ok` หรือ `response.status` | ไม่ประมวลผล error              |
| ใช้ `async/await`                            | ใช้ callback chains ยาวๆ       |
| ส่ง `Content-Type` header                    | ลืมส่ง headers                 |
| จัดการ timeout                               | รอข้อมูลตลอดไป                 |
| แสดง loading state                           | ไม่บอกผู้ใช้ว่า API กำลังทำงาน |

---

## สรุป

- **Fetch API** ใช้ขอข้อมูล HTTP ผ่าน JavaScript
- ส่งกลับ **Promise** จึงสามารถใช้ `.then()` หรือ `async/await`
- **HTTP Methods**: GET, POST, PUT, DELETE
- ต้องตรวจสอบ **response.ok** และจัดการ **errors**
- **Headers** ใช้ส่งข้อมูลเพิ่มเติม เช่น authentication tokens
