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创建