diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/exercise-tracker.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/exercise-tracker.chinese.md
new file mode 100644
index 0000000000..3123d33a74
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/exercise-tracker.chinese.md
@@ -0,0 +1,49 @@
+---
+id: 5a8b073d06fa14fcfde687aa
+title: Exercise Tracker
+localeTitle: 运动追踪器
+challengeType: 4
+isRequired: true
+---
+
+## Description
+ 0
构建一个功能类似于此的完整堆栈JavaScript应用程序: https : //fuschia-custard.glitch.me/ 。 0
在这个项目上工作将涉及您在我们的入门项目上的Glitch上编写代码。完成此项目后,您可以将公共故障网址(到应用程序的主页)复制到此屏幕进行测试!您可以选择在另一个平台上编写项目,但必须公开显示我们的测试。 0
使用此链接在Glitch上启动此项目或在GitHub上克隆此存储库 !如果您使用Glitch,请记住将项目链接保存到安全的地方!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 我可以通过将表单数据用户名发布到/ api / exercise / new-user来创建用户,并返回将是具有用户名和_id
的对象。
+ testString: ''
+ - text: 我可以通过使用与创建用户时相同的信息获取api / exercise / users来获得所有用户的数组。
+ testString: ''
+ - text: '我可以通过将表单数据userId(_id),描述,持续时间和可选日期发布到/ api / exercise / add来向任何用户添加练习。如果没有提供日期,它将使用当前日期。应用程序将返回添加了练习字段的用户对象。'
+ testString: ''
+ - text: 我可以通过使用userId(_id)参数获取/ api / exercise / log来检索任何用户的完整练习日志。应用程序将返回添加了数组日志和计数(总运动计数)的用户对象。
+ testString: ''
+ - text: '我还可以通过传递from和to或limit的可选参数来检索任何用户的部分日志。 (日期格式yyyy-mm-dd,limit = int)'
+ testString: ''
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/file-metadata-microservice.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/file-metadata-microservice.chinese.md
new file mode 100644
index 0000000000..4c9cad98d5
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/file-metadata-microservice.chinese.md
@@ -0,0 +1,43 @@
+---
+id: bd7158d8c443edefaeb5bd0f
+title: File Metadata Microservice
+localeTitle: 文件元数据微服务
+challengeType: 4
+isRequired: true
+---
+
+## Description
+ 0
构建一个功能类似于此的完整堆栈JavaScript应用程序: https : //purple-paladin.glitch.me/ 。 0
在这个项目上工作将涉及您在我们的入门项目上的Glitch上编写代码。完成此项目后,您可以将公共故障网址(到应用程序的主页)复制到此屏幕进行测试!您可以选择在另一个平台上编写项目,但必须公开显示我们的测试。 0
使用此链接在Glitch上启动此项目或在GitHub上克隆此存储库 !如果您使用Glitch,请记住将项目链接保存到安全的地方!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 我可以提交包含文件上传的FormData对象。
+ testString: ''
+ - text: “当我提交某些内容时,我将在JSON响应中收到以字节为单位的文件大小。”
+ testString: ''
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/request-header-parser-microservice.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/request-header-parser-microservice.chinese.md
new file mode 100644
index 0000000000..01319c6ad2
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/request-header-parser-microservice.chinese.md
@@ -0,0 +1,41 @@
+---
+id: bd7158d8c443edefaeb5bdff
+title: Request Header Parser Microservice
+localeTitle: 请求Header Parser Microservice
+challengeType: 4
+isRequired: true
+---
+
+## Description
+ 0
构建一个功能类似于此的完整堆栈JavaScript应用程序: https : //dandelion-roar.glitch.me/ 。 0
在这个项目上工作将涉及您在我们的入门项目上的Glitch上编写代码。完成此项目后,您可以将公共故障网址(到应用程序的主页)复制到此屏幕进行测试!您可以选择在另一个平台上编写项目,但必须公开显示我们的测试。 0
使用此链接在Glitch上启动此项目或在GitHub上克隆此存储库 !如果您使用Glitch,请记住将项目链接保存到安全的地方!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: “我可以为我的浏览器获取IP地址,语言和操作系统。”
+ testString: ''
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/timestamp-microservice.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/timestamp-microservice.chinese.md
new file mode 100644
index 0000000000..ff1d593a97
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/timestamp-microservice.chinese.md
@@ -0,0 +1,51 @@
+---
+id: bd7158d8c443edefaeb5bdef
+title: Timestamp Microservice
+localeTitle: 时间戳微服务
+challengeType: 4
+isRequired: true
+---
+
+## Description
+ 0
构建一个功能类似于此的完整堆栈JavaScript应用程序: https : //curse-arrow.glitch.me/ 。 0
在这个项目上工作将涉及您在我们的入门项目上的Glitch上编写代码。完成此项目后,您可以将公共故障网址(到应用程序的主页)复制到此屏幕进行测试!您可以选择在另一个平台上编写项目,但必须公开显示我们的测试。 0
使用此链接在Glitch上启动此项目或在GitHub上克隆此存储库 !如果您使用Glitch,请记住将项目链接保存到安全的地方!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '它应该处理一个有效的日期,并返回正确的unix时间戳'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp/2016-12-25'').then(data => { assert.equal(data.unix, 1482624000000, ''Should be a valid unix timestamp''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '它应该处理一个有效的日期,并返回正确的UTC字符串'
+ testString: 'getUserInput => $.get(getUserInput(''url'')+ ''/api/timestamp/2016-12-25'').then(data => { assert.equal(data.utc, ''Sun, 25 Dec 2016 00:00:00 GMT'', ''Should be a valid UTC date string''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '它应该处理一个有效的unix日期,并返回正确的unix时间戳'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp/1482624000000'').then(data => { assert.equal(data.unix, 1482624000000) ; }, xhr => { throw new Error(xhr.responseText); })'
+ - text: 它应返回无效日期的预期错误消息
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp/this-is-not-a-date'').then(data => { assert.equal(data.error.toLowerCase(), ''invalid date'');}, xhr => { throw new Error(xhr.responseText); })'
+ - text: '它应该处理一个空的日期参数,并以unix格式返回当前时间'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp'').then(data => { var now = Date.now(); assert.approximately(data.unix, now, 20000) ;}, xhr => { throw new Error(xhr.responseText); })'
+ - text: '它应该处理一个空日期参数,并以UTC格式返回当前时间'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp'').then(data => { var now = Date.now(); var serverTime = (new Date(data.utc)).getTime(); assert.approximately(serverTime, now, 20000) ;}, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/url-shortener-microservice.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/url-shortener-microservice.chinese.md
new file mode 100644
index 0000000000..29e8ce8f4e
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/apis-and-microservices-projects/url-shortener-microservice.chinese.md
@@ -0,0 +1,45 @@
+---
+id: bd7158d8c443edefaeb5bd0e
+title: URL Shortener Microservice
+localeTitle: URL Shortener微服务
+challengeType: 4
+isRequired: true
+---
+
+## Description
+ 0
构建一个功能类似于此的完整堆栈JavaScript应用程序: https : //thread-paper.glitch.me/ 。 0
在这个项目上工作将涉及您在我们的入门项目上的Glitch上编写代码。完成此项目后,您可以将公共故障网址(到应用程序的主页)复制到此屏幕进行测试!您可以选择在另一个平台上编写项目,但必须公开显示我们的测试。 0
使用此链接在Glitch上启动此项目或在GitHub上克隆此存储库 !如果您使用Glitch,请记住将项目链接保存到安全的地方!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 我可以传递一个URL作为参数,我将在JSON响应中收到一个缩短的URL。
+ testString: ''
+ - text: '如果我传递的网址无效,并且不遵循有效的http://www.example.com格式,则JSON响应将包含错误。'
+ testString: ''
+ - text: “当我访问缩短的网址时,它会将我重定向到我原来的链接。”
+ testString: ''
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/chain-middleware-to-create-a-time-server.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/chain-middleware-to-create-a-time-server.chinese.md
new file mode 100644
index 0000000000..1e5a9ef366
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/chain-middleware-to-create-a-time-server.chinese.md
@@ -0,0 +1,43 @@
+---
+id: 587d7fb1367417b2b2512bf4
+title: Chain Middleware to Create a Time Server
+localeTitle: 链中间件创建时间服务器
+challengeType: 2
+---
+
+## Description
+ 0
使用app.METHOD(path, middlewareFunction)
可以在特定路径上安装app.METHOD(path, middlewareFunction)
。中间件也可以在路由定义中链接。 0
查看以下示例:
+app.get('/user', function(req, res, next) {
req.user = getTheUserSync(); // Hypothetical synchronous operation
next();
}, function(req, res) {
res.send(req.user);
})
0
此方法可用于将服务器操作拆分为较小的单元。这导致了更好的应用程序结构,以及在不同位置重用代码的可能性。此方法还可用于对数据执行某些验证。在中间件堆栈的每个点,您可以阻止当前链的执行,并将控制权传递给专门用于处理错误的函数。或者您可以将控制权传递给下一个匹配的路径,以处理特殊情况。我们将在高级Express部分中看到如何。 0
在路径app.get('/now', ...)
链中间件函数和最终处理程序。在中间件功能中,您应该在req.time
键中将当前时间添加到请求对象。您可以使用new Date().toString()
。在处理程序中,使用JSON对象进行响应,采用结构{time: req.time}
。 0
提示:如果不链接中间件,测试将无法通过。如果将函数挂载到其他位置,即使输出结果正确,测试也会失败。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: / now端点应该已经安装了中间件
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/chain-middleware-time'').then(data => { assert.equal(data.stackLength, 2, ''"/now" route has no mounted middleware''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: / now端点应返回从现在起+/- 20秒的时间
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/chain-middleware-time'').then(data => { var now = new Date(); assert.isAtMost(Math.abs(new Date(data.time) - now), 20000, ''the returned time is not between +- 20 secs from now''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-data-from-post-requests.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-data-from-post-requests.chinese.md
new file mode 100644
index 0000000000..134fbfedc3
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-data-from-post-requests.chinese.md
@@ -0,0 +1,47 @@
+---
+id: 587d7fb2367417b2b2512bf8
+title: Get Data from POST Requests
+localeTitle: 从POST请求中获取数据
+challengeType: 2
+---
+
+## Description
+ 0
在路径/name
处安装POST处理程序。它和以前一样。我们在html首页中准备了一个表单。它将提交练习10(查询字符串)的相同数据。如果正确配置了body-parser,您应该在对象req.body
找到参数。看看通常的库示例:
+route: POST '/library'
urlencoded_body: userId=546&bookId=6754
req.body: {userId: '546', bookId: '6754'}
0
使用与以前相同的JSON对象进行响应: {name: 'firstname lastname'}
。使用我们在应用程序首页中提供的html表单测试您的端点是否正常工作。 0
提示:除了GET和POST之外,还有其他几种http方法。按照惯例,http动词与您要在服务器上执行的操作之间存在对应关系。传统的映射是:
+POST(有时是PUT) - 使用随请求发送的信息创建新资源,
+GET - 读取现有资源而不修改它,
+PUT或PATCH(有时是POST) - 使用数据更新资源已发送,
+DELETE =>删除资源。 0
还有一些其他方法用于协商与服务器的连接。除了GET之外,上面列出的所有其他方法都可以有一个有效载荷(即数据进入请求体)。身体解析器中间件也适用于这些方法。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '测试1:您的API端点应使用正确的名称进行响应'
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/name'', {first: ''Mick'', last: ''Jagger''}).then(data => { assert.equal(data.name, ''Mick Jagger'', ''Test 1: "POST /name" route does not behave as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '测试2:您的API端点应使用正确的名称进行响应'
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/name'', {first: ''Keith'', last: ''Richards''}).then(data => { assert.equal(data.name, ''Keith Richards'', ''Test 2: "POST /name" route does not behave as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-query-parameter-input-from-the-client.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-query-parameter-input-from-the-client.chinese.md
new file mode 100644
index 0000000000..4c94488b68
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-query-parameter-input-from-the-client.chinese.md
@@ -0,0 +1,43 @@
+---
+id: 587d7fb2367417b2b2512bf6
+title: Get Query Parameter Input from the Client
+localeTitle: 从客户端获取查询参数输入
+challengeType: 2
+---
+
+## Description
+ 0
从客户端获取输入的另一种常用方法是使用查询字符串对路径路径后的数据进行编码。查询字符串由问号(?)分隔,并包括field = value couple。每对夫妇用和号(&)隔开。 Express可以解析查询字符串中的数据,并填充对象req.query
。某些字符不能在URL中,它们必须以不同的格式编码才能发送它们。如果您使用JavaScript中的API,则可以使用特定方法对这些字符进行编码/解码。
+route_path: '/library'
actual_request_URL: '/library?userId=546&bookId=6754'
req.query: {userId: '546', bookId: '6754'}
0
构建一个以GET /name
挂载的API端点。使用结构{ name: 'firstname lastname'}
回复JSON文档。名字和姓氏参数应该在查询字符串中编码,例如?first=firstname&last=lastname
。 0
提示:在下面的练习中,我们将在相同/name
路径路径的POST请求中接收数据。如果需要,可以使用方法app.route(path).get(handler).post(handler)
。此语法允许您在同一路径路径上链接不同的动词处理程序。您可以节省一些打字,并拥有更清晰的代码。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '测试1:您的API端点应使用正确的名称进行响应'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/name?first=Mick&last=Jagger'').then(data => { assert.equal(data.name, ''Mick Jagger'', ''Test 1: "GET /name" route does not behave as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '测试2:您的APi端点应以正确的名称响应'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/name?last=Richards&first=Keith'').then(data => { assert.equal(data.name, ''Keith Richards'', ''Test 2: "GET /name" route does not behave as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-route-parameter-input-from-the-client.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-route-parameter-input-from-the-client.chinese.md
new file mode 100644
index 0000000000..9074d50fb7
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/get-route-parameter-input-from-the-client.chinese.md
@@ -0,0 +1,43 @@
+---
+id: 587d7fb2367417b2b2512bf5
+title: Get Route Parameter Input from the Client
+localeTitle: 从客户端获取路由参数输入
+challengeType: 2
+---
+
+## Description
+ 0
构建API时,我们必须允许用户与我们沟通他们希望从我们的服务中获得什么。例如,如果客户端请求有关存储在数据库中的用户的信息,他们需要一种方法让我们知道他们感兴趣的用户。实现此结果的一种可能方法是使用路由参数。路由参数是URL的命名段,由斜杠(/)分隔。每个段捕获URL的与其位置匹配的部分的值。捕获的值可以在req.params
对象中找到。
+route_path: '/user/:userId/book/:bookId'
actual_request_URL: '/user/546/book/6754'
req.params: {userId: '546', bookId: '6754'}
0
构建一个安装在路径GET /:word/echo
的回显服务器。使用结构{echo: word}
响应JSON对象。您可以在req.params.word
找到要重复的req.params.word
。您可以从浏览器的地址栏测试您的路线,访问一些匹配的路线,例如您的-app-rootpath / freecodecamp / echo
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '测试1:您的echo服务器应该正确重复单词'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/eChOtEsT/echo'').then(data => { assert.equal(data.echo, ''eChOtEsT'', ''Test 1: the echo server is not working as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '测试2:您的echo服务器应该正确重复单词'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/ech0-t3st/echo'').then(data => { assert.equal(data.echo, ''ech0-t3st'', ''Test 2: the echo server is not working as expected'') }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/implement-a-root-level-request-logger-middleware.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/implement-a-root-level-request-logger-middleware.chinese.md
new file mode 100644
index 0000000000..bde76c6bb8
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/implement-a-root-level-request-logger-middleware.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb1367417b2b2512bf3
+title: Implement a Root-Level Request Logger Middleware
+localeTitle: 实现根级请求记录器中间件
+challengeType: 2
+---
+
+## Description
+ 0
在我们介绍express.static()
中间件函数之前。现在是时候更详细地看看中间件是什么了。中间件函数是带有3个参数的函数:请求对象,响应对象和应用程序请求 - 响应周期中的下一个函数。这些函数执行一些可能对应用程序产生副作用的代码,并且通常会向请求或响应对象添加信息。当满足某些条件时,它们还可以结束发送响应的循环。如果他们没有发送响应,当他们完成时,他们开始执行堆栈中的下一个函数。触发调用第三个参数next()
。 快递文档中的更多信息。 0
查看以下示例:
+function(req, res, next) {
console.log("I'm a middleware...");
next();
}
0
假设我们在路线上安装了此功能。当请求与路由匹配时,它会显示字符串“我是中间件......”。然后它执行堆栈中的下一个函数。 0
在本练习中,我们将构建一个根级中间件。正如我们在挑战4中所见,要在根级别安装中间件功能,我们可以使用方法app.use(<mware-function>)
。在这种情况下,将对所有请求执行该功能,但您也可以设置更具体的条件。例如,如果您希望仅为POST请求执行某个函数,则可以使用app.post(<mware-function>)
。所有http动词都有类似的方法(GET,DELETE,PUT,...)。 0
构建一个简单的记录器。对于每个请求,它应该在控制台中登录一个字符串,采用以下格式: method path - ip
。示例如下: GET /json - ::ffff:127.0.0.1
。请注意, method
和path
之间有一个空格,并且破折号分隔path
和ip
被两侧的空格包围。您可以使用req.method
, req.path
和req.ip
从请求对象获取请求方法(http谓词),相对路由路径和调用者的ip。记得在完成后调用next()
,否则你的服务器将永远停留。确保打开“日志”,并查看某些请求到达时会发生什么... 0
提示:Express按照它们在代码中出现的顺序评估函数。中间件也是如此。如果您希望它适用于所有路由,则应在它们之前安装它。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 根级别记录器中间件应该是活动的
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/root-middleware-logger'').then(data => { assert.isTrue(data.passed, ''root-level logger is not working as expected''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/meet-the-node-console.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/meet-the-node-console.chinese.md
new file mode 100644
index 0000000000..f291b32ee9
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/meet-the-node-console.chinese.md
@@ -0,0 +1,39 @@
+---
+id: 587d7fb0367417b2b2512bed
+title: Meet the Node console
+localeTitle: 认识节点控制台
+challengeType: 2
+---
+
+## Description
+ 0
在开发过程中,能够检查代码中发生的情况非常重要。 Node只是一个JavaScript环境。与客户端JavaScript一样,您可以使用控制台显示有用的调试信息。在本地计算机上,您将在终端中看到控制台输出。在Glitch上,您可以打开屏幕下方的日志。您可以使用“日志”按钮切换日志面板(左上角,在应用名称下)。 0
要开始使用,只需在控制台中打印经典的“Hello World”即可。我们建议在应对这些挑战时保持日志面板处于打开状态。阅读日志,您可以了解可能发生的错误的性质。
+
+
+## Instructions
+ 0
修改myApp.js
文件以将“Hello World”记录到控制台。
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: "Hello World"
应该在控制台中
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/hello-console'').then(data => { assert.isTrue(data.passed, ''"Hello World" is not in the server console''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-an-html-file.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-an-html-file.chinese.md
new file mode 100644
index 0000000000..4697e6be79
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-an-html-file.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb0367417b2b2512bef
+title: Serve an HTML File
+localeTitle: 提供HTML文件
+challengeType: 2
+---
+
+## Description
+ 0
我们可以使用res.sendFile(path)
方法响应文件。 0
您可以将它放在app.get('/', ...)
路由处理程序中。在幕后,此方法将根据其类型设置适当的标头,以指示您的浏览器如何处理您要发送的文件。然后它将读取并发送文件。此方法需要绝对文件路径。我们建议您使用Node全局变量__dirname
来计算路径。 0
例如absolutePath = __dirname + relativePath/file.ext
。 0
要发送的文件是/views/index.html
。尝试“显示”你的应用程序,你应该看到一个很大的HTML标题(以及我们稍后将使用的表单......),没有应用任何样式。 0
注意:您可以编辑上一个挑战的解决方案,也可以创建一个新挑战。如果您创建新解决方案,请记住Express会从上到下评估路由。它执行第一个匹配的处理程序。您必须注释掉前面的解决方案,否则服务器将继续使用字符串进行响应。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 您的应用应该提供文件views / index.html
+ testString: 'getUserInput => $.get(getUserInput(''url'')).then(data => { assert.match(data, /.*<\/h1>/, ''Your app does not serve the expected HTML''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-json-on-a-specific-route.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-json-on-a-specific-route.chinese.md
new file mode 100644
index 0000000000..fefe0fb15d
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-json-on-a-specific-route.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb1367417b2b2512bf1
+title: Serve JSON on a Specific Route
+localeTitle: 在特定路线上提供JSON
+challengeType: 2
+---
+
+## Description
+ 0
虽然HTML服务器提供(您猜对了!)HTML,但API提供数据。 REST (REpresentational State Transfer)API允许以简单的方式进行数据交换,而无需客户端知道有关服务器的任何细节。客户端只需要知道资源的位置(URL),以及它想要对其执行的操作(动词)。当您获取某些信息而不修改任何信息时,将使用GET动词。目前,用于在Web上移动信息的首选数据格式是JSON。简单地说,JSON是一种将JavaScript对象表示为字符串的便捷方式,因此可以轻松传输。 0
让我们通过在路径/json
处创建一个以JSON响应的路由来创建一个简单的API。您可以像往常一样使用app.get()
方法执行此操作。在路由处理程序内部使用方法res.json()
,将对象作为参数传入。此方法关闭请求 - 响应循环,返回数据。在幕后,它将有效的JavaScript对象转换为字符串,然后设置相应的标题以告诉您的浏览器您正在提供JSON,并将数据发回。有效对象具有通常的结构{key: data}
。数据可以是数字,字符串,嵌套对象或数组。数据也可以是变量或函数调用的结果,在这种情况下,它将在转换为字符串之前进行评估。 0
将对象{"message": "Hello json"}
作为JSON格式的响应提供给对路由/json
的GET请求。然后将浏览器指向your-app-url / json,您应该在屏幕上看到该消息。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 'endpoint /json
应该服务于json对象{"message": "Hello json"}
'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/json'').then(data => { assert.equal(data.message, ''Hello json'', ''The \''/json\'' endpoint does not serve the right data''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-static-assets.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-static-assets.chinese.md
new file mode 100644
index 0000000000..09153dd358
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/serve-static-assets.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb0367417b2b2512bf0
+title: Serve Static Assets
+localeTitle: 服务静态资产
+challengeType: 2
+---
+
+## Description
+
+HTML服务器通常有一个或多个用户可以访问的目录。您可以放置应用程序所需的静态资产(样式表,脚本,图像)。在Express中,您可以使用中间件express.static(path)
来实现此功能,其中参数是包含资产的文件夹的绝对路径。如果您不知道中间件是什么,请不要担心。我们稍后会详细讨论它。基本上,中间件是拦截路由处理程序,添加某种信息的函数。需要使用app.use(path, middlewareFunction)
方法app.use(path, middlewareFunction)
。第一个路径参数是可选的。如果您没有通过它,将为所有请求执行中间件。 0
使用app.use()
为所有请求安装express.static()
中间件。 assets文件夹的绝对路径是__dirname + /public
。 0
现在,您的应用应该能够提供CSS样式表。从公共文件夹外部将显示挂载到根目录。你的头版现在应该看起来好一点!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 您的应用应该从/public
目录提供资产文件
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/style.css'').then(data => { assert.match(data, /body\s*\{[^\}]*\}/, ''Your app does not serve static assets''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/start-a-working-express-server.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/start-a-working-express-server.chinese.md
new file mode 100644
index 0000000000..715aca47a4
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/start-a-working-express-server.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb0367417b2b2512bee
+title: Start a Working Express Server
+localeTitle: 启动Working Express服务器
+challengeType: 2
+---
+
+## Description
+ 0
在myApp.js文件的前两行中,您可以看到如何轻松创建Express应用程序对象。这个对象有几种方法,我们将在这些挑战中学到很多方法。一个基本方法是app.listen(port)
。它告诉您的服务器侦听给定端口,使其处于运行状态。您可以在文件底部看到它。这是内部评论,因为出于测试原因,我们需要应用程序在后台运行。您可能想要添加的所有代码都介于这两个基本部分之间。 Glitch将端口号存储在环境变量process.env.PORT
。它的价值是3000
。 0
让我们的第一个字符串!在Express中,路由采用以下结构: app.METHOD(PATH, HANDLER)
。 METHOD是小写的http方法。 PATH是服务器上的相对路径(它可以是字符串,甚至是正则表达式)。 HANDLER是Express匹配路由时调用的功能。 0
处理程序采用表单function(req, res) {...}
,其中req是请求对象,res是响应对象。例如,处理程序
+function(req, res) {
res.send('Response String');
}
0
将提供字符串'Response String'。 0
使用app.get()
方法为字符串Hello Express提供服务,以匹配/ root路径的GET请求。通过查看日志确保您的代码正常工作,然后在浏览器中查看结果,单击Glitch UI中的“Show Live”按钮。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 您的应用应该提供字符串'Hello Express'
+ testString: 'getUserInput => $.get(getUserInput(''url'')).then(data => { assert.equal(data, ''Hello Express'', ''Your app does not serve the text "Hello Express"''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-body-parser-to-parse-post-requests.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-body-parser-to-parse-post-requests.chinese.md
new file mode 100644
index 0000000000..5a212b7b25
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-body-parser-to-parse-post-requests.chinese.md
@@ -0,0 +1,42 @@
+---
+id: 587d7fb2367417b2b2512bf7
+title: Use body-parser to Parse POST Requests
+localeTitle: 使用body-parser来解析POST请求
+challengeType: 2
+---
+
+## Description
+ 0
除了GET之外还有另一个常见的http动词,它是POST。 POST是用于使用HTML表单发送客户端数据的默认方法。在REST约定中,POST用于发送数据以在数据库中创建新项目(新用户或新博客文章)。我们在这个项目中没有数据库,但我们将学习如何处理POST请求。 0
在这些请求中,数据不会出现在URL中,它隐藏在请求正文中。这是HTML请求的一部分,也称为有效负载。由于HTML是基于文本的,即使您没有看到数据,也不意味着它们是秘密的。 HTTP POST请求的原始内容如下所示:
+POST /path/subpath HTTP/1.0
From: john@example.com
User-Agent: someBrowser/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 20
name=John+Doe&age=25
0
正如您所见,正文被编码为查询字符串。这是HTML表单使用的默认格式。使用Ajax,我们还可以使用JSON来处理具有更复杂结构的数据。还有另一种编码类型:multipart / form-data。这个用于上传二进制文件。 0
在本练习中,我们将使用urlencoded主体。 0
要解析来自POST请求的数据,您必须安装一个包:body-parser。该软件包允许您使用一系列中间件,这些中间件可以解码不同格式的数据。请参阅此处的文档。 0
在package.json中安装body-parser模块。然后在文件的顶部需要它。将其存储在名为bodyParser的变量中。
+bodyParser.urlencoded({extended: false})
返回处理url编码数据的中间件。 extended=false
是一个配置选项,告诉解析器使用经典编码。使用它时,值可以只是字符串或数组。扩展版本允许更多的数据灵活性,但它被JSON击败。将app.use()
传递给前一个方法调用返回的函数。像往常一样,必须在需要它的所有路由之前安装中间件。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 应该安装'body-parser'中间件
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/add-body-parser'').then(data => { assert.isAbove(data.mountedAt, 0, ''"body-parser" is not mounted correctly'') }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-the-.env-file.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-the-.env-file.chinese.md
new file mode 100644
index 0000000000..c4ad297ed6
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/basic-node-and-express/use-the-.env-file.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb1367417b2b2512bf2
+title: Use the .env File
+localeTitle: 使用.env文件
+challengeType: 2
+---
+
+## Description
+
+.env
文件是一个隐藏文件,用于将环境变量传递给应用程序。这个文件是秘密的,没有人可以访问它,它可以用来存储你想保密或隐藏的数据。例如,您可以存储来自外部服务或数据库URI的API密钥。您还可以使用它来存储配置选项。通过设置配置选项,您可以更改应用程序的行为,而无需重写某些代码。 0
可以从应用程序访问环境变量process.env.VAR_NAME
。 process.env
对象是一个全局Node对象,变量作为字符串传递。按照惯例,变量名都是大写的,单词用下划线分隔。 .env
是一个shell文件,因此您不需要在引号中包装名称或值。同样重要的是要注意,当您为变量赋值时,等号周围不能有空格,例如VAR_NAME=value
。通常,您将每个变量定义放在单独的行上。 0
让我们添加一个环境变量作为配置选项。将变量MESSAGE_STYLE=uppercase
存储在.env
文件中。然后告诉您在上一次质询中创建的GET /json
路由处理程序,如果process.env.MESSAGE_STYLE
等于uppercase
则将响应对象的消息转换为uppercase
。响应对象应该成为{"message": "HELLO JSON"}
。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 端点/json
的响应应根据环境变量MESSAGE_STYLE
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/use-env-vars'').then(data => { assert.isTrue(data.passed, ''The response of "/json" does not change according to MESSAGE_STYLE''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-description-to-your-package.json.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-description-to-your-package.json.chinese.md
new file mode 100644
index 0000000000..b132aaaa2a
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-description-to-your-package.json.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb3367417b2b2512bfc
+title: Add a Description to Your package.json
+localeTitle: 在package.json中添加一个描述
+challengeType: 2
+---
+
+## Description
+ 0
一个好的package.json的下一部分是description-field,其中有关于您的项目的简短但信息丰富的描述。 0
如果您有一天计划将软件包发布到npm,请记住这是一个字符串,当他们决定是否安装您的软件包时,应该将该想法卖给用户。然而,这并不是描述的唯一用例:这是总结项目工作的一种很好的方式,对于正常的Node.js项目来说,这对于帮助其他开发人员,未来的维护人员甚至是您未来的自我来理解项目同样重要很快。 0
无论您对项目的计划是什么,都建议您使用说明。让我们添加类似的东西:
+"description": "A project that does something awesome",
0
说明0
在Glitch项目中向package.json添加一个描述。 0
记住要使用双引号场名称(“)和逗号(,)分隔的字段。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: package.json应该有一个有效的“描述”键
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert(packJson.description, ''"description" is missing''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-license-to-your-package.json.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-license-to-your-package.json.chinese.md
new file mode 100644
index 0000000000..98a225183e
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-license-to-your-package.json.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb4367417b2b2512bfe
+title: Add a License to Your package.json
+localeTitle: 向package.json添加许可证
+challengeType: 2
+---
+
+## Description
+ 0
许可证字段用于通知项目用户他们可以使用它做什么。 0
开源项目的一些常见许可证包括MIT和BSD。如果您想了解更多适合您项目的许可证,http://choosealicense.com是一个很好的资源。 0
不需要许可证信息。大多数国家/地区的版权法都将授予您默认创建的所有权。但是,明确说明用户可以做什么和不做什么总是一个好习惯。 0
示例
+"license": "MIT",
0
说明0
如果您认为合适,请填写Glitch项目的package.json中的license-field。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: package.json应该有一个有效的“许可证”密钥
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert(packJson.license, ''"license" is missing''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-version-to-your-package.json.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-version-to-your-package.json.chinese.md
new file mode 100644
index 0000000000..759009aaf3
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-a-version-to-your-package.json.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb4367417b2b2512bff
+title: Add a Version to Your package.json
+localeTitle: 在package.json中添加一个版本
+challengeType: 2
+---
+
+## Description
+ 0
该版本与package.json中必填字段之一一起。该字段描述了项目的当前版本。 0
示例
+"version": "1.2",
0
说明0
在Glitch项目中向package.json添加版本。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: package.json应该有一个有效的“版本”密钥
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert(packJson.version, ''"version" is missing''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-keywords-to-your-package.json.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-keywords-to-your-package.json.chinese.md
new file mode 100644
index 0000000000..98f00f80b6
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/add-keywords-to-your-package.json.chinese.md
@@ -0,0 +1,46 @@
+---
+id: 587d7fb4367417b2b2512bfd
+title: Add Keywords to Your package.json
+localeTitle: 将关键字添加到package.json
+challengeType: 2
+---
+
+## Description
+
+keywords-field是您可以使用相关关键字描述项目的地方。 0
示例
+"keywords": [ "descriptive", "related", "words" ],
0
如您所见,此字段的结构为双引号字符串数组。 0
说明0
将一组合适的字符串添加到Glitch项目的package.json中的keywords-field。 0
其中一个关键字应该是freecodecamp。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: package.json应该有一个有效的“关键字”键
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert(packJson.keywords, ''"keywords" is missing''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“keywords”字段应为Array'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.isArray(packJson.keywords, ''"keywords" is not an array''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“关键字”应包含“freecodecamp”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.include(packJson.keywords, ''freecodecamp'', ''"keywords" does not include "freecodecamp"''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/expand-your-project-with-external-packages-from-npm.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/expand-your-project-with-external-packages-from-npm.chinese.md
new file mode 100644
index 0000000000..9c732af05c
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/expand-your-project-with-external-packages-from-npm.chinese.md
@@ -0,0 +1,47 @@
+---
+id: 587d7fb4367417b2b2512c00
+title: Expand Your Project with External Packages from npm
+localeTitle: 从npm扩展您的项目与外部包
+challengeType: 2
+---
+
+## Description
+ 0
使用包管理器的一个最大原因是它们强大的依赖关系管理。 npm无需手动确保在新计算机上设置项目时获得所有依赖项,npm会自动为您安装所有内容。但是,npm怎么能确切地知道你的项目需要什么呢?遇到package.json的依赖项部分。 0
在dependencies-section中,使用以下格式存储项目所需的包:
+"dependencies": {
+"package-name": "version",
+"express": "4.14.0"
+}
0
指令0
将软件包时刻的2.14.0版本添加到package.json的依赖项字段中
+Moment是一个方便的库,用于处理时间和日期。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '“依赖”应该包括“时刻”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''moment'', ''"dependencies" does not include "moment"''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“时刻”版本应为“2.14.0”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\^\~]?2\.14\.0/, ''Wrong version of "moment" installed. It should be 2.14.0''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/how-to-use-package.json-the-core-of-any-node.js-project-or-npm-package.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/how-to-use-package.json-the-core-of-any-node.js-project-or-npm-package.chinese.md
new file mode 100644
index 0000000000..5141f6b565
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/how-to-use-package.json-the-core-of-any-node.js-project-or-npm-package.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb3367417b2b2512bfb
+title: 'How to Use package.json, the Core of Any Node.js Project or npm Package'
+localeTitle: '如何使用package.json,任何Node.js项目的核心或npm包'
+challengeType: 2
+---
+
+## Description
+ 0
文件package.json是任何Node.js项目或npm包的中心。它存储有关项目的信息,就像HTML文档中的<head> -section描述网页内容一样。 package.json由一个JSON对象组成,其中信息存储在“key”:value-pairs中。最小的package.json中只有两个必填字段 - 名称和版本 - 但提供有关您的项目的其他信息可能对未来的用户或维护者有用,这是一个很好的做法。 0
作者字段0
如果您转到之前设置的Glitch项目并在屏幕左侧查看,您将找到文件树,您可以在其中查看项目中各种文件的概述。在文件树的后端部分,你会找到package.json - 我们将在接下来的几个挑战中改进的文件。 0
此文件中最常见的信息之一是author-field,它指定了谁是项目的创建者。它可以是字符串,也可以是具有联系人详细信息的对象。对于较大的项目,建议使用该对象,但在我们的示例中,将使用类似以下示例的简单字符串。
+"author": "Jane Doe",
0
说明0
将您的名字添加到Glitch项目的package.json中的author-field。 0
记住你正在编写JSON。 0
所有字段名称必须使用双引号(“),例如”author“ 0
所有字段必须用逗号分隔(,)
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: package.json应该有一个有效的“作者”密钥
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert(packJson.author, ''"author" is missing''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/manage-npm-dependencies-by-understanding-semantic-versioning.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/manage-npm-dependencies-by-understanding-semantic-versioning.chinese.md
new file mode 100644
index 0000000000..f2839132bf
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/manage-npm-dependencies-by-understanding-semantic-versioning.chinese.md
@@ -0,0 +1,47 @@
+---
+id: 587d7fb5367417b2b2512c01
+title: Manage npm Dependencies By Understanding Semantic Versioning
+localeTitle: 通过了解语义版本控制来管理npm依赖项
+challengeType: 2
+---
+
+## Description
+
+package.json的dependencies-section中的npm软件包的版本遵循所谓的语义版本控制(SemVer),这是软件版本控制的行业标准,旨在使管理依赖项更容易。在npm上发布的库,框架或其他工具应使用SemVer,以便清楚地传达依赖于程序包的项目在更新时可以期望的更改类型。
+SemVer在没有公共API的项目中没有意义 - 所以除非你的项目与上面的例子类似,否则使用另一种版本控制格式。 0
那么为什么你需要了解SemVer? 0
了解SemVer在开发使用外部依赖项的软件时非常有用(您几乎总是这样做)。有一天,您对这些数字的理解将使您免于意外地对项目进行重大更改而不理解为什么“昨天有效”的事情突然之间没有。 0
这是语义版本控制根据官方网站的工作方式: 0
给定版本号MAJOR.MINOR.PATCH,当您进行不兼容的API更改时,增加:
+MAJOR版本,当以向后兼容的方式添加功能时,增加
+MINOR版本,当您进行向后兼容的错误修复时,和
+PATCH版本。 0
这意味着PATCH是错误修复,MINOR添加了新功能,但它们都没有破坏之前的功能。最后,MAJOR添加了对早期版本无效的更改。 0
示例0
语义版本号:1.3.8 0
说明0
在package.json的dependencies-section中,更改时刻版本以匹配MAJOR版本2,MINOR版本10和PATCH版本2
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '“依赖”应该包括“时刻”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''moment'', ''"dependencies" does not include "moment"''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“时刻”版应该是“2.10.2”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\^\~]?2\.10\.2/, ''Wrong version of "moment". It should be 2.10.2''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/remove-a-package-from-your-dependencies.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/remove-a-package-from-your-dependencies.chinese.md
new file mode 100644
index 0000000000..1d76573908
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/remove-a-package-from-your-dependencies.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb5367417b2b2512c04
+title: Remove a Package from Your Dependencies
+localeTitle: 从您的依赖项中删除一个包
+challengeType: 2
+---
+
+## Description
+ 0
现在,您已经通过使用package.json的dependencies-section测试了一些可以管理项目依赖关系的方法。您已将外部包添加到文件中,甚至通过使用特殊字符作为代字号(〜)或插入符号(^)告诉npm您需要哪些类型的版本。 0
但是如果你想删除不再需要的外部包呢?您可能已经猜到了 - 只需从依赖项中删除相应的“key”:value对。 0
同样的方法也适用于删除package.json中的其他字段0
说明0
从依赖项中删除包时刻。 0
删除后确保您有相同数量的逗号。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '“依赖”不应该包括“时刻”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.notProperty(packJson.dependencies, ''moment'', ''"dependencies" still includes "moment"''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency.chinese.md
new file mode 100644
index 0000000000..735db258f1
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency.chinese.md
@@ -0,0 +1,43 @@
+---
+id: 587d7fb5367417b2b2512c03
+title: Use the Caret-Character to Use the Latest Minor Version of a Dependency
+localeTitle: 使用插入符号来使用最新的次要版本的依赖项
+challengeType: 2
+---
+
+## Description
+ 0
类似于我们在上一次挑战中学到的波形符(〜)允许npm为依赖项安装最新的PATCH,插入符号(^)允许npm也安装将来的更新。不同之处在于插入符号将允许MINOR更新和PATCH。 0
目前,您当前版本的时刻应为~2.10.2,允许npm安装到最新的2.10.x版本。如果我们改为使用插入符号(^)作为我们的版本前缀,则允许npm更新为任何2.xx版本。 0
示例
+"some-package-name": "^1.3.8" allows updates to any 1.xx version.
0
使用说明0
使用插入符(^)为依赖项中的时刻版本添加前缀,并允许npm将其更新为任何新的MINOR版本。 0
请注意,不应更改版本号本身。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '“依赖”应该包括“时刻”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''moment'', ''"dependencies" does not include "moment"''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“moment”版本应匹配“^ 2.x.x”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\^2\./, ''Wrong version of "moment". It should be ^2.10.2''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency.chinese.md
new file mode 100644
index 0000000000..53564db4fa
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/managing-packages-with-npm/use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency.chinese.md
@@ -0,0 +1,43 @@
+---
+id: 587d7fb5367417b2b2512c02
+title: Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency
+localeTitle: 使用Tilde-Character始终使用依赖项的最新修补程序版本
+challengeType: 2
+---
+
+## Description
+ 0
在上一次挑战中,我们告诉npm只包含特定版本的软件包。如果您需要确保项目的不同部分保持彼此兼容,那么这是一种冻结依赖关系的有用方法。但在大多数用例中,您不希望错过错误修复,因为它们通常包含重要的安全补丁,并且(希望)不会破坏这样做。 0
要允许npm依赖项更新到最新的PATCH版本,可以使用波形符(〜)为依赖项的版本添加前缀。在package.json中,我们关于npm如何升级时刻的当前规则是仅使用特定版本(2.10.2),但我们希望允许最新的2.10.x版本。 0
示例
+"some-package-name": "~1.3.8" allows updates to any 1.3.x version.
0
指令0
使用波形符(〜)为依赖项中的时刻版本添加前缀,并允许npm将其更新为任何新的PATCH版本。 0
请注意,不应更改版本号本身。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '“依赖”应该包括“时刻”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''moment'', ''"dependencies" does not include "moment"''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '“时刻”版本应匹配“~2.10.2”'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\~2\.10\.2/, ''Wrong version of "moment". It should be ~2.10.2''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md
new file mode 100644
index 0000000000..e925a9a36f
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb9367417b2b2512c12
+title: Chain Search Query Helpers to Narrow Search Results
+localeTitle: 链搜索查询帮助缩小搜索结果
+challengeType: 2
+---
+
+## Description
+ 0
如果未将回调作为Model.find()(或其他搜索方法)的最后一个参数传递,则不执行查询。您可以将查询存储在变量中以供以后使用。这种对象使您可以使用链接语法构建查询。当您最终链接方法.exec()时,将执行实际的数据库搜索。将回调传递给最后一个方法。有很多查询助手,这里我们将使用最“着名”的助手。 0
找到的人喜欢“burrito”。按名称对它们进行排序,将结果限制为两个文档,并隐藏它们的年龄。链.find(),. sort(),. limit(),。select(),然后是.exec()。将done(错误,数据)回调传递给exec()。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 链接查询助手应该成功
+ testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/query-tools'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''Pablo'', age: 26, favoriteFoods: [''burrito'', ''hot-dog'']}, {name: ''Bob'', age: 23, favoriteFoods: [''pizza'', ''nachos'']}, {name: ''Ashley'', age: 32, favoriteFoods: [''steak'', ''burrito'']}, {name: ''Mario'', age: 51, favoriteFoods: [''burrito'', ''prosciutto'']} ]) }).then(data => { assert.isArray(data, ''the response should be an Array''); assert.equal(data.length, 2, ''the data array length is not what expected''); assert.notProperty(data[0], ''age'', ''The returned first item has too many properties''); assert.equal(data[0].name, ''Ashley'', ''The returned first item name is not what expected''); assert.notProperty(data[1], ''age'', ''The returned second item has too many properties''); assert.equal(data[1].name, ''Mario'', ''The returned second item name is not what expected'');}, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md
new file mode 100644
index 0000000000..bff0e979a5
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md
@@ -0,0 +1,52 @@
+---
+id: 587d7fb6367417b2b2512c07
+title: Create a Model
+localeTitle: 创建一个模型
+challengeType: 2
+---
+
+## Description
+ 0
首先,我们需要一个Schema。每个模式都映射到MongoDB集合。它定义了该集合中文档的形状。 0
模式是模型的构建块。它们可以嵌套来创建复杂的模型,但在这种情况下,我们会保持简单。 0
模型允许您创建对象的实例,称为文档。 0
创建一个拥有此原型的人:
+- Person Prototype -
+--------------------
+name : string [required]
+age : number
+favoriteFoods : array of strings (*)
0
使用mongoose基本模式类型。如果需要,还可以添加0
个字段,使用简单的验证器,如required或unique, 0
并设置默认值。请参阅mongoose文档 。
+[C] RUD第一部分 - 创建0
注意:Glitch是一个真实的服务器,在真实服务器中,与db的交互发生在处理函数中。当某些事件发生时执行这些功能(例如某人在您的API上命中端点)。我们将在这些练习中遵循相同的方法。 done()函数是一个回调,告诉我们在完成插入,搜索,更新或删除等异步操作后我们可以继续。它遵循Node约定,应该在成功时调用done(null,data),或者在出错时调用(err)。 0
警告 - 与远程服务交互时,可能会发生错误!
+/* Example */
+var someFunc = function(done) {
+//... do something (risky) ...
+if(error) return done(error);
+done(null, result);
+};
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 从mongoose模式创建实例应该会成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/mongoose-model'', {name: ''Mike'', age: 28, favoriteFoods: [''pizza'', ''cheese'']}).then(data => { assert.equal(data.name, ''Mike'', ''"model.name" is not what expected''); assert.equal(data.age, ''28'', ''"model.age" is not what expected''); assert.isArray(data.favoriteFoods, ''"model.favoriteFoods" is not an Array''); assert.include(data.favoriteFoods, ''pizza'', ''"model.favoriteFoods" does not include the expected items''); assert.include(data.favoriteFoods, ''cheese'', ''"model.favoriteFoods" does not include the expected items''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md
new file mode 100644
index 0000000000..ab8d3c1b4a
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md
@@ -0,0 +1,45 @@
+---
+id: 587d7fb6367417b2b2512c09
+title: Create and Save a Record of a Model
+localeTitle: 创建并保存模型记录
+challengeType: 2
+---
+
+## Description
+ 0
使用之前构建的Person构造函数创建文档实例。将具有字段名称,年龄和favoriteFoods的对象传递给构造函数。它们的类型必须符合Person Schema中的类型。然后在返回的文档实例上调用方法document.save()。使用Node约定传递回调。这是一种常见模式,以下所有CRUD方法都将这样的回调函数作为最后一个参数。
+/* Example */
+// ...
+person.save(function(err, data) {
+// ...do your stuff here...
+});
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 创建和保存数据库项应该会成功
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/create-and-save-person'').then(data => { assert.isString(data.name, ''"item.name" should be a String''); assert.isNumber(data.age, ''28'', ''"item.age" should be a Number''); assert.isArray(data.favoriteFoods, ''"item.favoriteFoods" should be an Array''); assert.equal(data.__v, 0, ''The db item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md
new file mode 100644
index 0000000000..834e6be9d8
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb7367417b2b2512c0a
+title: Create Many Records with model.create()
+localeTitle: 使用model.create()创建许多记录
+challengeType: 2
+---
+
+## Description
+ 0
有时您需要创建模型的许多实例,例如,在使用初始数据为数据库播种时。 Model.create()接受一个对象数组,如[{name:'John',...},{...},...]作为第一个参数,并将它们全部保存在db中。使用函数参数arrayOfPeople使用Model.create()创建许多人。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 一次创建多个数据库项应该会成功
+ testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/create-many-people'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''John'', age: 24, favoriteFoods: [''pizza'', ''salad'']}, {name: ''Mary'', age: 21, favoriteFoods: [''onions'', ''chicken'']}])}).then(data => { assert.isArray(data, ''the response should be an array''); assert.equal(data.length, 2, ''the response does not contain the expected number of items''); assert.equal(data[0].name, ''John'', ''The first item is not correct''); assert.equal(data[0].__v, 0, ''The first item should be not previously edited''); assert.equal(data[1].name, ''Mary'', ''The second item is not correct''); assert.equal(data[1].__v, 0, ''The second item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md
new file mode 100644
index 0000000000..857aa12a6c
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb8367417b2b2512c11
+title: Delete Many Documents with model.remove()
+localeTitle: 使用model.remove()删除许多文档
+challengeType: 2
+---
+
+## Description
+
+Model.remove()用于删除与给定条件匹配的所有文档。使用Model.remove()删除名称为“Mary”的所有人员。将其传递给查询文档,其中设置了“name”字段,当然还有回调。 0
注意:Model.remove()不返回已删除的文档,而是返回包含操作结果和受影响项目数的JSON对象。不要忘记将它传递给done()回调,因为我们在测试中使用它。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 一次删除多个项目应该会成功
+ testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/remove-many-people'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''Mary'', age: 16, favoriteFoods: [''lollipop'']}, {name: ''Mary'', age: 21, favoriteFoods: [''steak'']}])}).then(data => { assert.isTrue(!!data.ok, ''The mongo stats are not what expected''); assert.equal(data.n, 2, ''The number of items affected is not what expected''); assert.equal(data.count, 0, ''the db items count is not what expected''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md
new file mode 100644
index 0000000000..c119ce472c
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb8367417b2b2512c10
+title: Delete One Document Using model.findByIdAndRemove
+localeTitle: 使用model.findByIdAndRemove删除一个文档
+challengeType: 2
+---
+
+## Description
+ 0
通过她的_id删除一个人。您应该使用findByIdAndRemove()或findOneAndRemove()方法之一。它们与之前的更新方法类似。他们将删除的文件传递给cb。像往常一样,使用函数参数personId作为搜索关键字。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 删除项目应该会成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/remove-one-person'', {name:''Jason Bourne'', age: 36, favoriteFoods:[''apples'']}).then(data => { assert.equal(data.name, ''Jason Bourne'', ''item.name is not what expected''); assert.equal(data.age, 36, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''apples''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0); assert.equal(data.count, 0, ''the db items count is not what expected''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md
new file mode 100644
index 0000000000..bf8399fdf5
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md
@@ -0,0 +1,44 @@
+---
+id: 587d7fb6367417b2b2512c06
+title: Install and Set Up Mongoose
+localeTitle: 安装和设置Mongoose
+challengeType: 2
+---
+
+## Description
+ 0
将mongodb和mongoose添加到项目的package.json中。然后需要猫鼬。将mLab数据库URI作为MONGO_URI存储在私有.env文件中。使用mongoose.connect连接到数据库( )
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: '"mongodb"依赖应该在package.json'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/file/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''mongodb''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '"mongoose"依赖应该在package.json'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/file/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''mongoose''); }, xhr => { throw new Error(xhr.responseText); })'
+ - text: '"mongoose"应该连接到数据库'
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/is-mongoose-ok'').then(data => {assert.isTrue(data.isMongooseOk, ''mongoose is not connected'')}, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md
new file mode 100644
index 0000000000..c6fbec18a1
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb8367417b2b2512c0e
+title: 'Perform Classic Updates by Running Find, Edit, then Save'
+localeTitle: '通过运行查找,编辑然后保存来执行经典更新'
+challengeType: 2
+---
+
+## Description
+ 0
在过去的好时光中,如果您想编辑文档并能够以某种方式使用它,例如在服务器响应中将其发回,则需要执行此操作。 Mongoose有一个专用的更新方法:Model.update()。它与低级mongo驱动程序绑定。它可以批量编辑符合特定条件的许多文档,但它不会发回更新的文档,只会发送“状态”消息。此外,它使模型验证变得困难,因为它只是直接调用mongo驱动程序。 0
使用参数personId作为搜索关键字,通过_id(使用上述任何方法)查找人物。将“hamburger”添加到她最喜欢的食物列表中(您可以使用Array.push())。然后 - 在find回调中 - save()更新的Person。
+[*]提示:如果你的Schema中你将favoriteFoods声明为一个数组而没有指定类型(即[String]),这可能会很棘手。在那种情况下,favorsFoods默认为Mixed type,你必须使用document.markModified('edited-field')手动将其标记为已编辑。 (http://mongoosejs.com/docs/schematypes.html - #Mixed)
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 查找 - 编辑 - 更新项目应该成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-edit-save'', {name:''Poldo'', age: 40, favoriteFoods:[''spaghetti'']}).then(data => { assert.equal(data.name, ''Poldo'', ''item.name is not what expected''); assert.equal(data.age, 40, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''spaghetti'', ''hamburger''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 1, ''The item should be previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md
new file mode 100644
index 0000000000..f3dff1feb4
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb8367417b2b2512c0f
+title: Perform New Updates on a Document Using model.findOneAndUpdate()
+localeTitle: 使用model.findOneAndUpdate()对文档执行新更新
+challengeType: 2
+---
+
+## Description
+ 0
最新版本的mongoose具有简化文档更新的方法。一些更高级的功能(即前/后挂钩,验证)与此方法的行为不同,因此Classic方法在许多情况下仍然有用。在按Id搜索时可以使用findByIdAndUpdate()。 0
按名称查找人员并将其年龄设置为20.使用函数参数personName作为搜索关键字。 0
提示:我们希望您返回更新的文档。为此,您需要将选项文档{new:true}作为findOneAndUpdate()的第三个参数传递。默认情况下,这些方法返回未修改的对象。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: findOneAndUpdate项应该成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-one-update'', {name:''Dorian Gray'', age: 35, favoriteFoods:[''unknown'']}).then(data => { assert.equal(data.name, ''Dorian Gray'', ''item.name is not what expected''); assert.equal(data.age, 20, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''unknown''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0, ''findOneAndUpdate does not increment version by design !!!''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md
new file mode 100644
index 0000000000..87ebd519ed
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb7367417b2b2512c0b
+title: Use model.find() to Search Your Database
+localeTitle: 使用model.find()搜索数据库
+challengeType: 2
+---
+
+## Description
+ 0
使用Model.find() - > [Person]查找具有给定名称的所有人0
在最简单的用法中,Model.find()接受查询文档(JSON对象)作为第一个参数,然后接受回调。它返回一个匹配数组。它支持极其广泛的搜索选项。在文档中查看它。使用函数参数personName作为搜索关键字。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 找到与标准对应的所有项目都应该成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-all-by-name'', {name: ''r@nd0mN4m3'', age: 24, favoriteFoods: [''pizza'']}).then(data => { assert.isArray(data, ''the response should be an Array''); assert.equal(data[0].name, ''r@nd0mN4m3'', ''item.name is not what expected''); assert.equal(data[0].__v, 0, ''The item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md
new file mode 100644
index 0000000000..62efc95df3
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md
@@ -0,0 +1,40 @@
+---
+id: 587d7fb7367417b2b2512c0d
+title: Use model.findById() to Search Your Database By _id
+localeTitle: 使用model.findById()按_id搜索数据库
+challengeType: 2
+---
+
+## Description
+ 0
保存文档时,mongodb会自动添加字段_id,并将其设置为唯一的字母数字键。按_id搜索是一种非常频繁的操作,因此mongoose为它提供了一种专用方法。使用Model.findById() - > Person找到具有给定_id的(仅!!)人物。使用函数参数personId作为搜索关键字。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 找到Id应该成功的项目
+ testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/find-by-id'').then(data => { assert.equal(data.name, ''test'', ''item.name is not what expected''); assert.equal(data.age, 0, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''none''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0, ''The item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md
new file mode 100644
index 0000000000..f85e862e85
--- /dev/null
+++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md
@@ -0,0 +1,41 @@
+---
+id: 587d7fb7367417b2b2512c0c
+title: Use model.findOne() to Return a Single Matching Document from Your Database
+localeTitle: 使用model.findOne()从数据库中返回单个匹配文档
+challengeType: 2
+---
+
+## Description
+
+Model.findOne()的行为类似于.find(),但它只返回一个文档(不是数组),即使有多个项目也是如此。在按声明为唯一的属性进行搜索时,它尤其有用。使用Model.findOne() - > Person,找到一个在她的收藏夹中有某种食物的人。使用函数参数food作为搜索键。
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: 找一个项应该成功
+ testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-one-by-food'', {name: ''Gary'', age: 46, favoriteFoods: [''chicken salad'']}).then(data => { assert.equal(data.name, ''Gary'', ''item.name is not what expected''); assert.deepEqual(data.favoriteFoods, [''chicken salad''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0, ''The item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })'
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+