REST
在 REST 术语中,我们将单个数据对象(如应用中的便笺)称为resources。 每个资源都有一个唯一的地址——它的 URL。 根据 json-server 使用的一般约定,我们将能够在资源 URL, 即notes/3上定位某个便笺,其中3是资源的 id。 另一方面, notes url 指向包含所有便笺的资源集合。
通过 HTTP GET 请求从服务器获取资源。 例如,对 URLnotes/3 的 HTTP GET 请求将返回 id 为3的便笺。 对notes URL 的 HTTP GET 请求将返回所有便笺的列表。
根据 json 服务器遵守的 REST 约定,通过向notes URL 发出 HTTP POST 请求来创建、存储新的便笺。 新便笺资源的数据在请求的body 中发送。
Json-server 要求以 JSON 格式发送所有数据。 实际上,这意味着数据必须是格式正确的字符串,并且请求必须包含值为application/json 的Content-Type 请求头。
发送数据到服务器
修改Notes项目中的addNote函数
addNote = event => {event.preventDefault()const noteObject = {content: newNote,date: new Date(),important: Math.random() > 0.5,}axios.post('http://localhost:3001/notes', noteObject).then(response => {setNotes(notes.concat(response.data))setNewNote('')})}
Changing the Importance of Notes
存储在 json-server 后端中的各个便笺可以通过对便笺的唯一 URL 发出 HTTP 请求,以两种不同的方式进行修改。 我们可以用 HTTP PUT 请求替换 整个便笺,或者只用 HTTP PATCH 请求更改便笺的一些属性。
const toggleImportanceOf = (id) => {const url = `http://localhost:3001/notes/${id}`const note = notes.find(n => n.id === id)const changedNote = { ...note, important: !note.important }axios.put(url, changedNote).then(response => {setNotes(notes.map(note => note.id !== id ? note : response.data))})}
- 第一行根据每个便笺资源的 id 定义其唯一的 url
- Array.find()返回数组中第一个符合条件的元素
- changedNote只是浅拷贝
Extracting communication with the backend into a separate module
将与后端的通信提取到单独的模块中
Single-responsibility principle 单一职责原则
创建一个src/services目录,并添加一个名为notes.js 的文件:
import axios from 'axios'const baseUrl = 'http://localhost:3001/notes'const getAll = () => {return axios.get(baseUrl)}const create = newObject => {return axios.post(baseUrl, newObject)}const update = (id, newObject) => {return axios.put(`${baseUrl}/${id}`, newObject)}const noteService = {getAll,create,update}export default noteService
在App.js中导入并使用
import noteService from './services/notes'-- snip--noteService.getAll().then(response => {setNotes(response.data)})-- snip --
如果我们只获得响应数据,而不是整个 HTTP 响应,可以做如下修改
因为.then返回的仍然是一个promise
import axios from 'axios'const baseUrl = 'http://localhost:3001/notes'const getAll = () => {const request = axios.get(baseUrl)return request.then(response => response.data)}const create = newObject => {const request = axios.post(baseUrl, newObject)return request.then(response => response.data)}const update = (id, newObject) => {const request = axios.put(`${baseUrl}/${id}`, newObject)return request.then(response => response.data)}const noteService = {getAll,create,update}export default noteService
在App.js中的使用则改为
-- snip --noteService.getAll().then(initialNotes => {setNotes(initialNotes)})
Cleaner syntax for defining object literals
用于定义对象字面量的更清晰的语法
上文中
export default { getAll, create, update }
其实是下列的简写, 这是ES6新语法
export default {getAll: getAll,create: create,update: update}
Promises and Errors

如果请求修改服务器中不存在的note,则会报错
当 HTTP 请求失败时,相关的promise是rejected
为被拒绝的promise添加处理程序的更常见的方法是使用catch方法
noteService.update(id, changedNote).then(returnedNote => {setNotes(notes.map(note => note.id !== id ? note : returnedNote))}).catch(error => {alert(`the note '${note.content}' was already deleted from server`)setNotes(notes.filter(n => n.id !== id))})
Exercises 2.15.-2.18.
phonebook项目实现删除人员
const handleDelete = (item) => {if (window.confirm(`Delete ${item.name}?`)) {personService.deletePerson(item.id).then(() => {setPersons(persons.filter(p => p.id !== item.id))}).catch(error => console.log(error))}}
- window.confirm弹出窗口确认是否删除
Array.filter方法更新删除后的数据
const deletePerson = (id) => {const request = axios.delete(`${baseUrl}/${id}`)return request.then(response => response.data)}
axios发送delete请求删除对应id
const handleSubmit = (event) => {event.preventDefault()const names = persons.map(item => item.name)const newObject = {name: newName,number: newNumber}if (names.indexOf(newName) >= 0) {if (window.confirm(`${newName} is already added to phonebook, replace the old number with a new one?`)) {const person = persons.find(item => item.name === newName)personService.update(person.id, newObject).then(response => {setPersons(persons.map(item => item.name !== newName ? item : response))})}} else {personService.create(newObject).then(response => {setPersons(persons.concat(response))setFilterFlag(false)})}}
const update = (id, newObject) => {const request = axios.put(`${baseUrl}/${id}`, newObject)return request.then(response => response.data)}
存在则axios.put更新,不存在则axios.post创建
