--- id: 5a8b073d06fa14fcfde687aa title: 运动跟踪器 challengeType: 4 forumTopicId: 301505 dashedName: exercise-tracker --- # --description-- 构建一个功能类似于 的 JavaScript 全栈应用。 在开发这个项目时,我们推荐你在 [Glitch](https://glitch.com/) 上编码。编码完成之后,你可以把应用主页的链接复制到屏幕的输入框中,测试你的代码是否能通过项目需求。当然你也可以基于其他的平台来完成自己的项目,只要提供一个公开的主页便于我们测试就行。 参考示例:你可以通过 [这个链接](https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-exercisetracker/) 访问在 Glitch 上的项目,或者从 GitHub 上 clone [这个仓库的代码](https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/)。如果你使用 Glitch,请记住将项目链接保存到妥当的地方。 # --hints-- 提供独立的项目, 而不是例程 url. ```js (getUserInput) => { const url = getUserInput('url'); assert( !new RegExp('.*/fuschia-custard.glitch.me.*').test(getUserInput('url')) ); }; ``` 通过指定 `/api/exercise/new-user` 的 username 参数来创建用户, 并且返回一个具有 username 和 \_id 的对象。 ```js async (getUserInput) => { const url = getUserInput('url'); const res = await fetch(url + '/api/exercise/new-user', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=fcc_test_${Date.now()}`.substr(0, 29) }); if (res.ok) { const { _id, username } = await res.json(); assert.exists(_id); assert.exists(username); } else { throw new Error(`${res.status} ${res.statusText}`); } }; ``` 通过指定 `api/exercise/users` 的参数为创建用户时相同的信息,来获取到一个用户的数组。 ```js async (getUserInput) => { const url = getUserInput('url'); const res = await fetch(url + '/api/exercise/users'); if (res.ok) { const data = await res.json(); assert.isArray(data); } else { throw new Error(`${res.status} ${res.statusText}`); } }; ``` 通过指定 `/api/exercise/add` 的 userId、description、duration 和 date(可选)参数, 去添加一条练习记录。 当没有传入 date 的时候,默认采用当前日期。 应用程序将返回添加了练习字段的用户对象。 ```js async (getUserInput) => { const url = getUserInput('url'); const res = await fetch(url + '/api/exercise/new-user', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=fcc_test_${Date.now()}`.substr(0, 29) }); if (res.ok) { const { _id, username } = await res.json(); const expected = { username, description: 'test', duration: 60, _id, date: 'Mon Jan 01 1990' }; const addRes = await fetch(url + '/api/exercise/add', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `userId=${_id}&description=${expected.description}&duration=${expected.duration}&date=1990-01-01` }); if (addRes.ok) { const actual = await addRes.json(); assert.deepEqual(actual, expected); } else { throw new Error(`${addRes.status} ${addRes.statusText}`); } } else { throw new Error(`${res.status} ${res.statusText}`); } }; ``` 通过指定 `/api/exercise/log` 的 userId 参数,可以获取任意用户的练习日志和总的练习次数。 ```js async (getUserInput) => { const url = getUserInput('url'); const res = await fetch(url + '/api/exercise/new-user', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=fcc_test_${Date.now()}`.substr(0, 29) }); if (res.ok) { const { _id, username } = await res.json(); const expected = { username, description: 'test', duration: 60, _id, date: new Date().toDateString() }; const addRes = await fetch(url + '/api/exercise/add', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `userId=${_id}&description=${expected.description}&duration=${expected.duration}` }); if (addRes.ok) { const logRes = await fetch(url + `/api/exercise/log?userId=${_id}`); if (logRes.ok) { const { log } = await logRes.json(); assert.isArray(log); assert.equal(1, log.length); } else { throw new Error(`${logRes.status} ${logRes.statusText}`); } } else { throw new Error(`${addRes.status} ${addRes.statusText}`); } } else { throw new Error(`${res.status} ${res.statusText}`); } }; ``` 我还可以通过传递可选参数 from & to 或 limit 来检索任何用户的部分日志。(日期格式如: yyyy-mm-dd, limit = int) ```js async (getUserInput) => { const url = getUserInput('url'); const res = await fetch(url + '/api/exercise/new-user', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `username=fcc_test_${Date.now()}`.substr(0, 29) }); if (res.ok) { const { _id, username } = await res.json(); const expected = { username, description: 'test', duration: 60, _id, date: new Date().toDateString() }; const addExerciseRes = await fetch(url + '/api/exercise/add', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `userId=${_id}&description=${expected.description}&duration=${expected.duration}&date=1990-01-01` }); const addExerciseTwoRes = await fetch(url + '/api/exercise/add', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `userId=${_id}&description=${expected.description}&duration=${expected.duration}&date=1990-01-02` }); if (addExerciseRes.ok && addExerciseTwoRes.ok) { const logRes = await fetch( url + `/api/exercise/log?userId=${_id}&from=1989-12-31&to=1990-01-03` ); if (logRes.ok) { const { log } = await logRes.json(); assert.isArray(log); assert.equal(2, log.length); } else { throw new Error(`${logRes.status} ${logRes.statusText}`); } const limitRes = await fetch( url + `/api/exercise/log?userId=${_id}&limit=1` ); if (limitRes.ok) { const { log } = await limitRes.json(); assert.isArray(log); assert.equal(1, log.length); } else { throw new Error(`${limitRes.status} ${limitRes.statusText}`); } } else { throw new Error(`${res.status} ${res.statusText}`); } } else { throw new Error(`${res.status} ${res.statusText}`); } }; ``` # --solutions-- ```js /** Backend challenges don't need solutions, because they would need to be tested against a full working project. Please check our contributing guidelines to learn more. */ ```