chore(i18n,curriculum): processed translations - new ukrainian (#44447)
This commit is contained in:
@@ -0,0 +1,611 @@
|
||||
---
|
||||
id: 5a8b073d06fa14fcfde687aa
|
||||
title: Трекер вправ
|
||||
challengeType: 4
|
||||
forumTopicId: 301505
|
||||
dashedName: exercise-tracker
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Створіть full stack додаток на JavaScript, який функціонально схожий до цього: <https://exercise-tracker.freecodecamp.rocks/>. Робота над цим проектом залучатиме тебе писати свій код використовуючи один з наступних методів:
|
||||
|
||||
- Клонувати [цей репозиторій з GitHub](https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/) та локально завершити свій проект.
|
||||
- Використати [наш проект для початківців на Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-exercisetracker) для завершення свого проекту.
|
||||
- Використати конструктор сайтів на свій вибір для завершення проекту. Впевніться, що ви зберегли всі файли із нашого GitHub репозиторію.
|
||||
|
||||
По завершенню переконайтеся, що працююча демоверсія вашого проекту розміщена у відкритому доступі. Потім введіть його URL-адресу в поле `Solution Link`. За бажанням також можете ввести посилання на вихідний код вашого проекту в полі `GitHub Link`.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Ваші відповіді повинні мати наступні структури.
|
||||
|
||||
Вправа:
|
||||
|
||||
```js
|
||||
{
|
||||
username: "fcc_test"
|
||||
description: "test",
|
||||
duration: 60,
|
||||
date: "Mon Jan 01 1990",
|
||||
_id: "5fb5853f734231456ccb3b05"
|
||||
}
|
||||
```
|
||||
|
||||
Користувач:
|
||||
|
||||
```js
|
||||
{
|
||||
username: "fcc_test",
|
||||
_id: "5fb5853f734231456ccb3b05"
|
||||
}
|
||||
```
|
||||
|
||||
Лог:
|
||||
|
||||
```js
|
||||
{
|
||||
username: "fcc_test",
|
||||
count: 1,
|
||||
_id: "5fb5853f734231456ccb3b05",
|
||||
log: [{
|
||||
description: "test",
|
||||
duration: 60,
|
||||
date: "Mon Jan 01 1990",
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Підказка:** для отримування очікуваного результату властивості `date` може використовуватися метод `toDateString` з `Date` API.
|
||||
|
||||
# --hints--
|
||||
|
||||
Вам необхідно вказати свій власний проект, а не приклад URL-адреси.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
assert(
|
||||
!/.*\/exercise-tracker\.freecodecamp\.rocks/.test(getUserInput('url'))
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Ви можете виконати `POST` запит до `/api/users` з даними форми `username` для створення нового користувача.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `username=fcc_test_${Date.now()}`.substr(0, 29)
|
||||
});
|
||||
assert.isTrue(res.ok);
|
||||
if(!res.ok) {
|
||||
throw new Error(`${res.status} ${res.statusText}`)
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Отримана відповідь від `POST /api/users` з даними форми `username` буде об'єктом з властивостями `username` та `_id`.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Ви можете зробити запит `GET` на `/api/users`, щоб отримати список всіх користувачів.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users');
|
||||
assert.isTrue(res.ok);
|
||||
if(!res.ok) {
|
||||
throw new Error(`${res.status} ${res.statusText}`)
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Запит `GET` на `/api/users` повертає масив.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users');
|
||||
if(res.ok){
|
||||
const users = await res.json();
|
||||
assert.isArray(users);
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Кожен елемент у масиві, який повернувся з `GET /api/users`, є літералом об'єкта з `username` та `_id` користувача.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users');
|
||||
if(res.ok){
|
||||
const users = await res.json();
|
||||
const user = users[0];
|
||||
assert.exists(user);
|
||||
assert.exists(user.username);
|
||||
assert.exists(user._id);
|
||||
assert.isString(user.username);
|
||||
assert.isString(user._id);
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Ви можете виконати `POST` запит до `/api/users/:_id/exercises` з даними форм `description`, `duration` та за бажанням `date`. Якщо дата не вказана, буде використовуватись поточна дата.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}&date=1990-01-01`
|
||||
});
|
||||
assert.isTrue(addRes.ok);
|
||||
if(!addRes.ok) {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`)
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Відповідь, що повернулася від `POST /api/users/:_id/exercises`, буде об'єктом користувача з доданими полями з вправи.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}&date=1990-01-01`
|
||||
});
|
||||
if (addRes.ok) {
|
||||
const actual = await addRes.json();
|
||||
assert.deepEqual(actual, expected);
|
||||
assert.isString(actual.description);
|
||||
assert.isNumber(actual.duration);
|
||||
assert.isString(actual.date);
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Ви можете зробити запит `GET` на `/api/users/:_id/logs`, щоб отримати повний журнал вправ будь-якого користувача.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if (addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
assert.isTrue(logRes.ok);
|
||||
if(!logRes.ok) {
|
||||
throw new Error(`${logRes.status} ${logRes.statusText}`)
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Запит до журналу користувача `GET /api/users/:_id/logs` повертає об'єкт користувача разом з властивістю `count` яка представляє кількість вправ, що належать цьому користувачеві.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if (addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Запит `GET` на `/api/users/:id/logs` поверне об'єкт користувача з `log`, - масивом всіх доданих вправ.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if(addRes.ok){
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
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}`)
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Кожен елемент у масиві `log`, який повернувся з `GET /api/users/:id/logs` це об'єкт, який повинен мати `description` `duration` і `date` властивості.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + `/api/users`, {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if(addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
if(logRes.ok) {
|
||||
const {log} = await logRes.json();
|
||||
const exercise = log[0];
|
||||
assert.exists(exercise);
|
||||
assert.exists(exercise.description);
|
||||
assert.exists(exercise.duration);
|
||||
assert.exists(exercise.date);
|
||||
} else {
|
||||
throw new Error(`${logRes.status} ${logRes.statusText}`);
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`)
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Властивість `description` будь-якого об'єкту в масиві `log`, що повернувся з `GET /api/users/:id/logs` повинен бути рядкового типу.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users/', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if(addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
if(logRes.ok){
|
||||
const {log} = await logRes.json();
|
||||
const exercise = log[0];
|
||||
assert.isString(exercise.description);
|
||||
assert.equal(exercise.description, expected.description);
|
||||
} else {
|
||||
throw new Error(`${logRes.status} ${logRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Властивість `duration` будь-якого об'єкту в масиві `log`, що повернувся з `GET /api/users/:id/logs`, повинна бути числового типу.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users/', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if(addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
if(logRes.ok){
|
||||
const {log} = await logRes.json();
|
||||
const exercise = log[0];
|
||||
assert.isNumber(exercise.duration);
|
||||
assert.equal(exercise.duration, expected.duration);
|
||||
} else {
|
||||
throw new Error(`${logRes.status} ${logRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Властивість `date` будь-якого об'єкту в масиві `log`, що повернувся з `GET /api/users/:id/logs`, повинна бути рядкового типу.. Використовуйте `dateString` формат з `Date` API.
|
||||
|
||||
```js
|
||||
async(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users/', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: `description=${expected.description}&duration=${expected.duration}`
|
||||
});
|
||||
if(addRes.ok) {
|
||||
const logRes = await fetch(url + `/api/users/${_id}/logs`);
|
||||
if(logRes.ok){
|
||||
const {log} = await logRes.json();
|
||||
const exercise = log[0];
|
||||
assert.isString(exercise.date);
|
||||
assert.equal(exercise.date, expected.date);
|
||||
} else {
|
||||
throw new Error(`${logRes.status} ${logRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
};
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Ви можете додати параметри `from`, `to` та `limit` у запит `GET /api/users/:_id/logs` для отримання частини журналу будь-якого користувача. `from` та `to` - дати у форматі `yyyy-mm-dd`. `limit` - це ціле число того, скільки журналів потрібно надіслати назад.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users', {
|
||||
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/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}&date=1990-01-01`
|
||||
});
|
||||
const addExerciseTwoRes = await fetch(url + `/api/users/${_id}/exercises`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `description=${expected.description}&duration=${expected.duration}&date=1990-01-02`
|
||||
});
|
||||
if (addExerciseRes.ok && addExerciseTwoRes.ok) {
|
||||
const logRes = await fetch(
|
||||
url + `/api/users/${_id}/logs?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/users/${_id}/logs?limit=1`
|
||||
);
|
||||
if (limitRes.ok) {
|
||||
const { log } = await limitRes.json();
|
||||
assert.isArray(log);
|
||||
assert.equal(1, log.length);
|
||||
} else {
|
||||
throw new Error(`${limitRes.status} ${limitRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: bd7158d8c443edefaeb5bdff
|
||||
title: Мікросервіс парсингу заголовків запиту
|
||||
challengeType: 4
|
||||
forumTopicId: 301507
|
||||
dashedName: request-header-parser-microservice
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Створіть full stack додаток на JavaScript, який функціонально схожий до цього:<https://request-header-parser-microservice.freecodecamp.rocks/>. Робота над цим проектом залучатиме тебе писати свій код використовуючи один з наступних методів:
|
||||
|
||||
- Клонувати [цей репозиторій з GitHub](https://github.com/freeCodeCamp/boilerplate-project-headerparser/) та локально завершити свій проект.
|
||||
- Використати [наш проект для початківців на Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-headerparser) для завершення свого проекту.
|
||||
- Використати конструктор сайтів на свій вибір для завершення проекту. Впевніться, що ви зберегли всі файли із нашого GitHub репозиторію.
|
||||
|
||||
По завершенню переконайтеся, що працююча демоверсія вашого проекту розміщена у відкритому доступі. Потім введіть його URL-адресу в поле `Solution Link`. За бажанням також можете ввести посилання на вихідний код вашого проекту в полі `GitHub Link`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Вам необхідно вказати свій власний проект, а не приклад URL-адреси.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
assert(
|
||||
!/.*\/request-header-parser-microservice\.freecodecamp\.rocks/.test(
|
||||
getUserInput('url')
|
||||
)
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Запит на `/api/whoami` повинен повернути об'єкт JSON з вашою IP-адресою у ключі `ipaddress`.
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/whoami').then(
|
||||
(data) => assert(data.ipaddress && data.ipaddress.length > 0),
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Запит на `/api/whoami` повинен повернути об’єкт JSON з вашою бажаною мовою у ключі `language`.
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/whoami').then(
|
||||
(data) => assert(data.language && data.language.length > 0),
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Запит на `/api/whoami` повинен повернути об'єкт JSON з вашим програмним забезпеченням у ключі `software`.
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/whoami').then(
|
||||
(data) => assert(data.software && data.software.length > 0),
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,79 @@
|
||||
---
|
||||
id: 587d7fb1367417b2b2512bf4
|
||||
title: Ланцюгове підпрограмне забезпечення для створення сервера часу
|
||||
challengeType: 2
|
||||
forumTopicId: 301510
|
||||
dashedName: chain-middleware-to-create-a-time-server
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Програмне забезпечення можна підключити за певним маршрутом за допомогою `app.METHOD(path, middlewareFunction)`. Підрограмне забезпечення також може бути поєднане всередині визначення маршруту.
|
||||
|
||||
Розглянемо наступний приклад:
|
||||
|
||||
```js
|
||||
app.get('/user', function(req, res, next) {
|
||||
req.user = getTheUserSync(); // Hypothetical synchronous operation
|
||||
next();
|
||||
}, function(req, res) {
|
||||
res.send(req.user);
|
||||
});
|
||||
```
|
||||
|
||||
Цей підхід корисний для поділу серверних операцій на менші одиниці. Це призводить до кращої структури додатків, та можливості повторного використання коду в різних місцях. Цей підхід також може бути використаний для проведення деякої перевірки даних. У кожній точці стеку підпрограмного забезпечення ви можете заблокувати виконання поточного ланцюга та передати управління функціями, спеціально розробленими для обробки помилок. Або ви можете передати контроль до наступних відповідних маршрутів, щоб впоратися з особливими випадками. Ми побачимо як у розділі розширений Експрес.
|
||||
|
||||
# --instructions--
|
||||
|
||||
У маршруті `app.get('/now', ...)` об'єднайте підппрограмне забезпечення та остаточний обробник. У функції підпрограмне забезпечення ви повинні додати поточний час до об’єкта запиту в `req.time` ключі. Ви можете використати `new Date().toString()`. В обробнику, відповідайте на об'єкт JSON, використовуючи структуру `{time: req.time}`.
|
||||
|
||||
**Примітка:** Тест не пройде, якщо ви не об'єднаєте підпрограмне забезпечення. Якщо ви встановите функцію десь в іншому місці, тест зазнає невдачі, навіть якщо результат виводу правильний.
|
||||
|
||||
# --hints--
|
||||
|
||||
Кінцева точка /now повинна бути підключена до проміжного програмного забезпечення
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
/now кінцева точка повинна повернути час, який відтепер складає +/-20 сек
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: 587d7fb2367417b2b2512bf8
|
||||
title: Отримання даних з POST запитів
|
||||
challengeType: 2
|
||||
forumTopicId: 301511
|
||||
dashedName: get-data-from-post-requests
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Встановіть POST обробник за шляхом `/name`. Це той самий шлях, що і раніше. Ми підготували форму на головній сторінці html. Вона надсилатиме такі ж дані, як і у вправі 10 (рядок запиту). Якщо body-parser налаштований правильно, ви повинні знайти параметри в об’єкті `req.body`. Подивіться на простий приклад з бібліотеки:
|
||||
|
||||
<blockquote>маршрут: POST '/library'<br>urlencoded_body: userId=546&bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
Дайте відповідь тим же об’єктом JSON, як і раніше: `{name: 'firstname lastname'}`. Перевірте, чи ваша кінцева точка працює з використанням Html-форми, яку ми надали на головній сторінці додатку.
|
||||
|
||||
Порада: є кілька інших способів, крім GET та POST. І за загальноприйнятим правилом існує відповідність між дієсловом http та операцією, яку ви будете виконувати на сервері. Стандартна відповідність наступна:
|
||||
|
||||
POST (іноді PUT) - Створити новий ресурс, використовуючи інформацію, що надсилається з запитом,
|
||||
|
||||
GET - Прочитати існуючий ресурс не змінюючи його,
|
||||
|
||||
PUT або PATCH (іноді POST) - Оновити ресурс за допомогою відправлених даних,
|
||||
|
||||
DELETE => Видалити ресурс.
|
||||
|
||||
Є також кілька інших методів, які використовуються для узгодження зв'язку з сервером. За винятком GET, всі інші перераховані вище методи, можуть мати корисне навантаження (тобто дані на вміст запиту). Проміжне програмне забезпечення Body-parser також працює з цими методами.
|
||||
|
||||
# --hints--
|
||||
|
||||
Тест 1: Ваша кінцева точка API повинна співпадати з правильним іменем
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Тест 2: Ваша кінцева точка API повинна співпадати з правильним іменем
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: 587d7fb2367417b2b2512bf6
|
||||
title: Отримання вхідних даних параметра запиту від клієнта
|
||||
challengeType: 2
|
||||
forumTopicId: 301512
|
||||
dashedName: get-query-parameter-input-from-the-client
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Інший поширений шлях отримати вхідні дані від клієнта - це кодування даних шляхом маршруту, використовуючи рядок запиту. Рядок запиту обмежений знаком питання (?), і включає в себе поле=пари значення. Кожна пара розділена амперсандами (&). Експрес може проаналізувати дані з рядка запиту і заповнити об’єкт `req.query`. Деякі символи, як-от відсотки (%), не можуть бути в URL-адресі і повинні бути закодовані в іншому форматі перед їх відправкою. Якщо ви використовуєте API з JavaScript, ви можете використовувати певні методи для кодування/декодування цих символів.
|
||||
|
||||
<blockquote>маршрут: '/library'<br>actual_request_URL: '/library?userId=546&bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
# --instructions--
|
||||
|
||||
Створіть кінцеву точку API, монтовану в `GET /name`. Відреагуйте JSON документом, використовуючи структуру `{ name: 'firstname lastname'}`. Перший і останній параметри імені повинні бути закодовані в рядку запиту, наприклад `?first=firstname&last=lastname`.
|
||||
|
||||
**Примітка:** У цьому завданні ви будете отримувати дані з POST-запиту, з того ж `/name` маршруту. За бажанням, можете використовувати `app.route(path).get(handler).post(handler)`. Цей синтаксис дозволяє об'єднувати різні обробники дієслів на тому ж шляху. Вам не знадобиться багато друкувати і ви матимете чистіший код.
|
||||
|
||||
# --hints--
|
||||
|
||||
Тест 1: Ваша кінцева точка API повинна співпадати з правильним іменем
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Тест 2: Ваша кінцева точка API повинна співпадати з правильним іменем
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: 587d7fb2367417b2b2512bf5
|
||||
title: Отримати ввід параметру маршруту від Клієнта
|
||||
challengeType: 2
|
||||
forumTopicId: 301513
|
||||
dashedName: get-route-parameter-input-from-the-client
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Створюючи API, ми повинні дозволити користувачам спілкуватися з нами, на тему того, що вони хочуть отримати від наших послуг. Наприклад, якщо клієнт запитує інформацію про користувача, збереженого в базі даних, їм потрібно мати шлях повідомити нам, який саме користувач їх цікавить. Одним із можливих способів досягнення цього результату є використання параметрів маршруту. Параметри маршруту мають назву сегментів URL, розділені косою рискою (/). Кожен сегмент фіксує значення частини URL, який відповідає його позиції. Збережені значення можна знайти в об’єкті `req.params`.
|
||||
|
||||
<blockquote>маршрут: '/user/:userId/book/:bookId'<br>actual_request_URL: '/user/546/book/6754' <br>req.params: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
# --instructions--
|
||||
|
||||
Побудуйте ехо-сервер, вмонтований у маршрут `GET /:word/echo`. Відреагуйте JSON об'єктом, використовуючи структуру `{echo: word}`. Ви можете знайти слово, яке потрібно повторити у `req.params.word`. Ви можете перевірити свій маршрут з адресної стрічки вашого браузера, відвідавши деякі відповідні маршрути, наприклад `your-app-rootpath/freecodecamp/echo`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Тест 1: Ваш ехо сервер повинен коректно повторити слова
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Тест 2: Ваш ехо сервер повинен коректно повторити слова
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 587d7fb1367417b2b2512bf3
|
||||
title: Реалізація підпрограмного забезпечення з журналу запитів кореневого рівня
|
||||
challengeType: 2
|
||||
forumTopicId: 301514
|
||||
dashedName: implement-a-root-level-request-logger-middleware
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Раніше ви ознайомились з функцією підпрограмного забезпечення `express.static()`. А зараз саме час більш детально розглянути, що таке підпрограмне забезпечення. Функції підпрограмного забезпечення – це функції, які мають 3 аргументи: об'єкт запиту, об'єкт відповіді й наступна функція циклу запиту-відповіді додатку. Ці функції виконують певний код, який може мати побічний ефект на додаток і зазвичай додає інформацію до об'єктів запиту й відповіді. Ще вони можуть закінчити цикл, надіславши відповідь, коли стикаються з певними умовами. Якщо після завершення вони не надсилають відповідь, вони починають виконувати наступну функцію в стеку. Це запускає третій аргумент – `next()`.
|
||||
|
||||
Розглянемо наступний приклад:
|
||||
|
||||
```js
|
||||
function(req, res, next) {
|
||||
console.log("I'm a middleware...");
|
||||
next();
|
||||
}
|
||||
```
|
||||
|
||||
Припустімо, ви підключили цю функцію до маршруту. Коли запит збігається з маршрутом, відображається рядок “I’m a middleware…“, потім виконується наступна функція в стеку. У цій вправі ви створите підпрограмне забезпечення кореневого рівня. Як ви бачили в завданні 4, щоб встановити функцію підпрограмного забезпечення на кореневий рівень, ви можете скористатись методом `app.use(<mware-function>)`. У такому випадку ця функція виконається для всіх запитів, але ви також можете встановити конкретніші умови. Наприклад, якщо ви хочете виконати функцію лише для запитів POST, можна скористатись `app.post(<mware-function>)`. Аналогічні методи існують для всіх дієслів HTTP (GET, DELETE, PUT, …).
|
||||
|
||||
# --instructions--
|
||||
|
||||
Створіть простий журнал. Для кожного запиту в консолі має записуватись рядок в наступному форматі: `method path - ip`. Приклад виглядатиме так: `GET /json - ::ffff:127.0.0.1`. Зверніть увагу, що між `method` і `path` є пробіл, і що дефіс, який розділяє `path` і `ip`, виділено пробілами з обох сторін. Ви можете дізнатись метод запиту (дієслово http), відносний шлях маршруту й ip абонента з об'єкта запиту, скориставшись `req.method`, `req.path` і `req.ip`. Коли закінчите, не забудьте запустити `next()`, бо інакше ваш сервер заблокується назавжди. Обов'язково відкрийте “Журнал“ і подивіться, що відбувається, коли надходять певні запити.
|
||||
|
||||
**Note:** Вираз оцінює функції в тому ж порядку, в якому вони з'являються в коді. Це стосується й підпрограмного забезпечення. Якщо ви хочете, щоб це працювало для всіх маршрутів, встановіть його перед ними.
|
||||
|
||||
# --hints--
|
||||
|
||||
Підпрограмне забезпечення журналу кореневого рівня має бути активним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 587d7fb0367417b2b2512bed
|
||||
title: Знайомство з консоллю Node
|
||||
challengeType: 2
|
||||
forumTopicId: 301515
|
||||
dashedName: meet-the-node-console
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Робота над цими завданнями передбачає написання коду одним із таких методів:
|
||||
|
||||
- Клонуйте [ цей репозиторій](https://github.com/freeCodeCamp/boilerplate-express/) та виконайте ці завдання локально.
|
||||
- Використовуйте [ наш стартовий проєкт Replit](https://replit.com/github/freeCodeCamp/boilerplate-express) для виконання цих завдань.
|
||||
- Для виконання проєкту скористуйтеся будь-яким конструктором сайтів на ваш розсуд. Впевніться, що ви маєте усі файли з нашого GitHub репозиторію.
|
||||
|
||||
Коли ви завершили, переконайтеся, що демоверсія вашого проєкту розміщена у відкритому доступі. Потім введіть URL-адресу проєкту у поле `Solution Link`.
|
||||
|
||||
Під час процесу розробки важливо перевіряти, що відбувається у коді.
|
||||
|
||||
Node - це всього лише середовище JavaScript. Як у клієнтському JavaScript, ви можете використовувати консоль для відображення корисної інформації для налагодження недоліків. На вашому локальному комп'ютері ви побачите вивід консолі в терміналі. На Replit термінал відкритий на правій панелі за замовчуванням.
|
||||
|
||||
Ми рекомендуємо тримати термінал відкритим під час роботи над цими завданнями. Читаючи вивід в терміналі, ви можете побачити будь-які помилки, що можуть виникнути.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Модифікуйте `myApp.js` для виводу "Hello World" на консоль.
|
||||
|
||||
# --hints--
|
||||
|
||||
`"Hello World"` має бути в консолі
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 587d7fb0367417b2b2512bef
|
||||
title: Робота з файлами у форматі HTML
|
||||
challengeType: 2
|
||||
forumTopicId: 301516
|
||||
dashedName: serve-an-html-file
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Ви можете відповідати на запити файлом, використовуючи метод `res.sendFile(path)`. Ви можете додати його до обробника маршрутів `app.get('/', ...)`. Насправді цей метод встановлює відповідні заголовки, які вказуватимуть вашому браузеру, як обробляти файл, який потрібно надіслати, відповідно до його типу. Потім він (метод) файл буде прочитаний та надісланий. Для цього методу потрібен абсолютний шлях до файлу. Ми рекомендуємо вам використовувати глобальну змінну Node `__dirname` для обчислення шляху, як вказано нижче:
|
||||
|
||||
```js
|
||||
absolutePath = __dirname + relativePath/file.ext
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Надішліть файл `/views/index.html` у відповідь на запит GET шляхом `/`. Якщо ви переглядаєте свій додаток у реальному часі, ви можете побачити великий заголовок HTML (і форму, яку ми будемо використовувати пізніше…), без стилю.
|
||||
|
||||
**Примітка:** Ви можете редагувати результат попереднього завдання або створити нове. Якщо ви створюєте нове рішення, майте на увазі, що Express оцінює маршрути зверху вниз і запускає обробник для першого збігу. Ви повинні прокоментувати попереднє рішення, інакше сервер буде продовжувати відповідати за допомогою рядку.
|
||||
|
||||
# --hints--
|
||||
|
||||
Ваш додаток повинен використовувати файл 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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 587d7fb1367417b2b2512bf1
|
||||
title: Передавання JSON за певним маршрутом
|
||||
challengeType: 2
|
||||
forumTopicId: 301517
|
||||
dashedName: serve-json-on-a-specific-route
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
У той час як HTML сервер передає HTML, API передає дані. <dfn>REST</dfn> (REpresentational State Transfer) API дозволяє обмінюватися даними простим способом, без необхідності, щоб клієнти знали будь-які деталі про сервер. Клієнту лише потрібно знати, де знаходиться ресурс (URL-адреса), та дію, яку він хоче на ньому виконати (дієслово). Дієслово GET використовується, коли ви отримуєте деяку інформацію, нічого не змінюючи. У наші часи JSON є найкращим форматом даних для переміщення інформації через інтернет. Простіше кажучи, JSON - це зручний спосіб представити об’єкт JavaScript у вигляді рядка, тому його можна легко передати.
|
||||
|
||||
Створімо простий API, створивши маршрут, який відповідає JSON на шляху `/json`. Ви можете це зробити, як зазвичай, за допомогою метода `app.get()`. Усередині обробника маршруту використовуйте метод `res.json()`, передаючи об'єкт як аргумент. Це метод закриває цикл запит-відповідь, повертаючи дані. По суті, він перетворює дійсний об’єкт JavaScript object у рядок, потім встановлює відповідні заголовки, щоб повідомити браузеру, що ви використовуєте JSON, і надсилає дані назад. Допустимий об'єкт має звичайну структуру `{key: data}`. `data` може бути числом, рядком, вкладеним об'єктом або масивом. `data` також може бути змінною або результатом виклику функції, в цьому випадку вони будуть оцінені перед перетворенням у рядок.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Передайте об'єкт `{"message": "Hello json"}` у форматі JSON як відповідь на GET-запити до маршруту `/json`. Потім вказуючи вашому браузері `your-app-url/json`, ви повинні побачити повідомлення на екрані.
|
||||
|
||||
# --hints--
|
||||
|
||||
Кінцева точка `/json` має використовувати json-об'єкт `{"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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 587d7fb0367417b2b2512bf0
|
||||
title: Обслуговування статичного контенту
|
||||
challengeType: 2
|
||||
forumTopicId: 301518
|
||||
dashedName: serve-static-assets
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Як правило, HTML-сервер має один чи кілька каталогів, доступних для користувача. Туди можна помістити статичний контент, необхідних для Вашого застосунку (таблиці стилів, скрипти, зображення).
|
||||
|
||||
В Express цю функцію можна підключити за допомогою проміжного програмного забезпечення `express.static(path)`, де параметр `path` - це абсолютний шлях до файлу з цим контентом.
|
||||
|
||||
Якщо Ви ніколи не чули про підпрограмне забезпечення, не хвилюйтеся. Пізніше ми детально його розглянемо. Загалом, підпрограмне забезпечення — це функції, що перехоплюють маршрутизатори, прикріплюючи певну інформацію. Підпрограмне забезпечення підключається за допомогою методу `app.use(path, middlewareFunction)`. Перший аргумент `path` є необов'язковим. Якщо цей аргумент не передається, підпрограмне забезпечення буде виконуватися для всіх запитів.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Підключіть підпрограмне забезпечення `express.static()` до `/public` шляху з `app.use()`. Абсолютним шляхом до папки assets є `__dirname + /public`.
|
||||
|
||||
Тепер Ваш застосунок зможе обслуговувати CSS таблиці стилів. Зверніть увагу, що посилання на файл `/public/style.css` знаходиться у папці `/views/index.html` шаблону проєктування. Тепер Ваша головна сторінка виглядатиме краще!
|
||||
|
||||
# --hints--
|
||||
|
||||
Ваш застосунок обслуговуватиме файли з каталогу `/public` до шляху `/public`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/public/style.css').then(
|
||||
(data) => {
|
||||
assert.match(
|
||||
data,
|
||||
/body\s*\{[^\}]*\}/,
|
||||
'Your app does not serve static assets'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 587d7fb0367417b2b2512bee
|
||||
title: Запуск робочого експрес-серверу
|
||||
challengeType: 2
|
||||
forumTopicId: 301519
|
||||
dashedName: start-a-working-express-server
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
У перших двох рядках файлу `myApp.js`, ви можете побачити, як легко створити об’єкт програми Express. Цей об’єкт має кілька методів, і ви багато із них вивчите за допомогою цих завдань. Одним із фундаментальних методів є `app.listen(port)`. Він повідомляє вашому серверу прослуховувати певний порт, переводячи його в робочий стан. З міркувань тестування нам потрібно, щоб програма працювала у фоновому режимі, тому ми для вас додали цей метод у файл `server.js`.
|
||||
|
||||
Давайте обслужимо наш перший рядок! В Express маршрути мають наступну структуру:`app.METHOD(PATH, HANDLER)`. METHOD - це метод http у нижньому регістрі. PATH - це відносний шлях на сервері (це може бути рядок або навіть регулярний вираз). HANDLER - це функція, яка викликає Express при узгодженні маршруту. Обробники приймають форму `function(req, res) {...}`, де req - об'єкт запиту, а res - об'єкт відповіді. Наприклад, обробник
|
||||
|
||||
```js
|
||||
function(req, res) {
|
||||
res.send('Response String');
|
||||
}
|
||||
```
|
||||
|
||||
буде обслуговувати рядок 'Рядок відповіді'.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Використовуйте метод `app.get()`, щоб обслужити рядок "Hello Express" для GET запитів, які відповідають шляху `/` (root). Переконайтеся, що ваш код працює, переглянувши журнали, а потім перегляньте результати у попередньому перегляді, якщо ви використовуєте Replit.
|
||||
|
||||
**Примітка:** Весь код для цих уроків слід додати між кількома рядками коду, з яких ми починали.
|
||||
|
||||
# --hints--
|
||||
|
||||
Ваш додаток має обслуговувати рядок "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 587d7fb2367417b2b2512bf7
|
||||
title: Обробка POST запитів за допомогою body-parser
|
||||
challengeType: 2
|
||||
forumTopicId: 301520
|
||||
dashedName: use-body-parser-to-parse-post-requests
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Крім GET, є ще одне спільне дієслово HTTP, це POST. POST - це типовий метод для надсилання даних клієнта з HTML формами. У методі REST, POST використовується для відправки даних, щоб створити нові елементи в базі даних (новий користувач або новий допис). Ви не зобов'язані мати базу даних у цьому проєкті, але ви все-таки дізнаєтесь, як опрацьовувати запити POST.
|
||||
|
||||
У таких запитах дані не з'являються в URL, він прихований у тілі запиту. Тіло є частиною HTTP-запиту, а також називається корисним навантаженням. Незважаючи на те, що дані не видимі в URL, це не означає, що вони приватні. Щоб зрозуміти чому, подивіться на необроблений вміст HTTP-запиту POST:
|
||||
|
||||
```http
|
||||
POST /path/subpath HTTP/1.0
|
||||
From: john@example.com
|
||||
User-Agent: someBrowser/1.0
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 20
|
||||
|
||||
name=John+Doe&age=25
|
||||
```
|
||||
|
||||
Як ви можете побачити, тіло закодоване як рядок запиту. Це типовий формат, який використовується у HTML-формах. За допомогою Ajax, ви також можете використати JSON для обробки даних, що мають більш складну структуру. Існує також інший тип кодування: multipart/form-data. Цей файл використовується для завантаження бінарних файлів. У цій вправі ви будете використовувати тіло, кодоване посиланням. Щоб аналізувати дані, отримані з POST-запитів, необхідно встановити пакет `body-parser`. Цей пакет дозволяє використовувати низку підпрограмного забезпечення, який може декодувати дані в різних форматах.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Встановіть модуль `body-parser` до вашого `package.json`. Тоді `require` його у верхній частині файлу. Збережіть його у змінній під назвою `bodyParser`. Проміжне програмне забезпечення, що має обробити Url-закодовані дані, повертається за допомогою `bodyParser.urlencoded({extended: false})`. Передайте функцію, повернуту попереднім викликом типу `app.use()`. Зазвичай підпрограмне забезпечення потрібно встановити перед маршрутами, які залежать від нього.
|
||||
|
||||
**Note:** `extended` це опція конфігурації, яка вказує `body-parser`, який парсинг необхідно використати. Коли `extended=false` він використовує класичне кодування `querystring` бібліотеки. Коли `extended=true` він використовує `qs` бібліотеку для парсингу.
|
||||
|
||||
При використанні `extended=false`, значення можуть бути тільки рядками або масивами. Об'єкт повертається, коли використання `querystring` не успадковується прототипно від `Object` JavaScript за замовчування, і означає, що функції `hasOwnProperty` та `toString` не будуть доступні. Розширена версія дозволяє підвищити гнучкість даних, але вона перевершує JSON.
|
||||
|
||||
# --hints--
|
||||
|
||||
Проміжне програмне забезпечення 'body-parser' має бути встановлено
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 587d7fb1367417b2b2512bf2
|
||||
title: Використання .env-файлу
|
||||
challengeType: 2
|
||||
forumTopicId: 301521
|
||||
dashedName: use-the--env-file
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Файл `.env` - це прихований файл, який використовується для передачі змінних оточень у вашому додатку. Цей файл є таємним, ніхто, крім вас, не може отримати до нього доступ, та він може використовуватися для зберігання даних, які ви хочете залишити конфіденційними або прихованими. Наприклад, ви можете зберігати API-ключі з зовнішніх сервісів або URI вашої бази даних. Ви також можете використовувати його для зберігання параметрів конфігурації. Налаштовуючи параметри конфігурації, ви можете змінити поведінку вашої програми без необхідності переписувати код.
|
||||
|
||||
Змінні оточення доступні з додатку як `process.env.VAR_NAME`. Об'єкт `process.env` є глобальним об'єктом Node, а змінні передаються у вигляді рядків. Згідно з правилами, ідентифікатори змінних пишуться у верхньому регістрі, а слова поділяються знаком підкресленням. `.env` - це файл оболонки, тому вам не потрібно укладати імена або значення в лапки. Також важливо відзначити, що не має бути пробілу навколо знаку рівності, коли ви привласнюєте значення змінним, наприклад, `VAR_NAME=value`. Зазвичай ви ставите визначення кожної змінної в окремий рядок.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додаймо змінну оточення в якості параметра конфігурації.
|
||||
|
||||
Створіть файл `.env` в основі каталогу вашого проєкту та збережіть в ньому змінну `MESSAGE_STYLE=uppercase`.
|
||||
|
||||
Потім, в обробнику маршруту `/json` GET, який ви створили в останній задачі, перетворіть повідомлення об'єкта-відповіді у верхній регістр, якщо `process.env.MESSAGE_STYLE` дорівнює `uppercase`. Об'єкт відповіді має бути `{"message": "Hello json"}` або `{"message": "HELLO JSON"}`, в залежності від значення `MESSAGE_STYLE`.
|
||||
|
||||
**Примітка:** Якщо ви використовуєте Replit, ви не можете створити файл `.env`. Замість цього використовуйте вбудовану вкладку <dfn>SECRETS</dfn> для додавання змінної.
|
||||
|
||||
При локальній роботі вам знадобиться пакет `dotenv`. Він завантажує змінні середовища з вашого `.env` файлу в `process.env`. Встановіть його з `npm install dotenv`. Тоді, зверху вашого `myApp.js` файлу, оберіть імпортувати та завантажити змінні з `require('dotenv').config()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Відповідь кінцевої точки `/json` має змінюватися відповідно до змінної оточення `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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 587d7fb3367417b2b2512bfc
|
||||
title: Додати опис до вашого package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301522
|
||||
dashedName: add-a-description-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Наступна частина хорошого файлу package.json - це `description` поля, якому належить короткий, але інформативний опис вашого проєкту.
|
||||
|
||||
Якщо ви плануєте колись опублікувати пакет на npm, то він є рядком, що повинен продати вашу ідею користувачам, якщо вони вирішуватимуть чи встановлювати ваш пакет чи ні. Однак, це не єдиний випадок використання для опису, це чудовий спосіб узагальнити те, що робить проект. Це також важливо в будь-якому проєкті Node.js, щоб допомогти іншим розробникам, майбутнім творцям чи навіть самому собі швидко зрозуміти проєкт.
|
||||
|
||||
Незалежно від того, що ви плануєте для свого проєкту, опис є безумовно рекомендованим. Ось приклад:
|
||||
|
||||
```json
|
||||
"description": "A project that does something awesome",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте `description` до файлу package.json вашого проєкту.
|
||||
|
||||
**Примітка:** Пам'ятайте: використовувати подвійні лапки для полів (") і коми (,) для розділення полів.
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json повинен мати дійсний ключ "опис"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 587d7fb4367417b2b2512bfe
|
||||
title: Додайте ліцензію до вашого package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301523
|
||||
dashedName: add-a-license-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Поле `license` дозволяє інформувати користувачів, які дії вони можуть виконувати з вашим проектом.
|
||||
|
||||
Деякі загальні ліцензії для проектів з відкритим кодом містять MIT та BSD. Ліцензійна інформація не являється обов'язковою і закони про авторські права в більшості країн дадуть вам право власності на те, що ви створюєте за замовчуванням. Проте завжди рекомендується чітко вказувати дії, які користувачам дозволено і не дозволено виконувати. Нижче наведено приклад, як виглядає поле ліцензії:
|
||||
|
||||
```json
|
||||
"license": "MIT",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Заповніть поле `license` для файлу package.json вашого проєкту, як вважаєте за потрібне.
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json повинен містити допустимий ключ ліцензії
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 587d7fb4367417b2b2512bff
|
||||
title: Додати опис до вашого package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301525
|
||||
dashedName: add-a-version-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`version` є одним з необхідних полів вашого package.json файлу. Це поле описує поточну версію вашого проекту. Ось приклад:
|
||||
|
||||
```json
|
||||
"version": "1.2.0",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте `version` до файлу package.json вашого проєкту.
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json повинен мати допустимий ключ "версія"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: 587d7fb4367417b2b2512bfd
|
||||
title: Додати ключові слова до вашого package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301526
|
||||
dashedName: add-keywords-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Значення `keywords` - це місце, де ви можете описати ваш проєкт, використовуючи відповідні ключові слова. Ось приклад:
|
||||
|
||||
```json
|
||||
"keywords": [ "descriptive", "related", "words" ],
|
||||
```
|
||||
|
||||
Як бачите, це поле структуровано як масив подвійних цитованих рядків.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте масив відповідних рядків у `keywords` у файлі package.json вашого проєкту.
|
||||
|
||||
Одне з ключових слів має бути "freecodecamp".
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json повинен мати допустимий ключ "ключові слова"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Поле "ключові слова" має бути масивом
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
"ключові слова" мають включати "freecodecamp"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: 587d7fb4367417b2b2512c00
|
||||
title: Розпакуйте ваш проєкт із зовнішніми пакетами через npm
|
||||
challengeType: 2
|
||||
forumTopicId: 301527
|
||||
dashedName: expand-your-project-with-external-packages-from-npm
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Однією з найважливіших підстав для використання менеджера пакетів є їх потужне управління залежностями. Npm автоматично встановлює всі необхідні елементи під час встановлення проекту на новому комп'ютер і позбавляє вас необхідності встановлювати все кожного разу вручну. Але як npm може отримати інформацію, чого потребує ваш проєкт? Знайдіть розділ `dependencies` у вашому файлі package.json.
|
||||
|
||||
У цьому розділі зберігаються пакети, необхідні для вашого проєкту, в наступному форматі:
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"package-name": "version",
|
||||
"express": "4.14.0"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте версію пакету "2.14.0" у поле `dependencies` вашого файлу package.json.
|
||||
|
||||
**Примітка:** Момент - це зручна бібліотека для дій з часом і днями.
|
||||
|
||||
# --hints--
|
||||
|
||||
"взаємозв'язки" повинні включати "момент"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
версія "момент" повинна бути "2.14.0"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 587d7fb3367417b2b2512bfb
|
||||
title: 'Як використовувати package.json, ядро будь-якого Node.js проєкту або npm пакету'
|
||||
challengeType: 2
|
||||
forumTopicId: 301528
|
||||
dashedName: how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Робота над цими завданнями включатиме написання вашого коду з використанням одного з наступних методів:
|
||||
|
||||
- Створіть [цей GitHub репозитарій](https://github.com/freeCodeCamp/boilerplate-npm/) і завершіть локально ці завдання.
|
||||
- Використовуйте [ наш стартовий проєкт Replit](https://replit.com/github/freeCodeCamp/boilerplate-npm) для виконання цих завдань.
|
||||
- Для завершення проєкту користуйтеся вибраним вами конструктором сайту. Переконайтеся, що ви зберегли всі файли з нашого репозиторію GitHub.
|
||||
|
||||
Коли ви завершили, переконайтеся, що ця демоверсія вашого проєкту розміщена у відкритому доступі. Потім введіть URL-адресу в поле `Solution Link`. За бажанням також можете ввести посилання на вихідний код вашого проєкту в полі `GitHub Link`.
|
||||
|
||||
Файл `package.json` є центром будь-якого проєкту Node.js або npm пакету. Він зберігає інформацію про ваш проєкт, схожий на те, як <заголовок> секція HTML-документа описує вміст веб-сторінки. Він складається з одного об'єкту JSON, де інформація зберігається у парах ключ-значення. Є лише два обов'язкові поля; "ім'я" та "версія", але дуже добре практикуватися надавати додаткову інформацію про ваш проєкт, який може бути корисний майбутнім користувачам або керівникам.
|
||||
|
||||
Якщо подивитесь на дерево файлів вашого проєкту, то знайдете файл package.json на верхньому рівні дерева. Це файл, який ви будете покращуватись у наступних парах завдань.
|
||||
|
||||
Одне з найпоширеніших відомостей у цьому файлі є полем `author`. Він вказує на те, хто створив проект, і може складатися з рядка або об'єкта з контактом або іншими деталями. Об’єкт рекомендований для більших проєктів, але простий рядок, як наступний приклад, працюватиме для цього проєкту.
|
||||
|
||||
```json
|
||||
"author": "Jane Doe",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте ваше ім'я як `author` проєкту у файл package.json.
|
||||
|
||||
**Примітка:** Пам'ятайте, що ви пишете JSON, бо всі назви полів повинні використовувати подвійні лапки (") і бути розділені комою (,).
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json повинен мати допустимий ключ "автор"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: 587d7fb5367417b2b2512c01
|
||||
title: Керування залежностями npm шляхом розуміння семантичної версії
|
||||
challengeType: 2
|
||||
forumTopicId: 301529
|
||||
dashedName: manage-npm-dependencies-by-understanding-semantic-versioning
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Версії `Versions` пакетів npm у розділі залежностей вашого файлу package.json відповідають тому, що називається семантичним керуванням версій (SemVer), галузевим стандартом керування версій програмного забезпечення, спрямованим на спрощення керування залежностями. Бібліотеки, фреймворки чи інші інструменти, опубліковані на npm, повинні використовувати SemVer, щоб чітко повідомляти, що може змінитись у проєктах, якщо вони оновляться.
|
||||
|
||||
Знання SemVer може бути корисним при розробці програмного забезпечення, яке використовує зовнішні залежності (що ви майже завжди і робите). Одного дня ваше розуміння цих цифр захистить вас від випадкового внесення кардинальних змін у ваш проєкт без розуміння, чому речі, які працювали вчора, раптово не працюють сьогодні. Ось як працює керування семантичними версіями, згідно з інформацією на офіційному веб-сайті:
|
||||
|
||||
```json
|
||||
"package": "MAJOR.MINOR.PATCH"
|
||||
```
|
||||
|
||||
ОСНОВНА версія має збільшуватися, коли ви вносите несумісні зміни в API. ДРУГОРЯДНА версія має збільшуватися, коли ви додаєте функціональні можливості у зворотно сумісному порядку. Версія PATCH повинна збільшуватись, коли ви робите виправлення помилок зі зворотною сумісністю. Це означає, що ПАТЧІ - це виправлення помилок, а ДРУГОРЯДНІ версії додають нові функції, але жодна з них не порушує те, що функціонувало раніше. Нарешті, ОСНОВНІ версії додають зміни, не сумісні з попередніми версіями.
|
||||
|
||||
# --instructions--
|
||||
|
||||
У розділі залежностей вашого файлу package.json, змініть версію моменту `version`, щоб вона відповідала ОСНОВНІЙ версії 2, ДРУГОРЯДНІЙ версії 10 та версії ПАТЧА 2
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" повинні містити "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
версія "moment" повинна бути "2.10.2"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 587d7fb5367417b2b2512c04
|
||||
title: Видалення пакету із залежностей
|
||||
challengeType: 2
|
||||
forumTopicId: 301530
|
||||
dashedName: remove-a-package-from-your-dependencies
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Ви вже протестували кілька способів, як можна керувати залежностями Вашого проєкту за допомогою розділу dependencies файлу package.json. Ви також додали зовнішні пакети до Вашого файлу і навіть задали npm бажані версії за допомогою спеціальних символів: тильда та карет.
|
||||
|
||||
Але що робити, якщо Ви бажаєте видалити більше не потрібний зовнішній пакет? Певно, Ви вже здогадалися, треба просто видалити відповідну пару "ключ-значення" цього пакету із залежностей.
|
||||
|
||||
Видалення інших полів package.json також здійснюється цим методом
|
||||
|
||||
# --instructions--
|
||||
|
||||
Видаліть пакет moment із залежностей.
|
||||
|
||||
**Примітка:** Переконайтесь, що після видалення пакету у Вас вказано правильну кількість ком.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" не має містити "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 587d7fb5367417b2b2512c03
|
||||
title: Використовуйте Caret-Character для використання останньої мінорної версії залежностей
|
||||
challengeType: 2
|
||||
forumTopicId: 301531
|
||||
dashedName: use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Подібно символу тильда, про який ми дізналися в останньому завданні, npm дозволяє встановити найновіший ПАТЧ для залежності, символ карет (`^`) дозволяє npm також встановлювати майбутні оновлення. Відмінність полягає в тому, що символ карет дозволяє і ДРУГОРЯДНІ оновлення, і ПАТЧІ.
|
||||
|
||||
Ваша поточна версія моменту повинна бути "~ 2.10.2", що дозволяє npm встановлювати останню версію 2.10.x. Якби ви використовували символ (^) як префікс версії замість цього, npm було б дозволено оновлюватись до будь-якої версії 2.xx.
|
||||
|
||||
```json
|
||||
"package": "^1.3.8"
|
||||
```
|
||||
|
||||
Це б дозволило оновлювати будь-яку версію 1.xx пакета.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Використовуйте символ (`^`), щоб встановити префікс версії моменту у ваших залежностях і дозволити npm оновити його до будь-якого оновлення ДРУГОРЯДНОЇ версії.
|
||||
|
||||
**Примітка:** Номери версій не слід змінювати.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" повинні містити "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
версія "moment" повинна бути "^2.x.x"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 587d7fb5367417b2b2512c02
|
||||
title: Використовуйте символ тильди (~), щоб завжди мати доступ до останньої версії залежностей Patch
|
||||
challengeType: 2
|
||||
forumTopicId: 301532
|
||||
dashedName: use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
В останньому завданні ви сказали npm включати тільки конкретну версію пакету. Це корисний спосіб призупинити блокування ваших залежностей, якщо вам потрібно переконатися, що різні частини вашого проєкту залишаються сумісними одна з одною. Але в більшості випадків ви не захочете пропустити виправлення помилок, оскільки вони часто містять важливі патчі безпеки і (як можна сподіватися) не порушують при цьому речі.
|
||||
|
||||
Щоб npm залежність оновилася до останньої версії PATCH, можна встановити префікс версії залежностей з символом тильди (`~`). Ось приклад оновлення для будь-якої версії 1.3.x.
|
||||
|
||||
```json
|
||||
"package": "~1.3.8"
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
У файлі package.json вашим поточним правилом для моменту оновлення npm є використання конкретної версії (2.10.2). Але тепер ви захочете останню версію 2.10.x.
|
||||
|
||||
Використовуйте символ тильди (`~`), щоб встановити префікс версії моменту у ваших залежностях і дозволити npm оновити його до будь-якого оновлення версії PATCH.
|
||||
|
||||
**Примітка:** Номери версій не слід змінювати.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" повинні містити "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
версія "moment" повинна бути "~2.10.2"
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: 587d7fb9367417b2b2512c12
|
||||
title: Пошукові ланцюгові помічники запитів для звуження результатів пошуку
|
||||
challengeType: 2
|
||||
forumTopicId: 301533
|
||||
dashedName: chain-search-query-helpers-to-narrow-search-results
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Якщо ви не передаєте зворотній виклик як останній аргумент до `Model.find()` (або інших пошукових методів), запит не буде виконуватися. Ви можете зберегти запит в змінній для подальшого використання. Цей тип об'єкту дозволяє створювати запит за допомогою ланцюгового синтаксису. Фактичний пошук db виконується, коли ви остаточно з'єднали метод `.exec()`. Ви завжди повинні передати зворотній виклик цьому останньому методу. Існує багато помічників для запитів, тут ми використовуємо найбільш поширені.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `queryChain`, щоб знайти людей, що люблять їжу, вказану змінною `foodToSearch`. Посортуйте їх за `name`, знизьте кількість результатів до двох документів та приховайте їхній вік. Об'єднайте `.find()`, `.sort()`, `.limit()`, `.select()`, and then `.exec()`. Передайте зворотній виклик `done(err, data)` до `exec()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Використання ланцюгових помічників для запитів має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,88 @@
|
||||
---
|
||||
id: 587d7fb6367417b2b2512c07
|
||||
title: Створити модель
|
||||
challengeType: 2
|
||||
forumTopicId: 301535
|
||||
dashedName: create-a-model
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**C**RUD Частина І - Створення
|
||||
|
||||
Перш за все, вам необхідна схема. Кожна схема пов'язана з колекцією MongoDB. Вона визначає форму документів у цій колекції. Схеми - це блоки, які складають моделі. Вони можуть бути вкладеними для того, щоб створити складні моделі, але в цьому випадку ми не будемо все ускладнювати. Модель дозволяє створювати екземпляри ваших об’єктів, які називаються документами.
|
||||
|
||||
Replit - це справжній сервер, і на реальних серверах взаємодії з базою даних відбуваються у функціях обробника. Ці функції виконуються, коли трапляється якась подія (наприклад, хтось попадає на кінцеву точку вашого API). Ми будемо дотримуватись того самого підходу в цих вправах. Функція `done()` - це зворотний виклик, який повідомляє нас про те, що ми можемо продовжувати після завершення асинхронної операції, такої як вставка, оновлення чи видалення. Він відповідає конвенції Node і повинен називатися `done(null, data)` on success, or `done(err)` в разі помилки.
|
||||
|
||||
Увага! Помилки можуть виникнути при взаємодії з віддаленими службами!
|
||||
|
||||
```js
|
||||
/* Example */
|
||||
|
||||
const someFunc = function(done) {
|
||||
//... do something (risky) ...
|
||||
if (error) return done(error);
|
||||
done(null, result);
|
||||
};
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Створіть особисту схему під назвою `personSchema`, яка має такий прототип:
|
||||
|
||||
```markup
|
||||
- Person Prototype -
|
||||
--------------------
|
||||
name : string [required]
|
||||
age : number
|
||||
favoriteFoods : array of strings (*)
|
||||
```
|
||||
|
||||
Використовуйте основні типи схем Mongoose. Якщо ви хочете, то також можете додати більше полів, використовувати прості валідатори, такі як обов’язкові або унікальні, і встановити значення за замовчуванням. Перегляньте [Mongoose docs](http://mongoosejs.com/docs/guide.html).
|
||||
|
||||
Тепер створіть модель під назвою `Person` from the `personSchema`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Створення екземпляру зі схеми Mongoose повинно пройти успішно
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 587d7fb6367417b2b2512c09
|
||||
title: Створіть та збережіть запис моделі
|
||||
challengeType: 2
|
||||
forumTopicId: 301536
|
||||
dashedName: create-and-save-a-record-of-a-model
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
У цьому завданні вам буде потрібно створити та зберегти запис моделі.
|
||||
|
||||
# --instructions--
|
||||
|
||||
У межах функції `createAndSavePerson`, створіть екземпляр документа, використовуючи модель конструктора `Person`, який ви побудували раніше. Перенесіть до конструктора об'єкт, який має поля `name`, `age`, і `favoriteFoods`. Їх типи повинні збігатися з тими, що у `personSchema`. Опісля викличте метод `document.save()` у зворотньому екземплярі документа. Додайте до нього функцію зворотнього виклику використовуючи метод вузла. Це - загальний шаблон; всі такі CRUD-методи потребують функції зворотнього зв'язку в якості останнього аргументу.
|
||||
|
||||
```js
|
||||
/* Example */
|
||||
|
||||
// ...
|
||||
person.save(function(err, data) {
|
||||
// ...do your stuff here...
|
||||
});
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
Створення та збереження елемента БД має пройти успішно
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 587d7fb7367417b2b2512c0a
|
||||
title: Створюємо багато записів використовуючи model.create()
|
||||
challengeType: 2
|
||||
forumTopicId: 301537
|
||||
dashedName: create-many-records-with-model-create
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Часом потрібно створити багато екземплярів ваших моделей, наприклад, під час заповнення бази даних початковими даними. `Model.create()` приймає масив об'єктів, таких як `[{name: 'John', ...}, {...}, ...]` в якості першого аргумента, і зберігає їх всіх до Бд.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Перейменуйте функцію `createManyPeople` щоб створити багато людей, використовуючи `Model.create()` з аргументом `arrayOfPeople`.
|
||||
|
||||
**Note** Ви можете повторно використати модель встановлену в попередній вправі.
|
||||
|
||||
# --hints--
|
||||
|
||||
Створення одразу багатьох елементів БД має пройти успішно
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 587d7fb8367417b2b2512c11
|
||||
title: Видалення багатьох елементів за допомогою model.remove()
|
||||
challengeType: 2
|
||||
forumTopicId: 301538
|
||||
dashedName: delete-many-documents-with-model-remove
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`Model.remove()` корисний для видалення всіх документів, що відповідають заданим критеріям.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `removeManyPeople`, щоб видалити всіх людей, ім'я яких знаходиться в змінній `nameToRemove`, за допомогою `Model.remove()`. Передайте його до документа запиту з набором полів `name`, і зворотнім викликом.
|
||||
|
||||
**Примітка:** `Model.remove()` не повертає видалений документ, а об'єкт JSON, що містить результат операції та кількість елементів, що постраждали. Не забудьте передати його до зворотного виклику `done()`, оскільки він буде використовуватися у тестах.
|
||||
|
||||
# --hints--
|
||||
|
||||
Видалення одразу декількох елементів має пройти успішно
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 587d7fb8367417b2b2512c10
|
||||
title: Видалення одного документа за допомогою model.findByIdAndRemove
|
||||
challengeType: 2
|
||||
forumTopicId: 301539
|
||||
dashedName: delete-one-document-using-model-findbyidandremove
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`findByIdAndRemove` і `findOneAndRemove` схожі до попередніх методів оновлення. Вони передають вилучений документ до db. Використовуйте аргумент функції `personId` як ключ пошуку.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `removeById`, щоб видалити одну особу на основі її `_id`. Потрібно використовувати один із методів `findByIdAndRemove()` or `findOneAndRemove()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Видалення елемента має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,85 @@
|
||||
---
|
||||
id: 587d7fb6367417b2b2512c06
|
||||
title: Встановлення і налаштування Mongoose
|
||||
challengeType: 2
|
||||
forumTopicId: 301540
|
||||
dashedName: install-and-set-up-mongoose
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Робота над цими завданнями включатиме написання вашого коду з використанням одного з наступних методів:
|
||||
|
||||
- Створіть [цей GitHub репозитарій](https://github.com/freeCodeCamp/boilerplate-mongomongoose/) і локально завершіть ці завдання.
|
||||
- Використовуйте [наш стартовий проєкт Replit](https://replit.com/github/freeCodeCamp/boilerplate-mongomongoose) для виконання цих завдань.
|
||||
- Використовуйте конструктор сайту на власний розсуд, щоб завершити проєкт. Перевірте, що ви зберегли усі файли з нашого репозиторію GitHub.
|
||||
|
||||
По завершенню, переконайтеся, що працююча демоверсія вашого проєкту розміщена у відкритому доступі. Потім введіть URL - адресу проєкту в поле `Solution Link` field.
|
||||
|
||||
У цьому завданні, створіть базу даних MongoDB Atlas та імпортуйте необхідні пакети для підключення до неї.
|
||||
|
||||
Дотримуйтесь <a href='https://www.freecodecamp.org/news/get-started-with-mongodb-atlas/' rel='noopener noreferrer' target='_blank'>цих вказівок</a>, щоб налаштувати розміщену базу даних на MongoDB Atlas.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Додайте `mongodb@~3.6.0` і `mongoose@~5.4.0` до `package.json` проєкту. Потім, необхідно встановити mongoose як `mongoose` у `myApp.js`. Створіть файл `.env` і додайте до нього змінну `MONGO_URI`. Його значенням має бути ваш URI бази даних MongoDB Atlas. Обов'язково помістіть URI в одинарні чи подвійні лапки, і пам'ятайте, що ви не можете використовувати пробіли навколо `=` у змінних середовища. Наприклад, `MONGO_URI='VALUE'`. Після завершення, під'єднайтесь до бази даних, використовуючи наступний синтаксис:
|
||||
|
||||
```js
|
||||
mongoose.connect(<Your URI>, { useNewUrlParser: true, useUnifiedTopology: true });
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
Залежність "mongodb" слід вказати в package.json
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Залежність "mongoose" слід вказати в package.json
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
"mongoose" слід підключити до бази даних
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 587d7fb8367417b2b2512c0e
|
||||
title: 'Виконайте класичні оновлення здійснюючи пошук, редагування і збереження'
|
||||
challengeType: 2
|
||||
forumTopicId: 301541
|
||||
dashedName: perform-classic-updates-by-running-find-edit-then-save
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
У старі добрі часи це було те, що вам потрібно було робити, якщо ви хотіли відредагувати документ і мати можливість якимсь чином ним користуватися (наприклад, надіслати його назад у відповіді сервера). Mongoose має спеціальний метод оновлення: `Model.update()`. Він прив'язаний до драйвера з низьким рівнем монго. Він може редагувати багато документів, що відповідають певним критеріям, але не надсилає оновлений документ, а лише повідомлення про статус. Крім того, це ускладнює перевірку моделі, оскільки просто викликає безпосередньо драйвер mongo.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `findEditThenSave`, щоб знайти особу за `_id` (використовуйте будь - який із вищезгаданих методів) з параметром `personId` як ключ пошуку. Додайте `"hamburger"` до списку `favoriteFoods` людини (можна використовувати `Array.push()`). Потім всередині зворотного виклику пошуку - `save()` оновлений`Person`.
|
||||
|
||||
**Примітка:** Це може бути складно, якщо у вашій схемі, ви визначили `favoriteFoods` як масив, не вказуючи тип (тобто `[String]`). В такому випадку `favoriteFoods` за замовчуванням приймає змішаний тип, і вам потрібно вручну позначити його як відредагований за допомогою `document.markModified('edited-field')`. Перегляньте [Mongoose documentation](https://mongoosejs.com/docs/schematypes.html#Mixed)
|
||||
|
||||
# --hints--
|
||||
|
||||
Пошук-редагування-оновлення елемента має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 587d7fb8367417b2b2512c0f
|
||||
title: Виконання нових оновлень для документа за допомогою model.findOneAndUpdate()
|
||||
challengeType: 2
|
||||
forumTopicId: 301542
|
||||
dashedName: perform-new-updates-on-a-document-using-model-findoneandupdate
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Останні версії Mongoose мають методи спрощення оновлення документів. Деякі більш розширені функції (наприклад, хуки до/після, перевірка) поводяться з таким підходом по-різному, тому класичний метод все ще корисний у багатьох ситуаціях. `findByIdAndUpdate()` можна використовувати під час пошуку за id.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `findAndUpdate`, щоб знайти особу за `Name` і встановити вік особи за `20`. Використовуйте параметр функції `personName` як ключ пошуку.
|
||||
|
||||
**Примітка:** Ви повинні повернути оновлений документ. Для цього необхідно передати опції документа `{ new: true }` як третій аргумент `findOneAndUpdate()`. За замовчуванням ці методи повертають немодифікований об'єкт.
|
||||
|
||||
# --hints--
|
||||
|
||||
пошук OneAndUpdate елемента має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 587d7fb7367417b2b2512c0b
|
||||
title: Використання model.find() для пошуку вашої бази даних
|
||||
challengeType: 2
|
||||
forumTopicId: 301543
|
||||
dashedName: use-model-find-to-search-your-database
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
У найпростішому використанні, `Model.find()` приймає документ - запит ( об'єкт JSON) як перший аргумент, а потім - зворотній виклик. Це повертає масив збігів. Це підтримує надзвичайно широкий спектр варіантів пошуку. Читайте більше в документації.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `findPeopleByName`, щоб знайти всіх людей з даним іменем, використовуючи <code>Model.find() -\> [Person]</code>
|
||||
|
||||
Використовуйте аргумент функції `personName` як ключ пошуку.
|
||||
|
||||
# --hints--
|
||||
|
||||
Пошук усіх елементів, що відповідають критеріям, мають бути успішними
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 587d7fb7367417b2b2512c0d
|
||||
title: Використання model.findById() для пошуку вашої бази даних за допомогою _id
|
||||
challengeType: 2
|
||||
forumTopicId: 301544
|
||||
dashedName: use-model-findbyid-to-search-your-database-by-id
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
При збереженні документу, MongoDB автоматично додає поле `_id`, і встановлює для нього унікальний алфавітно-цифровий ключ. Пошук за `_id` є надзвичайно частою операцією, тому Mongoose надає для цього спеціалізований метод.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть `findPersonById`, щоб знайти лише одну особу, яка має заданий `_id`, використовуючи `Model.findById() -> Person`. Використовуйте аргумент функції `personId` як ключ пошуку.
|
||||
|
||||
# --hints--
|
||||
|
||||
Пошук елемента за Id має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 587d7fb7367417b2b2512c0c
|
||||
title: Використання model.findOne() для повернення єдиного відповідного документа з вашої бази даних
|
||||
challengeType: 2
|
||||
forumTopicId: 301545
|
||||
dashedName: use-model-findone-to-return-a-single-matching-document-from-your-database
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`Model.findOne()` функціонує як `Model.find()`, але повертає лише один документ (не масив), навіть якщо є кілька елементів. Це особливо корисно під час пошуку за властивостями, які були оголошені як унікальні.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Змініть функцію `findOneByFood`, щоб знайти лише одну особу, яка має певну їжу у своїх вподобаннях, використовуючи модель `Model.findOne() -> Person`. Використовуйте аргумент функції `food` як ключ пошуку.
|
||||
|
||||
# --hints--
|
||||
|
||||
Пошук елемента має бути успішним
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
/**
|
||||
Backend challenges don't need solutions,
|
||||
because they would need to be tested against a full working project.
|
||||
Please check our contributing guidelines to learn more.
|
||||
*/
|
||||
```
|
Reference in New Issue
Block a user