Feat: add new Markdown parser (#39800)

and change all the challenges to new `md` format.
This commit is contained in:
Oliver Eyton-Williams
2020-11-27 19:02:05 +01:00
committed by GitHub
parent a07f84c8ec
commit 0bd52f8bd1
2580 changed files with 113436 additions and 111979 deletions

View File

@@ -5,253 +5,247 @@ challengeType: 4
forumTopicId: 301505
---
## Description
<section id='description'>
Build a full stack JavaScript app that is functionally similar to this: <a href='https://exercise-tracker.freecodecamp.rocks/' target='_blank'>https://exercise-tracker.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
# --description--
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/' target='_blank'>this GitHub repo</a> and complete your project locally.
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-exercisetracker' target='_blank'>our repl.it starter project</a> to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
Build a full stack JavaScript app that is functionally similar to this: <https://exercise-tracker.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-exercisetracker) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
</section>
## Instructions
<section id='instructions'>
# --hints--
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: You should provide your own project, not the example URL.
testString: |
getUserInput => {
const url = getUserInput('url');
assert(!/.*\/exercise-tracker\.freecodecamp\.rocks/.test(getUserInput('url')));
}
- text: You can `POST` to `/api/exercise/new-user` with form data `username` to create a new user. The returned response will be an object with `username` and `_id` properties.
testString: "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}`);
}
}
"
- text: You can make a `GET` request to `api/exercise/users` to get an array of all users. Each element in the array is an object containing a user's `username` and `_id`.
testString: "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);
assert.isString(data[0].username);
assert.isString(data[0]._id);
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
}
"
- text: 'You can `POST` to `/api/exercise/add` with form data `userId=_id`, `description`, `duration`, and optionally `date`. If no date is supplied, the current date will be used. The response returned will be the user object with the exercise fields added.'
testString: "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}`);
}
}
"
- text: You can make a `GET` request to `/api/exercise/log` with a parameter of `userId=_id` to retrieve a full exercise log of any user. The returned response will be the user object with a `log` array of all the exercises added. Each log item has the `description`, `duration`, and `date` properties.
testString: "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}`);
}
}
"
- text: "A request to a user's log (`/api/exercise/log`) returns an object with a `count` property representing the number of exercises returned."
testString: "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 { count } = await logRes.json();
assert(count);
} else {
throw new Error(`${logRes.status} ${logRes.statusText}`);
}
} else {
throw new Error(`${addRes.status} ${addRes.statusText}`);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
}
"
- text: 'You can add `from`, `to` and `limit` parameters to a `/api/exercise/log` request to retrieve part of the log of any user. `from` and `to` are dates in `yyyy-mm-dd` format. `limit` is an integer of how many logs to send back.'
testString: "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}`);
}
}
"
You should provide your own project, not the example URL.
```js
(getUserInput) => {
const url = getUserInput('url');
assert(
!/.*\/exercise-tracker\.freecodecamp\.rocks/.test(getUserInput('url'))
);
};
```
</section>
You can `POST` to `/api/exercise/new-user` with form data `username` to create a new user. The returned response will be an object with `username` and `_id` properties.
## Challenge Seed
<section id='challengeSeed'>
```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}`);
}
};
```
</section>
You can make a `GET` request to `api/exercise/users` to get an array of all users. Each element in the array is an object containing a user's `username` and `_id`.
## Solution
<section id='solution'>
```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);
assert.isString(data[0].username);
assert.isString(data[0]._id);
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
You can `POST` to `/api/exercise/add` with form data `userId=_id`, `description`, `duration`, and optionally `date`. If no date is supplied, the current date will be used. The response returned will be the user object with the exercise fields added.
```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}`);
}
};
```
You can make a `GET` request to `/api/exercise/log` with a parameter of `userId=_id` to retrieve a full exercise log of any user. The returned response will be the user object with a `log` array of all the exercises added. Each log item has the `description`, `duration`, and `date` properties.
```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}`);
}
};
```
A request to a user's log (`/api/exercise/log`) returns an object with a `count` property representing the number of exercises returned.
```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 { count } = await logRes.json();
assert(count);
} else {
throw new Error(`${logRes.status} ${logRes.statusText}`);
}
} else {
throw new Error(`${addRes.status} ${addRes.statusText}`);
}
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
You can add `from`, `to` and `limit` parameters to a `/api/exercise/log` request to retrieve part of the log of any user. `from` and `to` are dates in `yyyy-mm-dd` format. `limit` is an integer of how many logs to send back.
```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}`);
}
};
```
# --seed--
# --solutions--
```js
/**
@@ -260,5 +254,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,78 +5,80 @@ challengeType: 4
forumTopicId: 301506
---
## Description
# --description--
<section id='description'>
Build a full stack JavaScript app that is functionally similar to this: <a href='https://file-metadata-microservice.freecodecamp.rocks/' target='_blank'>https://file-metadata-microservice.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
Build a full stack JavaScript app that is functionally similar to this: <https://file-metadata-microservice.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-filemetadata/' target='_blank'>this GitHub repo</a> and complete your project locally.
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-filemetadata' target='_blank'>our repl.it starter project</a> to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-filemetadata/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-filemetadata) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your projects source code in the `GitHub Link` field.
</section>
## Instructions
<section id='instructions'>
# --instructions--
**HINT:** You can use the `multer` npm package to handle file uploading.
</section>
## Tests
# --hints--
<section id='tests'>
```yml
tests:
- text: You should provide your own project, not the example URL.
testString: |
getUserInput => {
assert(!/.*\/file-metadata-microservice\.freecodecamp\.rocks/.test(getUserInput('url')));
}
- text: You can submit a form that includes a file upload.
testString: "async getUserInput => {
const site = await fetch(getUserInput('url'));
const data = await site.text();
const doc = new DOMParser().parseFromString(data, 'text/html');
assert(doc.querySelector('input[type=\"file\"]'));
}"
- text: The form file input field has the `name` attribute set to `upfile`.
testString: "async getUserInput => {
const site = await fetch(getUserInput('url'));
const data = await site.text();
const doc = new DOMParser().parseFromString(data, 'text/html');
assert(doc.querySelector('input[name=\"upfile\"]'));
}"
- text: When you submit a file, you receive the file `name`, `type`, and `size` in bytes within the JSON response.
testString: "async getUserInput => {
const formData = new FormData();
const fileData = await fetch('https://cdn.freecodecamp.org/weather-icons/01d.png');
const file = await fileData.blob();
formData.append('upfile', file, 'icon');
const data = await fetch(getUserInput('url') + '/api/fileanalyse', {
method: 'POST', body: formData
});
const parsed = await data.json();
assert.property(parsed, 'size');
assert.equal(parsed.name, 'icon');
assert.equal(parsed.type, 'image/png');
}"
You should provide your own project, not the example URL.
```js
(getUserInput) => {
assert(
!/.*\/file-metadata-microservice\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
</section>
You can submit a form that includes a file upload.
## Challenge Seed
```js
async (getUserInput) => {
const site = await fetch(getUserInput('url'));
const data = await site.text();
const doc = new DOMParser().parseFromString(data, 'text/html');
assert(doc.querySelector('input[type="file"]'));
};
```
<section id='challengeSeed'>
The form file input field has the `name` attribute set to `upfile`.
</section>
```js
async (getUserInput) => {
const site = await fetch(getUserInput('url'));
const data = await site.text();
const doc = new DOMParser().parseFromString(data, 'text/html');
assert(doc.querySelector('input[name="upfile"]'));
};
```
## Solution
When you submit a file, you receive the file `name`, `type`, and `size` in bytes within the JSON response.
<section id='solution'>
```js
async (getUserInput) => {
const formData = new FormData();
const fileData = await fetch(
'https://cdn.freecodecamp.org/weather-icons/01d.png'
);
const file = await fileData.blob();
formData.append('upfile', file, 'icon');
const data = await fetch(getUserInput('url') + '/api/fileanalyse', {
method: 'POST',
body: formData
});
const parsed = await data.json();
assert.property(parsed, 'size');
assert.equal(parsed.name, 'icon');
assert.equal(parsed.type, 'image/png');
};
```
# --seed--
# --solutions--
```js
/**
@@ -85,5 +87,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,50 +5,69 @@ challengeType: 4
forumTopicId: 301507
---
## Description
<section id='description'>
Build a full stack JavaScript app that is functionally similar to this: <a href='https://request-header-parser-microservice.freecodecamp.rocks/' target='_blank'>https://request-header-parser-microservice.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
# --description--
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-headerparser/' target='_blank'>this GitHub repo</a> and complete your project locally.
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-headerparser' target='_blank'>our repl.it starter project</a> to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
Build a full stack JavaScript app that is functionally similar to this: <https://request-header-parser-microservice.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-headerparser/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-headerparser) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
</section>
## Instructions
<section id='instructions'>
# --hints--
</section>
You should provide your own project, not the example URL.
## Tests
<section id='tests'>
```yml
tests:
- text: You should provide your own project, not the example URL.
testString: |
getUserInput => {
assert(!/.*\/request-header-parser-microservice\.freecodecamp\.rocks/.test(getUserInput('url')));
}
- text: 'A request to `/api/whoami` should return a JSON object with your IP address in the <code>ipaddress</code> key.'
testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/whoami'').then(data => assert(data.ipaddress && data.ipaddress.length > 0), xhr => { throw new Error(xhr.responseText)})'
- text: 'A request to `/api/whoami` should return a JSON object with your preferred language in the <code>language</code> key.'
testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/whoami'').then(data => assert(data.language && data.language.length > 0), xhr => { throw new Error(xhr.responseText)})'
- text: 'A request to `/api/whoami` should return a JSON object with your software in the <code>software</code> key.'
testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/whoami'').then(data => assert(data.software && data.software.length > 0), xhr => { throw new Error(xhr.responseText)})'
```js
(getUserInput) => {
assert(
!/.*\/request-header-parser-microservice\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
</section>
A request to `/api/whoami` should return a JSON object with your IP address in the `ipaddress` key.
## Challenge Seed
<section id='challengeSeed'>
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/whoami').then(
(data) => assert(data.ipaddress && data.ipaddress.length > 0),
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
</section>
A request to `/api/whoami` should return a JSON object with your preferred language in the `language` key.
## Solution
<section id='solution'>
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/whoami').then(
(data) => assert(data.language && data.language.length > 0),
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
A request to `/api/whoami` should return a JSON object with your software in the `software` key.
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/whoami').then(
(data) => assert(data.software && data.software.length > 0),
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
# --seed--
# --solutions--
```js
/**
@@ -57,5 +76,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,58 +5,146 @@ challengeType: 4
forumTopicId: 301508
---
## Description
<section id='description'>
Build a full stack JavaScript app that is functionally similar to this: <a href='https://timestamp-microservice.freecodecamp.rocks/' target='_blank'>https://timestamp-microservice.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
# --description--
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-timestamp/' target='_blank'>this GitHub repo</a> and complete your project locally.
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-timestamp' target='_blank'>our repl.it starter project</a> to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
Build a full stack JavaScript app that is functionally similar to this: <https://timestamp-microservice.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-timestamp/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-timestamp) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your projects source code in the `GitHub Link` field.
</section>
## Instructions
<section id='instructions'>
# --hints--
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: You should provide your own project, not the example URL.
testString: |
getUserInput => {
assert(!/.*\/timestamp-microservice\.freecodecamp\.rocks/.test(getUserInput('url')));
}
- text: 'A request to `/api/timestamp/:date?` with a valid date should return a JSON object with a `unix` key that is a Unix timestamp of the input date in milliseconds'
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: 'A request to `/api/timestamp/:date?` with a valid date should return a JSON object with a `utc` key that is a string of the input date in the format: `Thu, 01 Jan 1970 00:00:00 GMT`'
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: 'A request to `/api/timestamp/1451001600000` should return `{ unix: 1451001600000, utc: "Fri, 25 Dec 2015 00:00:00 GMT" }` '
testString: 'getUserInput => $.get(getUserInput(''url'') + ''/api/timestamp/1451001600000'').then(data => { assert(data.unix === 1451001600000 && data.utc === "Fri, 25 Dec 2015 00:00:00 GMT"); }, xhr => { throw new Error(xhr.responseText); })'
- text: 'Your project can handle dates that can be successfully parsed by `new Date(date_string)`'
testString: 'getUserInput => $.get(getUserInput(''url'')+ ''/api/timestamp/05 October 2011'').then(data => { assert(data.unix === 1317772800000 && data.utc === "Wed, 05 Oct 2011 00:00:00 GMT" ) }, xhr => { throw new Error(xhr.responseText); })'
- text: 'If the input date string is invalid, the api returns an object having the structure `{ error : "Invalid Date" }`'
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: 'An empty date parameter should return the current time in a JSON object with a `unix` key'
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: 'An empty date parameter should return the current time in a JSON object with a `utc` key'
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); })'
You should provide your own project, not the example URL.
```js
(getUserInput) => {
assert(
!/.*\/timestamp-microservice\.freecodecamp\.rocks/.test(getUserInput('url'))
);
};
```
</section>
A request to `/api/timestamp/:date?` with a valid date should return a JSON object with a `unix` key that is a Unix timestamp of the input date in milliseconds
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
A request to `/api/timestamp/:date?` with a valid date should return a JSON object with a `utc` key that is a string of the input date in the format: `Thu, 01 Jan 1970 00:00:00 GMT`
## Solution
<section id='solution'>
```js
(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);
}
);
```
A request to `/api/timestamp/1451001600000` should return `{ unix: 1451001600000, utc: "Fri, 25 Dec 2015 00:00:00 GMT" }`
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/timestamp/1451001600000').then(
(data) => {
assert(
data.unix === 1451001600000 &&
data.utc === 'Fri, 25 Dec 2015 00:00:00 GMT'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
Your project can handle dates that can be successfully parsed by `new Date(date_string)`
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/timestamp/05 October 2011').then(
(data) => {
assert(
data.unix === 1317772800000 &&
data.utc === 'Wed, 05 Oct 2011 00:00:00 GMT'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
If the input date string is invalid, the api returns an object having the structure `{ error : "Invalid Date" }`
```js
(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);
}
);
```
An empty date parameter should return the current time in a JSON object with a `unix` key
```js
(getUserInput) =>
$.get(getUserInput('url') + '/api/timestamp').then(
(data) => {
var now = Date.now();
assert.approximately(data.unix, now, 20000);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
An empty date parameter should return the current time in a JSON object with a `utc` key
```js
(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);
}
);
```
# --seed--
# --solutions--
```js
/**
@@ -65,5 +153,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,121 +5,117 @@ challengeType: 4
forumTopicId: 301509
---
## Description
# --description--
<section id='description'>
Build a full stack JavaScript app that is functionally similar to this: <a href='https://url-shortener-microservice.freecodecamp.rocks/' target='_blank'>https://url-shortener-microservice.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
Build a full stack JavaScript app that is functionally similar to this: <https://url-shortener-microservice.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-urlshortener/' target='_blank'>this GitHub repo</a> and complete your project locally.
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-urlshortener' target='_blank'>our repl.it starter project</a> to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-urlshortener/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-urlshortener) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your projects source code in the `GitHub Link` field.
</section>
## Instructions
<section id='instructions'>
# --instructions--
**HINT:** Do not forget to use a body parsing middleware to handle the POST requests. Also, you can use the function `dns.lookup(host, cb)` from the `dns` core module to verify a submitted URL.
</section>
# --hints--
## Tests
You should provide your own project, not the example URL.
<section id='tests'>
```yml
tests:
- text: You should provide your own project, not the example URL.
testString: |
getUserInput => {
assert(!/.*\/url-shortener-microservice\.freecodecamp\.rocks/.test(getUserInput('url')));
}
- text: "You can POST a URL to `/api/shorturl/new` and get a JSON response with `original_url` and `short_url` properties. Here's an example: `{ original_url : 'https://freeCodeCamp.org', short_url : 1}`"
testString: "async getUserInput => {
const url = getUserInput('url');
const urlVariable = Date.now();
const res = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
});
if (res.ok) {
const { short_url, original_url } = await res.json();
assert.isNotNull(short_url);
assert.match(original_url, new RegExp(`https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`));
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
}
"
- text: When you visit `/api/shorturl/<short_url>`, you will be redirected to the original URL.
testString: "async getUserInput => {
const url = getUserInput('url');
const urlVariable = Date.now();
let shortenedUrlVariable;
const postResponse = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
});
if (postResponse.ok) {
const { short_url } = await postResponse.json();
shortenedUrlVariable = short_url;
} else {
throw new Error(`${postResponse.status} ${postResponse.statusText}`);
}
const getResponse = await fetch(url + '/api/shorturl/' + shortenedUrlVariable);
if (getResponse) {
const { redirected, url } = getResponse;
assert.isTrue(redirected);
assert.strictEqual(url, `https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`);
} else {
throw new Error(`${getResponse.status} ${getResponse.statusText}`);
}
}
"
- text: "If you pass an invalid URL that doesn't follow the valid `http://www.example.com` format, the JSON response will contain `{ error: 'invalid url' }`"
testString: "async getUserInput => {
const url = getUserInput('url');
const res = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=ftp:/john-doe.org`
});
if (res.ok) {
const { error } = await res.json();
assert.isNotNull(error);
assert.strictEqual(error.toLowerCase(), 'invalid url');
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
}
"
```js
(getUserInput) => {
assert(
!/.*\/url-shortener-microservice\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
</section>
You can POST a URL to `/api/shorturl/new` and get a JSON response with `original_url` and `short_url` properties. Here's an example: `{ original_url : 'https://freeCodeCamp.org', short_url : 1}`
## Challenge Seed
```js
async (getUserInput) => {
const url = getUserInput('url');
const urlVariable = Date.now();
const res = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
});
if (res.ok) {
const { short_url, original_url } = await res.json();
assert.isNotNull(short_url);
assert.match(
original_url,
new RegExp(
`https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
)
);
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
<section id='challengeSeed'>
When you visit `/api/shorturl/<short_url>`, you will be redirected to the original URL.
</section>
```js
async (getUserInput) => {
const url = getUserInput('url');
const urlVariable = Date.now();
let shortenedUrlVariable;
const postResponse = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
});
if (postResponse.ok) {
const { short_url } = await postResponse.json();
shortenedUrlVariable = short_url;
} else {
throw new Error(`${postResponse.status} ${postResponse.statusText}`);
}
const getResponse = await fetch(
url + '/api/shorturl/' + shortenedUrlVariable
);
if (getResponse) {
const { redirected, url } = getResponse;
assert.isTrue(redirected);
assert.strictEqual(
url,
`https://timestamp-microservice.freecodecamp.rocks/api/timestamp/${urlVariable}`
);
} else {
throw new Error(`${getResponse.status} ${getResponse.statusText}`);
}
};
```
## Solution
If you pass an invalid URL that doesn't follow the valid `http://www.example.com` format, the JSON response will contain `{ error: 'invalid url' }`
<section id='solution'>
```js
async (getUserInput) => {
const url = getUserInput('url');
const res = await fetch(url + '/api/shorturl/new/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `url=ftp:/john-doe.org`
});
if (res.ok) {
const { error } = await res.json();
assert.isNotNull(error);
assert.strictEqual(error.toLowerCase(), 'invalid url');
} else {
throw new Error(`${res.status} ${res.statusText}`);
}
};
```
# --seed--
# --solutions--
```js
/**
@@ -128,5 +124,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,10 @@ challengeType: 2
forumTopicId: 301510
---
## Description
<section id='description'>
Middleware can be mounted at a specific route using <code>app.METHOD(path, middlewareFunction)</code>. Middleware can also be chained inside route definition.
# --description--
Middleware can be mounted at a specific route using `app.METHOD(path, middlewareFunction)`. Middleware can also be chained inside route definition.
Look at the following example:
```js
@@ -21,35 +22,54 @@ app.get('/user', function(req, res, next) {
This approach is useful to split the server operations into smaller units. That leads to a better app structure, and the possibility to reuse code in different places. This approach can also be used to perform some validation on the data. At each point of the middleware stack you can block the execution of the current chain and pass control to functions specifically designed to handle errors. Or you can pass control to the next matching route, to handle special cases. We will see how in the advanced Express section.
</section>
# --instructions--
## Instructions
<section id='instructions'>
In the route <code>app.get('/now', ...)</code> chain a middleware function and the final handler. In the middleware function you should add the current time to the request object in the <code>req.time</code> key. You can use <code>new Date().toString()</code>. In the handler, respond with a JSON object, taking the structure <code>{time: req.time}</code>.
<strong>Note:</strong> The test will not pass if you dont chain the middleware. If you mount the function somewhere else, the test will fail, even if the output result is correct.
</section>
In the route `app.get('/now', ...)` chain a middleware function and the final handler. In the middleware function you should add the current time to the request object in the `req.time` key. You can use `new Date().toString()`. In the handler, respond with a JSON object, taking the structure `{time: req.time}`.
## Tests
<section id='tests'>
**Note:** The test will not pass if you dont chain the middleware. If you mount the function somewhere else, the test will fail, even if the output result is correct.
```yml
tests:
- text: The /now endpoint should have mounted middleware
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: The /now endpoint should return a time that is +/- 20 secs from now
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); })'
# --hints--
The /now endpoint should have mounted middleware
```js
(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);
}
);
```
</section>
The /now endpoint should return a time that is +/- 20 secs from now
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -58,5 +78,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,45 +5,70 @@ challengeType: 2
forumTopicId: 301511
---
## Description
<section id='description'>
Mount a POST handler at the path <code>/name</code>. Its the same path as before. We have prepared a form in the html frontpage. It will submit the same data of exercise 10 (Query string). If the body-parser is configured correctly, you should find the parameters in the object <code>req.body</code>. Have a look at the usual library example:
<blockquote>route: POST '/library'<br>urlencoded_body: userId=546&bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>
Respond with the same JSON object as before: <code>{name: 'firstname lastname'}</code>. Test if your endpoint works using the html form we provided in the app frontpage.
# --description--
Mount a POST handler at the path `/name`. Its the same path as before. We have prepared a form in the html frontpage. It will submit the same data of exercise 10 (Query string). If the body-parser is configured correctly, you should find the parameters in the object `req.body`. Have a look at the usual library example:
<blockquote>route: POST '/library'<br>urlencoded_body: userId=546&#x26;bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>
Respond with the same JSON object as before: `{name: 'firstname lastname'}`. Test if your endpoint works using the html form we provided in the app frontpage.
Tip: There are several other http methods other than GET and POST. And by convention there is a correspondence between the http verb, and the operation you are going to execute on the server. The conventional mapping is:
POST (sometimes PUT) - Create a new resource using the information sent with the request,
GET - Read an existing resource without modifying it,
PUT or PATCH (sometimes POST) - Update a resource using the data sent,
DELETE => Delete a resource.
There are also a couple of other methods which are used to negotiate a connection with the server. Except from GET, all the other methods listed above can have a payload (i.e. the data into the request body). The body-parser middleware works with these methods as well.
</section>
## Instructions
<section id='instructions'>
# --hints--
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: 'Test 1 : Your API endpoint should respond with the correct name'
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: 'Test 2 : Your API endpoint should respond with the correct name'
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); })'
Test 1 : Your API endpoint should respond with the correct name
```js
(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);
}
);
```
</section>
Test 2 : Your API endpoint should respond with the correct name
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -52,5 +77,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,39 +5,59 @@ challengeType: 2
forumTopicId: 301512
---
## Description
<section id='description'>
Another common way to get input from the client is by encoding the data after the route path, using a query string. The query string is delimited by a question mark (?), and includes field=value couples. Each couple is separated by an ampersand (&). Express can parse the data from the query string, and populate the object <code>req.query</code>. Some characters, like the percent (%), cannot be in URLs and have to be encoded in a different format before you can send them. If you use the API from JavaScript, you can use specific methods to encode/decode these characters.
<blockquote>route_path: '/library'<br>actual_request_URL: '/library?userId=546&bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>
</section>
# --description--
## Instructions
<section id='instructions'>
Build an API endpoint, mounted at <code>GET /name</code>. Respond with a JSON document, taking the structure <code>{ name: 'firstname lastname'}</code>. The first and last name parameters should be encoded in a query string e.g. <code>?first=firstname&last=lastname</code>.
<strong>Note:</strong> In the following exercise you are going to receive data from a POST request, at the same <code>/name</code> route path. If you want, you can use the method <code>app.route(path).get(handler).post(handler)</code>. This syntax allows you to chain different verb handlers on the same path route. You can save a bit of typing, and have cleaner code.
</section>
Another common way to get input from the client is by encoding the data after the route path, using a query string. The query string is delimited by a question mark (?), and includes field=value couples. Each couple is separated by an ampersand (&). Express can parse the data from the query string, and populate the object `req.query`. Some characters, like the percent (%), cannot be in URLs and have to be encoded in a different format before you can send them. If you use the API from JavaScript, you can use specific methods to encode/decode these characters.
## Tests
<section id='tests'>
<blockquote>route_path: '/library'<br>actual_request_URL: '/library?userId=546&#x26;bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>
```yml
tests:
- text: 'Test 1 : Your API endpoint should respond with the correct name'
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: 'Test 2 : Your API endpoint should respond with the correct name'
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); })'
# --instructions--
Build an API endpoint, mounted at `GET /name`. Respond with a JSON document, taking the structure `{ name: 'firstname lastname'}`. The first and last name parameters should be encoded in a query string e.g. `?first=firstname&last=lastname`.
**Note:** In the following exercise you are going to receive data from a POST request, at the same `/name` route path. If you want, you can use the method `app.route(path).get(handler).post(handler)`. This syntax allows you to chain different verb handlers on the same path route. You can save a bit of typing, and have cleaner code.
# --hints--
Test 1 : Your API endpoint should respond with the correct name
```js
(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);
}
);
```
</section>
Test 2 : Your API endpoint should respond with the correct name
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -46,5 +66,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,38 +5,57 @@ challengeType: 2
forumTopicId: 301513
---
## Description
<section id='description'>
When building an API, we have to allow users to communicate to us what they want to get from our service. For example, if the client is requesting information about a user stored in the database, they need a way to let us know which user they're interested in. One possible way to achieve this result is by using route parameters. Route parameters are named segments of the URL, delimited by slashes (/). Each segment captures the value of the part of the URL which matches its position. The captured values can be found in the <code>req.params</code> object.
# --description--
When building an API, we have to allow users to communicate to us what they want to get from our service. For example, if the client is requesting information about a user stored in the database, they need a way to let us know which user they're interested in. One possible way to achieve this result is by using route parameters. Route parameters are named segments of the URL, delimited by slashes (/). Each segment captures the value of the part of the URL which matches its position. The captured values can be found in the `req.params` object.
<blockquote>route_path: '/user/:userId/book/:bookId'<br>actual_request_URL: '/user/546/book/6754' <br>req.params: {userId: '546', bookId: '6754'}</blockquote>
</section>
## Instructions
<section id='instructions'>
Build an echo server, mounted at the route <code>GET /:word/echo</code>. Respond with a JSON object, taking the structure <code>{echo: word}</code>. You can find the word to be repeated at <code>req.params.word</code>. You can test your route from your browser's address bar, visiting some matching routes, e.g. <code>your-app-rootpath/freecodecamp/echo</code>.
</section>
# --instructions--
## Tests
<section id='tests'>
Build an echo server, mounted at the route `GET /:word/echo`. Respond with a JSON object, taking the structure `{echo: word}`. You can find the word to be repeated at `req.params.word`. You can test your route from your browser's address bar, visiting some matching routes, e.g. `your-app-rootpath/freecodecamp/echo`.
```yml
tests:
- text: 'Test 1 : Your echo server should repeat words correctly'
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: 'Test 2 : Your echo server should repeat words correctly'
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); })'
# --hints--
Test 1 : Your echo server should repeat words correctly
```js
(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);
}
);
```
</section>
Test 2 : Your echo server should repeat words correctly
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -45,5 +64,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,10 @@ challengeType: 2
forumTopicId: 301514
---
## Description
<section id='description'>
Earlier, you were introduced to the <code>express.static()</code> middleware function. Now its time to see what middleware is, in more detail. Middleware functions are functions that take 3 arguments: the request object, the response object, and the next function in the applications request-response cycle. These functions execute some code that can have side effects on the app, and usually add information to the request or response objects. They can also end the cycle by sending a response when some condition is met. If they dont send the response when they are done, they start the execution of the next function in the stack. This triggers calling the 3rd argument, <code>next()</code>.
# --description--
Earlier, you were introduced to the `express.static()` middleware function. Now its time to see what middleware is, in more detail. Middleware functions are functions that take 3 arguments: the request object, the response object, and the next function in the applications request-response cycle. These functions execute some code that can have side effects on the app, and usually add information to the request or response objects. They can also end the cycle by sending a response when some condition is met. If they dont send the response when they are done, they start the execution of the next function in the stack. This triggers calling the 3rd argument, `next()`.
Look at the following example:
```js
@@ -17,35 +18,36 @@ function(req, res, next) {
}
```
Lets suppose you mounted this function on a route. When a request matches the route, it displays the string “Im a middleware…”, then it executes the next function in the stack.
In this exercise, you are going to build root-level middleware. As you have seen in challenge 4, to mount a middleware function at root level, you can use the <code>app.use(&lt;mware-function&gt;)</code> method. In this case, the function will be executed for all the requests, but you can also set more specific conditions. For example, if you want a function to be executed only for POST requests, you could use <code>app.post(&lt;mware-function&gt;)</code>. Analogous methods exist for all the HTTP verbs (GET, DELETE, PUT, …).
</section>
Lets suppose you mounted this function on a route. When a request matches the route, it displays the string “Im a middleware…”, then it executes the next function in the stack. In this exercise, you are going to build root-level middleware. As you have seen in challenge 4, to mount a middleware function at root level, you can use the `app.use(<mware-function>)` method. In this case, the function will be executed for all the requests, but you can also set more specific conditions. For example, if you want a function to be executed only for POST requests, you could use `app.post(<mware-function>)`. Analogous methods exist for all the HTTP verbs (GET, DELETE, PUT, …).
## Instructions
<section id='instructions'>
Build a simple logger. For every request, it should log to the console a string taking the following format: <code>method path - ip</code>. An example would look like this: <code>GET /json - ::ffff:127.0.0.1</code>. Note that there is a space between <code>method</code> and <code>path</code> and that the dash separating <code>path</code> and <code>ip</code> is surrounded by a space on both sides. You can get the request method (http verb), the relative route path, and the callers ip from the request object using <code>req.method</code>, <code>req.path</code> and <code>req.ip</code>. Remember to call <code>next()</code> when you are done, or your server will be stuck forever. Be sure to have the Logs opened, and see what happens when some request arrives.
<strong>Note:</strong> Express evaluates functions in the order they appear in the code. This is true for middleware too. If you want it to work for all the routes, it should be mounted before them.
</section>
# --instructions--
## Tests
<section id='tests'>
Build a simple logger. For every request, it should log to the console a string taking the following format: `method path - ip`. An example would look like this: `GET /json - ::ffff:127.0.0.1`. Note that there is a space between `method` and `path` and that the dash separating `path` and `ip` is surrounded by a space on both sides. You can get the request method (http verb), the relative route path, and the callers ip from the request object using `req.method`, `req.path` and `req.ip`. Remember to call `next()` when you are done, or your server will be stuck forever. Be sure to have the Logs opened, and see what happens when some request arrives.
```yml
tests:
- text: Root level logger middleware should be active
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); })'
**Note:** Express evaluates functions in the order they appear in the code. This is true for middleware too. If you want it to work for all the routes, it should be mounted before them.
# --hints--
Root level logger middleware should be active
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -54,5 +56,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,43 +5,39 @@ challengeType: 2
forumTopicId: 301515
---
## Description
<section id='description'>
During the development process, it is important to be able to check whats going on in your code.
# --description--
During the development process, it is important to be able to check whats going on in your code.
Node is just a JavaScript environment. Like client side JavaScript, you can use the console to display useful debug information. On your local machine, you would see console output in a terminal. On Repl.it, a terminal is open in the right pane by default.
We recommend to keep the terminal open while working at these challenges. By reading the output in the terminal, you can see any errors that may occur.
</section>
## Instructions
<section id='instructions'>
# --instructions--
If you have not already done so, please read the instructions in [the introduction](/learn/apis-and-microservices/basic-node-and-express/) and start a new project on Repl.it using [this link](https://repl.it/github/freeCodeCamp/boilerplate-express).
Modify the <code>myApp.js</code> file to log "Hello World" to the console.
</section>
Modify the `myApp.js` file to log "Hello World" to the console.
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: <code>"Hello World"</code> should be in the console
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); })'
`"Hello World"` should be in the console
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -50,5 +46,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,42 +5,43 @@ challengeType: 2
forumTopicId: 301516
---
## Description
<section id='description'>
You can respond to requests with a file using the <code>res.sendFile(path)</code> method. You can put it inside the <code>app.get('/', ...)</code> route handler. Behind the scenes, this method will set the appropriate headers to instruct your browser on how to handle the file you want to send, according to its type. Then it will read and send the file. This method needs an absolute file path. We recommend you to use the Node global variable <code>__dirname</code> to calculate the path like this:
# --description--
You can respond to requests with a file using the `res.sendFile(path)` method. You can put it inside the `app.get('/', ...)` route handler. Behind the scenes, this method will set the appropriate headers to instruct your browser on how to handle the file you want to send, according to its type. Then it will read and send the file. This method needs an absolute file path. We recommend you to use the Node global variable `__dirname` to calculate the path like this:
```js
absolutePath = __dirname + relativePath/file.ext
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Send the <code>/views/index.html</code> file as a response to GET requests to the <code>/</code> path. If you view your live app, you should see a big HTML heading (and a form that we will use later…), with no style applied.
Send the `/views/index.html` file as a response to GET requests to the `/` path. If you view your live app, you should see a big HTML heading (and a form that we will use later…), with no style applied.
<strong>Note:</strong> You can edit the solution of the previous challenge or create a new one. If you create a new solution, keep in mind that Express evaluates routes from top to bottom, and executes the handler for the first match. You have to comment out the preceding solution, or the server will keep responding with a string.
</section>
**Note:** You can edit the solution of the previous challenge or create a new one. If you create a new solution, keep in mind that Express evaluates routes from top to bottom, and executes the handler for the first match. You have to comment out the preceding solution, or the server will keep responding with a string.
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: Your app should serve the file views/index.html
testString: 'getUserInput => $.get(getUserInput(''url'')).then(data => { assert.match(data, /<h1>.*<\/h1>/, ''Your app does not serve the expected HTML''); }, xhr => { throw new Error(xhr.responseText); })'
Your app should serve the file views/index.html
```js
(getUserInput) =>
$.get(getUserInput('url')).then(
(data) => {
assert.match(
data,
/<h1>.*<\/h1>/,
'Your app does not serve the expected HTML'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -49,5 +50,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,36 +5,39 @@ challengeType: 2
forumTopicId: 301517
---
## Description
<section id='description'>
# --description--
While an HTML server serves (you guessed it!) HTML, an API serves data. A <dfn>REST</dfn> (REpresentational State Transfer) API allows data exchange in a simple way, without the need for clients to know any detail about the server. The client only needs to know where the resource is (the URL), and the action it wants to perform on it (the verb). The GET verb is used when you are fetching some information, without modifying anything. These days, the preferred data format for moving information around the web is JSON. Simply put, JSON is a convenient way to represent a JavaScript object as a string, so it can be easily transmitted.
Let's create a simple API by creating a route that responds with JSON at the path <code>/json</code>. You can do it as usual, with the <code>app.get()</code> method. Inside the route handler, use the method <code>res.json()</code>, passing in an object as an argument. This method closes the request-response loop, returning the data. Behind the scenes, it converts a valid JavaScript object into a string, then sets the appropriate headers to tell your browser that you are serving JSON, and sends the data back. A valid object has the usual structure <code>{key: data}</code>. <code>data</code> can be a number, a string, a nested object or an array. <code>data</code> can also be a variable or the result of a function call, in which case it will be evaluated before being converted into a string.
</section>
## Instructions
<section id='instructions'>
Serve the object <code>{"message": "Hello json"}</code> as a response, in JSON format, to GET requests to the <code>/json</code> route. Then point your browser to <code>your-app-url/json</code>, you should see the message on the screen.
</section>
Let's create a simple API by creating a route that responds with JSON at the path `/json`. You can do it as usual, with the `app.get()` method. Inside the route handler, use the method `res.json()`, passing in an object as an argument. This method closes the request-response loop, returning the data. Behind the scenes, it converts a valid JavaScript object into a string, then sets the appropriate headers to tell your browser that you are serving JSON, and sends the data back. A valid object has the usual structure `{key: data}`. `data` can be a number, a string, a nested object or an array. `data` can also be a variable or the result of a function call, in which case it will be evaluated before being converted into a string.
## Tests
<section id='tests'>
# --instructions--
```yml
tests:
- text: 'The endpoint <code>/json</code> should serve the json object <code>{"message": "Hello json"}</code>'
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); })'
Serve the object `{"message": "Hello json"}` as a response, in JSON format, to GET requests to the `/json` route. Then point your browser to `your-app-url/json`, you should see the message on the screen.
# --hints--
The endpoint `/json` should serve the json object `{"message": "Hello json"}`
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -43,5 +46,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,36 +5,39 @@ challengeType: 2
forumTopicId: 301518
---
## Description
<section id='description'>
An HTML server usually has one or more directories that are accessible by the user. You can place there the static assets needed by your application (stylesheets, scripts, images). In Express, you can put in place this functionality using the middleware <code>express.static(path)</code>, where the <code>path</code> parameter is the absolute path of the folder containing the assets. If you dont know what middleware is... dont worry, we will discuss in detail later. Basically, middleware are functions that intercept route handlers, adding some kind of information. A middleware needs to be mounted using the method <code>app.use(path, middlewareFunction)</code>. The first <code>path</code> argument is optional. If you dont pass it, the middleware will be executed for all requests.
</section>
# --description--
An HTML server usually has one or more directories that are accessible by the user. You can place there the static assets needed by your application (stylesheets, scripts, images). In Express, you can put in place this functionality using the middleware `express.static(path)`, where the `path` parameter is the absolute path of the folder containing the assets. If you dont know what middleware is... dont worry, we will discuss in detail later. Basically, middleware are functions that intercept route handlers, adding some kind of information. A middleware needs to be mounted using the method `app.use(path, middlewareFunction)`. The first `path` argument is optional. If you dont pass it, the middleware will be executed for all requests.
# --instructions--
Mount the `express.static()` middleware for all requests with `app.use()`. The absolute path to the assets folder is `__dirname + /public`.
## Instructions
<section id='instructions'>
Mount the <code>express.static()</code> middleware for all requests with <code>app.use()</code>. The absolute path to the assets folder is <code>__dirname + /public</code>.
Now your app should be able to serve a CSS stylesheet. From outside, the public folder will appear mounted to the root directory. Your front-page should look a little better now!
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: Your app should serve asset files from the <code>/public</code> directory
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); })'
Your app should serve asset files from the `/public` directory
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -43,5 +46,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,12 +5,11 @@ challengeType: 2
forumTopicId: 301519
---
## Description
<section id='description'>
In the first two lines of the file <code>myApp.js</code>, you can see how easy it is to create an Express app object. This object has several methods, and you will learn many of them in these challenges. One fundamental method is <code>app.listen(port)</code>. It tells your server to listen on a given port, putting it in running state. For testing reasons, we need the app to be running in the background so we added this method in the `server.js` file for you.
# --description--
Lets serve our first string! In Express, routes takes the following structure: <code>app.METHOD(PATH, HANDLER)</code>. METHOD is an http method in lowercase. PATH is a relative path on the server (it can be a string, or even a regular expression). HANDLER is a function that Express calls when the route is matched.
Handlers take the form <code>function(req, res) {...}</code>, where req is the request object, and res is the response object. For example, the handler
In the first two lines of the file `myApp.js`, you can see how easy it is to create an Express app object. This object has several methods, and you will learn many of them in these challenges. One fundamental method is `app.listen(port)`. It tells your server to listen on a given port, putting it in running state. For testing reasons, we need the app to be running in the background so we added this method in the \`server.js\` file for you.
Lets serve our first string! In Express, routes takes the following structure: `app.METHOD(PATH, HANDLER)`. METHOD is an http method in lowercase. PATH is a relative path on the server (it can be a string, or even a regular expression). HANDLER is a function that Express calls when the route is matched. Handlers take the form `function(req, res) {...}`, where req is the request object, and res is the response object. For example, the handler
```js
function(req, res) {
@@ -19,33 +18,36 @@ function(req, res) {
```
will serve the string 'Response String'.
</section>
## Instructions
<section id='instructions'>
Use the <code>app.get()</code> method to serve the string "Hello Express" to GET requests matching the <code>/</code> (root) path. Be sure that your code works by looking at the logs, then see the results in the preview if you are using Repl.it.
<strong>Note:</strong> All the code for these lessons should be added in between the few lines of code we have started you off with.
</section>
# --instructions--
## Tests
<section id='tests'>
Use the `app.get()` method to serve the string "Hello Express" to GET requests matching the `/` (root) path. Be sure that your code works by looking at the logs, then see the results in the preview if you are using Repl.it.
```yml
tests:
- text: Your app should serve the string '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); })'
**Note:** All the code for these lessons should be added in between the few lines of code we have started you off with.
# --hints--
Your app should serve the string 'Hello Express'
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -54,5 +56,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,10 @@ challengeType: 2
forumTopicId: 301520
---
## Description
<section id='description'>
# --description--
Besides GET, there is another common HTTP verb, it is POST. POST is the default method used to send client data with HTML forms. In REST convention, POST is used to send data to create new items in the database (a new user, or a new blog post). You dont have a database in this project, but you are going to learn how to handle POST requests anyway.
In these kind of requests, the data doesnt appear in the URL, it is hidden in the request body. The body is a part of the HTTP request, also called the payload. Even though the data is not visible in the URL, this does not mean that it is private. To see why, look at the raw content of an HTTP POST request:
```http
@@ -19,35 +20,37 @@ Content-Length: 20
name=John+Doe&age=25
```
As you can see, the body is encoded like the query string. This is the default format used by HTML forms. With Ajax, you can also use JSON to handle data having a more complex structure. There is also another type of encoding: multipart/form-data. This one is used to upload binary files.
In this exercise, you will use a urlencoded body. To parse the data coming from POST requests, you have to install the <code>body-parser</code> package. This package allows you to use a series of middleware, which can decode data in different formats.
</section>
As you can see, the body is encoded like the query string. This is the default format used by HTML forms. With Ajax, you can also use JSON to handle data having a more complex structure. There is also another type of encoding: multipart/form-data. This one is used to upload binary files. In this exercise, you will use a urlencoded body. To parse the data coming from POST requests, you have to install the `body-parser` package. This package allows you to use a series of middleware, which can decode data in different formats.
## Instructions
<section id='instructions'>
Install the <code>body-parser</code> module in your <code>package.json</code>. Then, <code>require</code> it at the top of the file. Store it in a variable named <code>bodyParser</code>. The middleware to handle urlencoded data is returned by <code>bodyParser.urlencoded({extended: false})</code>. Pass to <code>app.use()</code> the function returned by the previous method call. As usual, the middleware must be mounted before all the routes which need it.
<strong>Note:</strong> <code>extended=false</code> is a configuration option that tells the parser to use the classic encoding. When using it, values can be only strings or arrays. The extended version allows more data flexibility, but it is outmatched by JSON.
</section>
# --instructions--
## Tests
<section id='tests'>
Install the `body-parser` module in your `package.json`. Then, `require` it at the top of the file. Store it in a variable named `bodyParser`. The middleware to handle urlencoded data is returned by `bodyParser.urlencoded({extended: false})`. Pass to `app.use()` the function returned by the previous method call. As usual, the middleware must be mounted before all the routes which need it.
```yml
tests:
- text: The 'body-parser' middleware should be mounted
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); })'
**Note:** `extended=false` is a configuration option that tells the parser to use the classic encoding. When using it, values can be only strings or arrays. The extended version allows more data flexibility, but it is outmatched by JSON.
# --hints--
The 'body-parser' middleware should be mounted
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -56,5 +59,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,37 +5,40 @@ challengeType: 2
forumTopicId: 301521
---
## Description
<section id='description'>
The <code>.env</code> file is a hidden file that is used to pass environment variables to your application. This file is secret, no one but you can access it, and it can be used to store data that you want to keep private or hidden. For example, you can store API keys from external services or your database URI. You can also use it to store configuration options. By setting configuration options, you can change the behavior of your application, without the need to rewrite some code.
The environment variables are accessible from the app as <code>process.env.VAR_NAME</code>. The <code>process.env</code> object is a global Node object, and variables are passed as strings. By convention, the variable names are all uppercase, with words separated by an underscore. The <code>.env</code> is a shell file, so you dont need to wrap names or values in quotes. It is also important to note that there cannot be space around the equals sign when you are assigning values to your variables, e.g. <code>VAR_NAME=value</code>. Usually, you will put each variable definition on a separate line.
</section>
# --description--
The `.env` file is a hidden file that is used to pass environment variables to your application. This file is secret, no one but you can access it, and it can be used to store data that you want to keep private or hidden. For example, you can store API keys from external services or your database URI. You can also use it to store configuration options. By setting configuration options, you can change the behavior of your application, without the need to rewrite some code.
The environment variables are accessible from the app as `process.env.VAR_NAME`. The `process.env` object is a global Node object, and variables are passed as strings. By convention, the variable names are all uppercase, with words separated by an underscore. The `.env` is a shell file, so you dont need to wrap names or values in quotes. It is also important to note that there cannot be space around the equals sign when you are assigning values to your variables, e.g. `VAR_NAME=value`. Usually, you will put each variable definition on a separate line.
# --instructions--
## Instructions
<section id='instructions'>
Let's add an environment variable as a configuration option.
Store the variable <code>MESSAGE_STYLE=uppercase</code> in the <code>.env</code> file. Then tell the GET <code>/json</code> route handler that you created in the last challenge to transform the response objects message to uppercase if <code>process.env.MESSAGE_STYLE</code> equals <code>uppercase</code>. The response object should become <code>{"message": "HELLO JSON"}</code>.
</section>
## Tests
<section id='tests'>
Store the variable `MESSAGE_STYLE=uppercase` in the `.env` file. Then tell the GET `/json` route handler that you created in the last challenge to transform the response objects message to uppercase if `process.env.MESSAGE_STYLE` equals `uppercase`. The response object should become `{"message": "HELLO JSON"}`.
```yml
tests:
- text: The response of the endpoint <code>/json</code> should change according to the environment variable <code>MESSAGE_STYLE</code>
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); })'
# --hints--
The response of the endpoint `/json` should change according to the environment variable `MESSAGE_STYLE`
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -44,5 +47,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,43 +5,44 @@ challengeType: 2
forumTopicId: 301522
---
## Description
<section id='description'>
The next part of a good package.json file is the <code>description</code> field; where a short, but informative description about your project belongs.
# --description--
The next part of a good package.json file is the `description` field; where a short, but informative description about your project belongs.
If you some day plan to publish a package to npm, this is the string that should sell your idea to the user when they decide whether to install your package or not. However, thats not the only use case for the description, its a great way to summarize what a project does. Its just as important in any Node.js project to help other developers, future maintainers or even your future self understand the project quickly.
Regardless of what you plan for your project, a description is definitely recommended. Here's an example:
```json
"description": "A project that does something awesome",
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Add a <code>description</code> to the package.json file of your project.
<strong>Note:</strong> Remember to use double-quotes for field-names (") and commas (,) to separate fields.
</section>
Add a `description` to the package.json file of your project.
## Tests
<section id='tests'>
**Note:** Remember to use double-quotes for field-names (") and commas (,) to separate fields.
```yml
tests:
- text: package.json should have a valid "description" key
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); })'
# --hints--
package.json should have a valid "description" key
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -50,5 +51,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,41 +5,40 @@ challengeType: 2
forumTopicId: 301523
---
## Description
<section id='description'>
The <code>license</code> field is where you inform users of what they are allowed to do with your project.
# --description--
The `license` field is where you inform users of what they are allowed to do with your project.
Some common licenses for open source projects include MIT and BSD. License information is not required, and copyright laws in most countries will give you ownership of what you create by default. However, its always a good practice to explicitly state what users can and cant do. Here's an example of the license field:
```json
"license": "MIT",
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Fill the <code>license</code> field in the package.json file of your project as you find suitable.
</section>
Fill the `license` field in the package.json file of your project as you find suitable.
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: package.json should have a valid "license" key
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); })'
package.json should have a valid "license" key
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -48,5 +47,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,40 +5,38 @@ challengeType: 2
forumTopicId: 301525
---
## Description
<section id='description'>
A <code>version</code> is one of the required fields of your package.json file. This field describes the current version of your project. Here's an example:
# --description--
A `version` is one of the required fields of your package.json file. This field describes the current version of your project. Here's an example:
```json
"version": "1.2.0",
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Add a <code>version</code> to the package.json file of your project.
</section>
Add a `version` to the package.json file of your project.
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: package.json should have a valid "version" key
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); })'
package.json should have a valid "version" key
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -47,5 +45,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,46 +5,76 @@ challengeType: 2
forumTopicId: 301526
---
## Description
<section id='description'>
The <code>keywords</code> field is where you can describe your project using related keywords. Here's an example:
# --description--
The `keywords` field is where you can describe your project using related keywords. Here's an example:
```json
"keywords": [ "descriptive", "related", "words" ],
```
As you can see, this field is structured as an array of double-quoted strings.
</section>
## Instructions
<section id='instructions'>
Add an array of suitable strings to the <code>keywords</code> field in the package.json file of your project.
# --instructions--
Add an array of suitable strings to the `keywords` field in the package.json file of your project.
One of the keywords should be "freecodecamp".
</section>
## Tests
<section id='tests'>
# --hints--
```yml
tests:
- text: package.json should have a valid "keywords" key
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" field should be an 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: '"keywords" should include "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); })'
package.json should have a valid "keywords" key
```js
(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);
}
);
```
</section>
"keywords" field should be an Array
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
"keywords" should include "freecodecamp"
## Solution
<section id='solution'>
```js
(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);
}
);
```
# --seed--
# --solutions--
```js
/**
@@ -53,5 +83,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,10 @@ challengeType: 2
forumTopicId: 301527
---
## Description
<section id='description'>
One of the biggest reasons to use a package manager, is their powerful dependency management. Instead of manually having to make sure that you get all dependencies whenever you set up a project on a new computer, npm automatically installs everything for you. But how can npm know exactly what your project needs? Meet the <code>dependencies</code> section of your package.json file.
# --description--
One of the biggest reasons to use a package manager, is their powerful dependency management. Instead of manually having to make sure that you get all dependencies whenever you set up a project on a new computer, npm automatically installs everything for you. But how can npm know exactly what your project needs? Meet the `dependencies` section of your package.json file.
In this section, packages your project requires are stored using the following format:
```json
@@ -18,35 +19,55 @@ In this section, packages your project requires are stored using the following f
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Add version "2.14.0" of the "moment" package to the <code>dependencies</code> field of your package.json file.
<strong>Note:</strong> Moment is a handy library for working with time and dates.
</section>
Add version "2.14.0" of the "moment" package to the `dependencies` field of your package.json file.
## Tests
<section id='tests'>
**Note:** Moment is a handy library for working with time and dates.
```yml
tests:
- text: '"dependencies" should include "moment"'
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" version should be "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); })'
# --hints--
"dependencies" should include "moment"
```js
(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);
}
);
```
</section>
"moment" version should be "2.14.0"
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -55,5 +76,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,43 +5,44 @@ challengeType: 2
forumTopicId: 301528
---
## Description
<section id='description'>
The <code>package.json</code> file is the center of any Node.js project or npm package. It stores information about your project, similar to how the &lt;head&gt; section of an HTML document describes the content of a webpage. It consists of a single JSON object where information is stored in key-value pairs. There are only two required fields; "name" and "version", but its good practice to provide additional information about your project that could be useful to future users or maintainers.
# --description--
The `package.json` file is the center of any Node.js project or npm package. It stores information about your project, similar to how the &lt;head> section of an HTML document describes the content of a webpage. It consists of a single JSON object where information is stored in key-value pairs. There are only two required fields; "name" and "version", but its good practice to provide additional information about your project that could be useful to future users or maintainers.
If you look at the file tree of your project, you will find the package.json file on the top level of the tree. This is the file that you will be improving in the next couple of challenges.
One of the most common pieces of information in this file is the <code>author</code> field. It specifies who created the project, and can consist of a string or an object with contact or other details. An object is recommended for bigger projects, but a simple string like the following example will do for this project.
One of the most common pieces of information in this file is the `author` field. It specifies who created the project, and can consist of a string or an object with contact or other details. An object is recommended for bigger projects, but a simple string like the following example will do for this project.
```json
"author": "Jane Doe",
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
Add your name as the <code>author</code> of the project in the package.json file.
<strong>Note:</strong> Remember that youre writing JSON, so all field names must use double-quotes (") and be separated with a comma (,).
</section>
Add your name as the `author` of the project in the package.json file.
## Tests
<section id='tests'>
**Note:** Remember that youre writing JSON, so all field names must use double-quotes (") and be separated with a comma (,).
```yml
tests:
- text: package.json should have a valid "author" key
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); })'
# --hints--
package.json should have a valid "author" key
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -50,5 +51,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,47 +5,65 @@ challengeType: 2
forumTopicId: 301529
---
## Description
<section id='description'>
<code>Versions</code> of the npm packages in the dependencies section of your package.json file follow whats called Semantic Versioning (SemVer), an industry standard for software versioning aiming to make it easier to manage dependencies. Libraries, frameworks or other tools published on npm should use SemVer in order to clearly communicate what kind of changes projects can expect if they update.
# --description--
`Versions` of the npm packages in the dependencies section of your package.json file follow whats called Semantic Versioning (SemVer), an industry standard for software versioning aiming to make it easier to manage dependencies. Libraries, frameworks or other tools published on npm should use SemVer in order to clearly communicate what kind of changes projects can expect if they update.
Knowing SemVer can be useful when you develop software that uses external dependencies (which you almost always do). One day, your understanding of these numbers will save you from accidentally introducing breaking changes to your project without understanding why things that worked yesterday suddenly dont work today. This is how Semantic Versioning works according to the official website:
```json
"package": "MAJOR.MINOR.PATCH"
```
The MAJOR version should increment when you make incompatible API changes.
The MINOR version should increment when you add functionality in a backwards-compatible manner.
The PATCH version should increment when you make backwards-compatible bug fixes.
This means that PATCHes are bug fixes and MINORs add new features but neither of them break what worked before. Finally, MAJORs add changes that wont work with earlier versions.
</section>
The MAJOR version should increment when you make incompatible API changes. The MINOR version should increment when you add functionality in a backwards-compatible manner. The PATCH version should increment when you make backwards-compatible bug fixes. This means that PATCHes are bug fixes and MINORs add new features but neither of them break what worked before. Finally, MAJORs add changes that wont work with earlier versions.
## Instructions
<section id='instructions'>
In the dependencies section of your package.json file, change the <code>version</code> of moment to match MAJOR version 2, MINOR version 10 and PATCH version 2
</section>
# --instructions--
## Tests
<section id='tests'>
In the dependencies section of your package.json file, change the `version` of moment to match MAJOR version 2, MINOR version 10 and PATCH version 2
```yml
tests:
- text: '"dependencies" should include "moment"'
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" version should be "2.10.2"'
testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/package.json'').then(data => { var packJson = JSON.parse(data); assert.equal(packJson.dependencies.moment,"2.10.2", ''Wrong version of "moment". It should be 2.10.2''); }, xhr => { throw new Error(xhr.responseText); })'
# --hints--
"dependencies" should include "moment"
```js
(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);
}
);
```
</section>
"moment" version should be "2.10.2"
## Challenge Seed
<section id='challengeSeed'>
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/package.json').then(
(data) => {
var packJson = JSON.parse(data);
assert.equal(
packJson.dependencies.moment,
'2.10.2',
'Wrong version of "moment". It should be 2.10.2'
);
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -54,5 +72,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,38 +5,44 @@ challengeType: 2
forumTopicId: 301530
---
## Description
<section id='description'>
# --description--
You have now tested a few ways you can manage dependencies of your project by using the package.json's dependencies section. You have also included external packages by adding them to the file and even told npm what types of versions you want, by using special characters such as the tilde or the caret.
But what if you want to remove an external package that you no longer need? You might already have guessed it, just remove the corresponding key-value pair for that package from your dependencies.
This same method applies to removing other fields in your package.json as well
</section>
## Instructions
<section id='instructions'>
# --instructions--
Remove the moment package from your dependencies.
<strong>Note:</strong> Make sure you have the right amount of commas after removing it.
</section>
## Tests
<section id='tests'>
**Note:** Make sure you have the right amount of commas after removing it.
```yml
tests:
- text: '"dependencies" should not include "moment"'
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); })'
# --hints--
"dependencies" should not include "moment"
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -45,5 +51,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,10 @@ challengeType: 2
forumTopicId: 301531
---
## Description
<section id='description'>
Similar to how the tilde we learned about in the last challenge allows npm to install the latest PATCH for a dependency, the caret (<code>^</code>) allows npm to install future updates as well. The difference is that the caret will allow both MINOR updates and PATCHes.
# --description--
Similar to how the tilde we learned about in the last challenge allows npm to install the latest PATCH for a dependency, the caret (`^`) allows npm to install future updates as well. The difference is that the caret will allow both MINOR updates and PATCHes.
Your current version of moment should be "~2.10.2" which allows npm to install to the latest 2.10.x version. If you were to use the caret (^) as a version prefix instead, npm would be allowed to update to any 2.x.x version.
```json
@@ -15,35 +16,56 @@ Your current version of moment should be "~2.10.2" which allows npm to install t
```
This would allow updates to any 1.x.x version of the package.
</section>
## Instructions
<section id='instructions'>
Use the caret (<code>^</code>) to prefix the version of moment in your dependencies and allow npm to update it to any new MINOR release.
<strong>Note:</strong> The version numbers themselves should not be changed.
</section>
# --instructions--
## Tests
<section id='tests'>
Use the caret (`^`) to prefix the version of moment in your dependencies and allow npm to update it to any new MINOR release.
```yml
tests:
- text: '"dependencies" should include "moment"'
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" version should match "^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); })'
**Note:** The version numbers themselves should not be changed.
# --hints--
"dependencies" should include "moment"
```js
(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);
}
);
```
</section>
"moment" version should match "^2.x.x"
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -52,5 +74,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,45 +5,67 @@ challengeType: 2
forumTopicId: 301532
---
## Description
<section id='description'>
# --description--
In the last challenge, you told npm to only include a specific version of a package. Thats a useful way to freeze your dependencies if you need to make sure that different parts of your project stay compatible with each other. But in most use cases, you dont want to miss bug fixes since they often include important security patches and (hopefully) dont break things in doing so.
To allow an npm dependency to update to the latest PATCH version, you can prefix the dependencys version with the tilde (<code>~</code>) character. Here's an example of how to allow updates to any 1.3.x version.
To allow an npm dependency to update to the latest PATCH version, you can prefix the dependencys version with the tilde (`~`) character. Here's an example of how to allow updates to any 1.3.x version.
```json
"package": "~1.3.8"
```
</section>
# --instructions--
## Instructions
<section id='instructions'>
In the package.json file, your current rule for how npm may upgrade moment is to use a specific version (2.10.2). But now, you want to allow the latest 2.10.x version.
Use the tilde (<code>~</code>) character to prefix the version of moment in your dependencies, and allow npm to update it to any new PATCH release.
<strong>Note:</strong> The version numbers themselves should not be changed.
</section>
## Tests
<section id='tests'>
Use the tilde (`~`) character to prefix the version of moment in your dependencies, and allow npm to update it to any new PATCH release.
```yml
tests:
- text: '"dependencies" should include "moment"'
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" version should match "~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); })'
**Note:** The version numbers themselves should not be changed.
# --hints--
"dependencies" should include "moment"
```js
(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);
}
);
```
</section>
"moment" version should match "~2.10.2"
## Challenge Seed
<section id='challengeSeed'>
```js
(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);
}
);
```
</section>
# --seed--
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -52,5 +74,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,60 +5,77 @@ challengeType: 2
forumTopicId: 301533
---
## Description
<section id='description'>
# --description--
If you dont pass the callback as the last argument to `Model.find()` (or to the other search methods), the query is not executed. You can store the query in a variable for later use. This kind of object enables you to build up a query using chaining syntax. The actual db search is executed when you finally chain the method `.exec()`. You always need to pass your callback to this last method. There are many query helpers, here we'll use the most commonly used.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `queryChain` function to find people who like the food specified by the variable named `foodToSearch`. Sort them by `name`, limit the results to two documents, and hide their age. Chain `.find()`, `.sort()`, `.limit()`, `.select()`, and then `.exec()`. Pass the `done(err, data)` callback to `exec()`.
### Further Readings
## Further Reading
If you are eager to learn and want to go deeper, You may look at:
- Indexes ( very important for query efficiency ),
- Pre/Post hooks,
- Validation,
- Schema Virtuals and Model, Static, and Instance methods,
- Indexes ( very important for query efficiency ),
- Pre/Post hooks,
- Validation,
- Schema Virtuals and Model, Static, and Instance methods,
</section>
# --hints--
## Tests
Chaining query helpers should succeed
<section id='tests'>
```yml
tests:
- text: Chaining query helpers should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -67,5 +84,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,9 +5,7 @@ challengeType: 2
forumTopicId: 301535
---
## Description
<section id='description'>
# --description--
**C**RUD Part I - CREATE
@@ -27,11 +25,7 @@ const someFunc = function(done) {
};
```
</section>
## Instructions
<section id='instructions'>
# --instructions--
Create a person schema called `personSchema` having this prototype:
@@ -43,40 +37,48 @@ age : number
favoriteFoods : array of strings (*)
```
Use the Mongoose basic schema types. If you want you can also add more fields, use simple validators like required or unique, and set default values. See the <a href='http://mongoosejs.com/docs/guide.html'>Mongoose docs</a>.
Use the Mongoose basic schema types. If you want you can also add more fields, use simple validators like required or unique, and set default values. See the [Mongoose docs](http://mongoosejs.com/docs/guide.html).
Now, create a model called `Person` from the `personSchema`.
</section>
# --hints--
## Tests
Creating an instance from a mongoose schema should succeed
<section id='tests'>
```yml
tests:
- text: Creating an instance from a mongoose schema should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -85,5 +87,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,17 +5,11 @@ challengeType: 2
forumTopicId: 301536
---
## Description
<section id='description'>
# --description--
In this challenge you will have to create and save a record of a model.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Within the `createAndSavePerson` function, create a document instance using the `Person` model constructor you built before. Pass to the constructor an object having the fields `name`, `age`, and `favoriteFoods`. Their types must conform to the ones in the `personSchema`. Then, call the method `document.save()` on the returned document instance. Pass to it a callback using the Node convention. This is a common pattern; all the following CRUD methods take a callback function like this as the last argument.
@@ -28,36 +22,31 @@ person.save(function(err, data) {
});
```
</section>
# --hints--
## Tests
<section id='tests'>
```yml
tests:
- text: Creating and saving a db item should succeed
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); })
Creating and saving a db item should succeed
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -66,5 +55,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,53 +5,60 @@ challengeType: 2
forumTopicId: 301537
---
## Description
<section id='description'>
# --description--
Sometimes you need to create many instances of your models, e.g. when seeding a database with initial data. `Model.create()` takes an array of objects like `[{name: 'John', ...}, {...}, ...]` as the first argument, and saves them all in the db.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `createManyPeople` function to create many people using `Model.create()` with the argument `arrayOfPeople`.
**Note:** You can reuse the model you instantiated in the previous exercise.
</section>
# --hints--
## Tests
Creating many db items at once should succeed
<section id='tests'>
```yml
tests:
- text: Creating many db items at once should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -60,5 +67,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,50 +5,49 @@ challengeType: 2
forumTopicId: 301538
---
## Description
<section id='description'>
# --description--
`Model.remove()` is useful to delete all the documents matching given criteria.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `removeManyPeople` function to delete all the people whose name is within the variable `nameToRemove`, using `Model.remove()`. Pass it to a query document with the `name` field set, and a callback.
**Note:** The `Model.remove()` doesnt return the deleted document, but a JSON object containing the outcome of the operation, and the number of items affected. Dont forget to pass it to the `done()` callback, since we use it in tests.
</section>
# --hints--
## Tests
Deleting many items at once should succeed
<section id='tests'>
```yml
tests:
- text: Deleting many items at once should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -57,5 +56,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,50 +5,45 @@ challengeType: 2
forumTopicId: 301539
---
## Description
<section id='description'>
# --description--
`findByIdAndRemove` and `findOneAndRemove` are like the previous update methods. They pass the removed document to the db. As usual, use the function argument `personId` as the search key.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `removeById` function to delete one person by the person's `_id`. You should use one of the methods `findByIdAndRemove()` or `findOneAndRemove()`.
</section>
# --hints--
## Tests
Deleting an item should succeed
<section id='tests'>
```yml
tests:
- text: Deleting an item should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -57,5 +52,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,17 +5,11 @@ challengeType: 2
forumTopicId: 301540
---
## Description
<section id='description'>
# --description--
In this challenge, you will import the required projects, and connect to your Atlas database.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Add `mongodb` and `mongoose` to the projects `package.json`. Then, require mongoose as `mongoose` in `myApp.js`. Store your MongoDB Atlas database URI in a private `.env` file as `MONGO_URI`. Surround the the URI with single or double quotes, and make sure no space exists between both the variable and the `=`, and the value and `=`. Connect to the database using the following syntax:
@@ -23,44 +17,55 @@ Add `mongodb` and `mongoose` to the projects `package.json`. Then, require mo
mongoose.connect(<Your URI>, { useNewUrlParser: true, useUnifiedTopology: true });
```
</section>
# --hints--
## Tests
"mongodb" dependency should be in package.json
<section id='tests'>
```yml
tests:
- text: '"mongodb" dependency should be in 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" dependency should be in 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" should be connected to a database'
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); })
```js
(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);
}
);
```
</section>
"mongoose" dependency should be in package.json
## Challenge Seed
```js
(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);
}
);
```
<section id='challengeSeed'>
"mongoose" should be connected to a database
</section>
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/is-mongoose-ok').then(
(data) => {
assert.isTrue(data.isMongooseOk, 'mongoose is not connected');
},
(xhr) => {
throw new Error(xhr.responseText);
}
);
```
## Solution
# --seed--
<section id='solution'>
# --solutions--
```js
/**
@@ -69,5 +74,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,51 +5,46 @@ challengeType: 2
forumTopicId: 301541
---
## Description
<section id='description'>
# --description--
In the good old days, this was what you needed to do if you wanted to edit a document, and be able to use it somehow (e.g. sending it back in a server response). Mongoose has a dedicated updating method: `Model.update()`. It is bound to the low-level mongo driver. It can bulk-edit many documents matching certain criteria, but it doesnt send back the updated document, only a 'status' message. Furthermore, it makes model validations difficult, because it just directly calls the mongo driver.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `findEditThenSave` function to find a person by `_id` (use any of the above methods) with the parameter `personId` as search key. Add `"hamburger"` to the list of the person's `favoriteFoods` (you can use `Array.push()`). Then - inside the find callback - `save()` the updated `Person`.
**Note:** This may be tricky, if in your Schema, you declared `favoriteFoods` as an Array, without specifying the type (i.e. `[String]`). In that case, `favoriteFoods` defaults to Mixed type, and you have to manually mark it as edited using `document.markModified('edited-field')`. See [Mongoose documentation](https://mongoosejs.com/docs/schematypes.html#Mixed)
</section>
# --hints--
## Tests
Find-edit-update an item should succeed
<section id='tests'>
```yml
tests:
- text: Find-edit-update an item should succeed
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 is 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); })
```js
(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 is 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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -58,5 +53,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,51 +5,50 @@ challengeType: 2
forumTopicId: 301542
---
## Description
<section id='description'>
# --description--
Recent versions of Mongoose have methods to simplify documents updating. Some more advanced features (i.e. pre/post hooks, validation) behave differently with this approach, so the classic method is still useful in many situations. `findByIdAndUpdate()` can be used when searching by id.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `findAndUpdate` function to find a person by `Name` and set the person's age to `20`. Use the function parameter `personName` as the search key.
**Note:** You should return the updated document. To do that, you need to pass the options document `{ new: true }` as the 3rd argument to `findOneAndUpdate()`. By default, these methods return the unmodified object.
</section>
# --hints--
## Tests
findOneAndUpdate an item should succeed
<section id='tests'>
```yml
tests:
- text: findOneAndUpdate an item should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -58,5 +57,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,50 +5,45 @@ challengeType: 2
forumTopicId: 301543
---
## Description
<section id='description'>
# --description--
In its simplest usage, `Model.find()` accepts a query document (a JSON object) as the first argument, then a callback. It returns an array of matches. It supports an extremely wide range of search options. Read more in the docs.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `findPeopleByName` function to find all the people having a given name, using `Model.find() -> [Person]`
Use the function argument `personName` as the search key.
</section>
# --hints--
## Tests
Find all items corresponding to a criteria should succeed
<section id='tests'>
```yml
tests:
- text: Find all items corresponding to a criteria should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -57,5 +52,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,49 +5,40 @@ challengeType: 2
forumTopicId: 301544
---
## Description
<section id='description'>
# --description--
When saving a document, MongoDB automatically adds the field `_id`, and set it to a unique alphanumeric key. Searching by `_id` is an extremely frequent operation, so Mongoose provides a dedicated method for it.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `findPersonById` to find the only person having a given `_id`, using `Model.findById() -> Person`. Use the function argument `personId` as the search key.
</section>
# --hints--
## Tests
Find an item by Id should succeed
<section id='tests'>
```yml
tests:
- text: Find an item by Id should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -56,5 +47,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>

View File

@@ -5,48 +5,43 @@ challengeType: 2
forumTopicId: 301545
---
## Description
<section id='description'>
# --description--
`Model.findOne()` behaves like `.find()`, but it returns only one document (not an array), even if there are multiple items. It is especially useful when searching by properties that you have declared as unique.
</section>
## Instructions
<section id='instructions'>
# --instructions--
Modify the `findOneByFood` function to find just one person which has a certain food in the person's favorites, using `Model.findOne() -> Person`. Use the function argument `food` as search key.
</section>
# --hints--
## Tests
Find one item should succeed
<section id='tests'>
```yml
tests:
- text: Find one item should succeed
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); })
```js
(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);
}
);
```
</section>
# --seed--
## Challenge Seed
<section id='challengeSeed'>
</section>
## Solution
<section id='solution'>
# --solutions--
```js
/**
@@ -55,5 +50,3 @@ tests:
Please check our contributing guidelines to learn more.
*/
```
</section>