调用 API 的页面
本课属于 Coddy Node.js 学习旅程的“REST API”单元。第 21 课,共 25 课。
页面会使用 fetch 调用你的 API。POST 请求需要三个选项:方法、标头和请求体。将 JavaScript 对象转换为 JSON 文本作为请求体,并将该文本标记为 application/json。
const response = await fetch('/api/books', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title: title}),
});
const data = await response.json();第一个 await 接收 HTTP 响应。第二个读取响应的 JSON 请求体。response.ok 会告诉你响应状态是否处于成功范围内。像 400 或 409 这样的状态不会导致 fetch promise 被拒绝;它会返回一个 ok 为 false 的响应。表单和列表代码已提供,你只需专注于发送请求并处理结果。
提供的 message 变量指向页面上的消息段落。设置它的 textContent 来显示文本,或者将其设为空字符串以清除内容:
message.textContent = data.error.message;
// 成功后清空它:
message.textContent = '';页面和 API 使用相同的来源,因此此调用不需要 CORS 权限。FormData 对表单的编码方式与 JSON 不同;请使用 JSON 文本,因为此 API 使用 express.json()。
挑战
简单你的 API 还没有页面。为它添加一个简单的页面,由同一台服务器提供,其中的表单通过 API 添加任务。
- 在
server.js中,使用express.static提供public文件夹,这样GET /就会返回public/index.html。 - 在
public/index.html中,提交事件监听器已经读取了标题。让它把新任务发送到 API:- 使用包含输入文本的
title变量。 - 使用
fetch('/api/tasks', ...)发送 POST 请求。 - 请求正文是用
JSON.stringify生成的 JSON 文本,例如{"title":"Water the plants"}。 - 请求需要在
fetch的headers选项中设置请求头'Content-Type': 'application/json',否则express.json()将无法读取请求正文。
- 使用包含输入文本的
- 如果响应正常(对于 200 到 299 之间的任何状态码,其
ok属性都为 true),就用form.reset()清空表单,清空#message,然后调用load(),让列表显示新任务。 - 否则,响应正文采用之前介绍过的错误格式,例如:在
{ "error": { "code": "conflict", "message": "A task with this title already exists" } }#message段落中显示其中的message。
检查会使用一个简单的模拟表单和真实的课内 API 来执行这个提供的页面脚本。它们会提交一个任务和一个重复任务,然后检查列表、表单和消息。也可以在编辑器旁边试试实际页面。
试试看:发送 GET /。页面会在页面视图中打开,其中显示 3 个初始任务。输入 "Water the plants" 并按 Add:输入框会清空,任务会出现在列表底部。再次输入 "Water the plants" 并按 Add:列表保持不变,表单下方会显示 "A task with this title already exists"。
亲手试试
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tasks</title>
</head>
<body>
<h1>Tasks</h1>
<ul id="list"></ul>
<form id="add">
<input name="title" placeholder="New task" required>
<button>Add</button>
</form>
<p id="message"></p>
<script>
const list = document.querySelector('#list');
const form = document.querySelector('#add');
const message = document.querySelector('#message');
async function load() {
const response = await fetch('/api/tasks?limit=50');
const page = await response.json();
list.replaceChildren(...page.items.map((task) => {
const item = document.createElement('li');
item.textContent = (task.done ? '[x] ' : '[ ] ') + task.title;
return item;
}));
}
form.addEventListener('submit', async (event) => {
event.preventDefault();
const title = form.elements.title.value;
// Send the title to POST /api/tasks as JSON. On success clear
// the form and load() again; on an error show its message.
});
load();
</script>
</body>
</html>
REST API中的所有课
自己练习: Express 在线编辑器