feat: add 'back/front end' in curriculum (#42596)
* chore: rename APIs and Microservices to include "Backend" (#42515) * fix typo * fix typo * undo change * Corrected grammar mistake Corrected a grammar mistake by removing a comma. * change APIs and Microservices cert title * update title * Change APIs and Microservices certi title * Update translations.json * update title * feat(curriculum): rename apis and microservices cert * rename folder structure * rename certificate * rename learn Markdown * apis-and-microservices -> back-end-development-and-apis * update backend meta * update i18n langs and cypress test Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * fix: add development to front-end libraries (#42512) * fix: added-the-word-Development-to-front-end-libraries * fix/added-the-word-Development-to-front-end-libraries * fix/added-word-development-to-front-end-libraries-in-other-related-files * fix/added-the-word-Development-to-front-end-and-all-related-files * fix/removed-typos-from-last-commit-in-index.md * fix/reverted-changes-that-i-made-to-dependecies * fix/removed xvfg * fix/reverted changes that i made to package.json * remove unwanted changes * front-end-development-libraries changes * rename backend certSlug and README * update i18n folder names and keys * test: add legacy path redirect tests This uses serve.json from the client-config repo, since we currently use that in production * fix: create public dir before moving serve.json * fix: add missing script * refactor: collect redirect tests * test: convert to cy.location for stricter tests * rename certificate folder to 00-certificates * change crowdin config to recognise new certificates location * allow translations to be used Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com> * add forwards slashes to path redirects * fix cypress path tests again * plese cypress * fix: test different challenge Okay so I literally have no idea why this one particular challenge fails in Cypress Firefox ONLY. Tom and I paired and spun a full build instance and confirmed in Firefox the page loads and redirects as expected. Changing to another bootstrap challenge passes Cypress firefox locally. Absolutely boggled by this. AAAAAAAAAAAAAAA * fix: separate the test Okay apparently the test does not work unless we separate it into a different `it` statement. >:( >:( >:( >:( Co-authored-by: Sujal Gupta <55016909+heysujal@users.noreply.github.com> Co-authored-by: Noor Fakhry <65724923+NoorFakhry@users.noreply.github.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
---
|
||||
id: 5a8b073d06fa14fcfde687aa
|
||||
title: Registrador de exercícios
|
||||
challengeType: 4
|
||||
forumTopicId: 301505
|
||||
dashedName: exercise-tracker
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Crie um aplicativo full stack em JavaScript que seja funcionalmente semelhante a este: <https://exercise-tracker.freecodecamp.rocks/>. Trabalhar nesse projeto vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/) e complete o projeto localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-exercisetracker) para completar o projeto.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve fornecer seu próprio projeto, não o exemplo de URL.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
assert(
|
||||
!/.*\/exercise-tracker\.freecodecamp\.rocks/.test(getUserInput('url'))
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Você pode fazer a solicitação de `POST` para `/api/users` com dados do formulário `username` para criar um novo usuário. A resposta retornada será um objeto com as propriedades `username` e `_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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Você pode fazer uma solicitação de `GET` a `/api/users` para obter um array de todos os usuários. Cada elemento no array é um objeto que contém `username` e `_id` dos usuários.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/users');
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
assert.isArray(data);
|
||||
assert.isString(data[0].username);
|
||||
assert.isString(data[0]._id);
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Você pode fazer a solicitação de `POST` para `/api/users/:_id/exercises` com os dados do formulário `description`, `duration` e, como opção, `date`. Se nenhuma data for fornecida, a data atual será utilizada. A resposta retornada será o objeto do usuário com os campos de exercício adicionados.
|
||||
|
||||
```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);
|
||||
} else {
|
||||
throw new Error(`${addRes.status} ${addRes.statusText}`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Você pode fazer uma solicitação de `GET` a `/api/users/:_id/logs` para obter um registro completo dos exercícios de qualquer usuário. A resposta retornada será o objeto de usuário com um array de `log` de todos os exercícios adicionados. Cada item do registro (log) terá as propriedades `description`, `duration` e `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();
|
||||
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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Uma solicitação para o registro (log) de um usuário (`/api/users/:_id/logs`) retornará um objeto com uma propriedade `count`, que representa o número de exercícios retornados.
|
||||
|
||||
```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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Você pode adicionar os parâmetros `from`, `to` e `limit` a uma solicitação para `/api/users/:_id/logs` para recuperar parte do registro de qualquer usuário. `from` e `to` são datas no formato `yyyy-mm-dd`. `limit` é um número inteiro de quantos registros devem ser enviados de volta.
|
||||
|
||||
```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,88 @@
|
||||
---
|
||||
id: bd7158d8c443edefaeb5bd0f
|
||||
title: Microsserviço de metadados de arquivos
|
||||
challengeType: 4
|
||||
forumTopicId: 301506
|
||||
dashedName: file-metadata-microservice
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Crie um aplicativo full stack em JavaScript que seja funcionalmente semelhante a este: <https://file-metadata-microservice.freecodecamp.rocks/>. Trabalhar nesse projeto vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-project-filemetadata/) e complete o projeto localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-filemetadata) para completar o projeto.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
# --instructions--
|
||||
|
||||
**DICA:** você pode usar o pacote `multer` do npm para lidar com o envio de arquivos.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve fornecer seu próprio projeto, não o exemplo de URL.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
assert(
|
||||
!/.*\/file-metadata-microservice\.freecodecamp\.rocks/.test(
|
||||
getUserInput('url')
|
||||
)
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Você pode enviar um formulário que inclua o upload de arquivos.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const site = await fetch(getUserInput('url'));
|
||||
const data = await site.text();
|
||||
const doc = new DOMParser().parseFromString(data, 'text/html');
|
||||
assert(doc.querySelector('input[type="file"]'));
|
||||
};
|
||||
```
|
||||
|
||||
O campo entrada do arquivo de formulário tem o atributo `name` definido como `upfile`.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const site = await fetch(getUserInput('url'));
|
||||
const data = await site.text();
|
||||
const doc = new DOMParser().parseFromString(data, 'text/html');
|
||||
assert(doc.querySelector('input[name="upfile"]'));
|
||||
};
|
||||
```
|
||||
|
||||
Ao enviar um arquivo, você recebe `name` (nome), `type` (tipo) e `size` (tamanho, em bytes) do arquivo dentro da resposta em JSON.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const formData = new FormData();
|
||||
const fileData = await fetch(
|
||||
'https://cdn.freecodecamp.org/weather-icons/01d.png'
|
||||
);
|
||||
const file = await fileData.blob();
|
||||
formData.append('upfile', file, 'icon');
|
||||
const data = await fetch(getUserInput('url') + '/api/fileanalyse', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
const parsed = await data.json();
|
||||
assert.property(parsed, 'size');
|
||||
assert.equal(parsed.name, 'icon');
|
||||
assert.equal(parsed.type, 'image/png');
|
||||
};
|
||||
```
|
||||
|
||||
# --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: Microsserviço conversor de requisição de cabeçalho
|
||||
challengeType: 4
|
||||
forumTopicId: 301507
|
||||
dashedName: request-header-parser-microservice
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Crie um aplicativo full stack em JavaScript que seja funcionalmente semelhante a este: <https://request-header-parser-microservice.freecodecamp.rocks/>. Trabalhar nesse projeto vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-project-headerparser/) e complete o projeto localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-headerparser) para completar o projeto.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve fornecer seu próprio projeto, não o exemplo de URL.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
assert(
|
||||
!/.*\/request-header-parser-microservice\.freecodecamp\.rocks/.test(
|
||||
getUserInput('url')
|
||||
)
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/whoami` deve retornar um objeto JSON com o seu endereço IP na chave `ipaddress`.
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/whoami').then(
|
||||
(data) => assert(data.ipaddress && data.ipaddress.length > 0),
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/whoami` deve retornar um objeto JSON com o seu idioma preferido na chave `language`.
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/whoami').then(
|
||||
(data) => assert(data.language && data.language.length > 0),
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/whoami` deve retornar um objeto JSON com o seu software na chave `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,154 @@
|
||||
---
|
||||
id: bd7158d8c443edefaeb5bdef
|
||||
title: Microsserviço de timestamp
|
||||
challengeType: 4
|
||||
forumTopicId: 301508
|
||||
dashedName: timestamp-microservice
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Crie um aplicativo full stack em JavaScript que seja funcionalmente semelhante a este: <https://timestamp-microservice.freecodecamp.rocks/>. Trabalhar nesse projeto vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-project-timestamp/) e complete o projeto localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-timestamp) para completar o projeto.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve fornecer seu próprio projeto, não o exemplo de URL.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
assert(
|
||||
!/.*\/timestamp-microservice\.freecodecamp\.rocks/.test(getUserInput('url'))
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/:date?` com uma data válida deve retornar um objeto JSON com uma chave `unix`, que é um timestamp do Unix da data de entrada em milissegundos
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/2016-12-25').then(
|
||||
(data) => {
|
||||
assert.equal(
|
||||
data.unix,
|
||||
1482624000000,
|
||||
'Should be a valid unix timestamp'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/:date?` com uma data válida deve retornar um objeto JSON com uma chave `utc` que é uma string da data de entrada no formato: `Thu, 01 Jan 1970 00:00:00 GMT`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/2016-12-25').then(
|
||||
(data) => {
|
||||
assert.equal(
|
||||
data.utc,
|
||||
'Sun, 25 Dec 2016 00:00:00 GMT',
|
||||
'Should be a valid UTC date string'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Uma solicitação a `/api/1451001600000` deve retornar `{ unix: 1451001600000, utc: "Fri, 25 Dec 2015 00:00:00 GMT" }`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/1451001600000').then(
|
||||
(data) => {
|
||||
assert(
|
||||
data.unix === 1451001600000 &&
|
||||
data.utc === 'Fri, 25 Dec 2015 00:00:00 GMT'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Seu projeto pode tratar as datas que podem ser analisadas com sucesso por `new Date(date_string)`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/05 October 2011').then(
|
||||
(data) => {
|
||||
assert(
|
||||
data.unix === 1317772800000 &&
|
||||
data.utc === 'Wed, 05 Oct 2011 00:00:00 GMT'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Se a string de data de entrada for inválida, a api retorna um objeto que tem a estrutura `{ error : "Invalid Date" }`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api/this-is-not-a-date').then(
|
||||
(data) => {
|
||||
assert.equal(data.error.toLowerCase(), 'invalid date');
|
||||
},
|
||||
(xhr) => {
|
||||
assert(xhr.responseJSON.error.toLowerCase() === 'invalid date');
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Um parâmetro de data vazia deve retornar o tempo atual em um objeto JSON com a chave `unix`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api').then(
|
||||
(data) => {
|
||||
var now = Date.now();
|
||||
assert.approximately(data.unix, now, 20000);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Um parâmetro de data vazia deve retornar o tempo atual em um objeto JSON com a chave `utc`
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/api').then(
|
||||
(data) => {
|
||||
var now = Date.now();
|
||||
var serverTime = new Date(data.utc).getTime();
|
||||
assert.approximately(serverTime, now, 20000);
|
||||
},
|
||||
(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,119 @@
|
||||
---
|
||||
id: bd7158d8c443edefaeb5bd0e
|
||||
title: Microsserviço redutor de URL
|
||||
challengeType: 4
|
||||
forumTopicId: 301509
|
||||
dashedName: url-shortener-microservice
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Crie um aplicativo full stack em JavaScript que seja funcionalmente semelhante a este: <https://url-shortener-microservice.freecodecamp.rocks/>. Trabalhar nesse projeto vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-project-urlshortener/) e complete o projeto localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-urlshortener) para completar o projeto.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
# --instructions--
|
||||
|
||||
**DICA:** não se esqueça de usar um middleware de análise do body para tratar as solicitações de POST. Você também pode usar a função `dns.lookup(host, cb)` do módulo central do `dns` para verificar um URL enviado.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve fornecer seu próprio projeto, não o exemplo de URL.
|
||||
|
||||
```js
|
||||
(getUserInput) => {
|
||||
assert(
|
||||
!/.*\/url-shortener-microservice\.freecodecamp\.rocks/.test(
|
||||
getUserInput('url')
|
||||
)
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Você pode postar um URL para `/api/shorturl` e obter uma resposta em JSON com as propriedades `original_url` e `short_url`. Aqui está um exemplo: `{ original_url : 'https://freeCodeCamp.org', short_url : 1}`
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const urlVariable = Date.now();
|
||||
const fullUrl = `${url}/?v=${urlVariable}`
|
||||
const res = await fetch(url + '/api/shorturl', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `url=${fullUrl}`
|
||||
});
|
||||
if (res.ok) {
|
||||
const { short_url, original_url } = await res.json();
|
||||
assert.isNotNull(short_url);
|
||||
assert.strictEqual(original_url, `${url}/?v=${urlVariable}`);
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Quando você visitar `/api/shorturl/<short_url>`, será redirecionado para o URL original.
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const urlVariable = Date.now();
|
||||
const fullUrl = `${url}/?v=${urlVariable}`
|
||||
let shortenedUrlVariable;
|
||||
const postResponse = await fetch(url + '/api/shorturl', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `url=${fullUrl}`
|
||||
});
|
||||
if (postResponse.ok) {
|
||||
const { short_url } = await postResponse.json();
|
||||
shortenedUrlVariable = short_url;
|
||||
} else {
|
||||
throw new Error(`${postResponse.status} ${postResponse.statusText}`);
|
||||
}
|
||||
const getResponse = await fetch(
|
||||
url + '/api/shorturl/' + shortenedUrlVariable
|
||||
);
|
||||
if (getResponse) {
|
||||
const { redirected, url } = getResponse;
|
||||
assert.isTrue(redirected);
|
||||
assert.strictEqual(url,fullUrl);
|
||||
} else {
|
||||
throw new Error(`${getResponse.status} ${getResponse.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Se você passar um URL inválido que não siga o formato válido `http://www.example.com` , a resposta em JSON conterá `{ error: 'invalid url' }`
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/shorturl', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `url=ftp:/john-doe.org`
|
||||
});
|
||||
if (res.ok) {
|
||||
const { error } = await res.json();
|
||||
assert.isNotNull(error);
|
||||
assert.strictEqual(error.toLowerCase(), 'invalid url');
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
# --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: Encadear middleware para criar um servidor de tempo
|
||||
challengeType: 2
|
||||
forumTopicId: 301510
|
||||
dashedName: chain-middleware-to-create-a-time-server
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
O middleware pode ser montado em uma rota específica usando `app.METHOD(path, middlewareFunction)`. O middleware também pode ser encadeado nas definições de rota.
|
||||
|
||||
Observe o exemplo abaixo:
|
||||
|
||||
```js
|
||||
app.get('/user', function(req, res, next) {
|
||||
req.user = getTheUserSync(); // Hypothetical synchronous operation
|
||||
next();
|
||||
}, function(req, res) {
|
||||
res.send(req.user);
|
||||
});
|
||||
```
|
||||
|
||||
Esse método é útil para separar as operações de servidor em pedaços menores. Isso fornece uma melhor estrutura de aplicativo, além da possibilidade de reusar código em partes diferentes. Esse método também pode ser usado para realizar algumas validações de dados. Em cada ponto da pilha de middleware, você poderá bloquear a execução da cadeia atual e passar o controle para funções específicas criadas especificamente para gerenciar erros. Você também pode passar o controle para a próxima rota correspondente, para gerenciar casos especiais. Veremos como fazer isso na seção avançada do Express.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Na rota `app.get('/now', ...)`, encadeie uma função middleware e o handler final. Na função middleware, você deverá adicionar o tempo atual no objeto de requisição na chave `req.time`. Você pode usar `new Date().toString()`. No gerenciador, responda com um objeto JSON, pegando a estrutura `{time: req.time}`.
|
||||
|
||||
**Observação:** o teste não vai passar se você não encadear o middleware. Se você montar a função em algum outro lugar, o teste vai falhar, mesmo que o resultado final esteja correto.
|
||||
|
||||
# --hints--
|
||||
|
||||
O endpoint (URL) /now deve ter o middleware montado
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
O endpoint (URL) /now deve retornar um horário que possui margem de erro de +/- 20 segundos a partir de agora
|
||||
|
||||
```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: Obter dados de solicitações de POST
|
||||
challengeType: 2
|
||||
forumTopicId: 301511
|
||||
dashedName: get-data-from-post-requests
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Monte um handler POST no caminho `/name`. É o mesmo caminho de antes. Nós preparamos um formulário na página inicial html. Ele vai enviar os mesmos dados do exercício 10 (string de consulta). Se o body-parser estiver configurado corretamente, você deverá encontrar os parâmetros do objeto `req.body`. Dê uma olhada no exemplo habitual da biblioteca:
|
||||
|
||||
<blockquote>route: POST '/library'<br>urlencoded_body: userId=546&bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
Responda com o mesmo objeto JSON usado antes: `{name: 'firstname lastname'}`. Teste se seu endpoint (URL) funciona usando o formulário html que fornecemos na página inicial do aplicativo.
|
||||
|
||||
Dica: existem vários outros métodos http além de GET e POST. Por convenção, existem correspondências entre o verbo http e a operação que você vai executar no servidor. O mapeamento convencional é:
|
||||
|
||||
POST (às vezes, PUT) – Cria um novo recurso usando a informação enviada com a requisição,
|
||||
|
||||
GET - Lê um recurso existente sem modificá-lo,
|
||||
|
||||
PUT ou PATCH (às vezes, POST) – Atualiza um recurso usando os dados enviados,
|
||||
|
||||
DELETE=> Exclui um recurso.
|
||||
|
||||
Existem também alguns outros métodos que são usados para estabelecer uma conexão com o servidor. Com a exceção de GET, todos os outros métodos listados acima podem ter uma payload(carga) (exemplo: os dados enviados no corpo da requisição). O middleware body-parser também funciona com esses métodos.
|
||||
|
||||
# --hints--
|
||||
|
||||
Teste 1 : O endpoint (URL) da API deve responder com o nome correto
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Teste 2: O endpoint da API deve responder com o nome correto
|
||||
|
||||
```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: Obter a entrada do parâmetro da consulta do client
|
||||
challengeType: 2
|
||||
forumTopicId: 301512
|
||||
dashedName: get-query-parameter-input-from-the-client
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Outro jeito usual de obter a entrada do client é ao codificar os dados após o caminho da rota, usando uma string de consulta. A string de consulta é delimitada por um símbolo de interrogação (?) e inclui pares campo=valor. Cada par é separado por um e comercial(&). O Express pode analisar os dados da string de consulta e preencher o objeto `req.query`. Alguns caracteres, como o de porcentagem (%), não podem estar nos URLs e tem de ser codificados em um formato diferente antes que você os envie. Se você usa a API do JavaScript, você pode usar métodos específicos para codificar/decodificar esses caracteres.
|
||||
|
||||
<blockquote>route_path: '/library'<br>actual_request_URL: '/library?userId=546&bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
# --instructions--
|
||||
|
||||
Faça uma API de endpoint (URL), montada em `GET /name`. Responda com um documento JSON, pegando a estrutura `{ name: 'firstname lastname'}`. O parâmetros primeiro e último nome devem ser codificados em uma string de consulta como, por exemplo: `?first=firstname&last=lastname`.
|
||||
|
||||
**Observação:** no exercício seguinte, você vai receber dados de uma requisição POST, no mesmo caminho de rota `/name`. Se você quiser, poderá usar o método `app.route(path).get(handler).post(handler)`. Essa sintaxe permite a você encadear diferentes manipuladores do tipo verb no mesmo caminho de rota. Você vai economizar na digitação e ter um código mais limpo.
|
||||
|
||||
# --hints--
|
||||
|
||||
Teste 1: O endpoint (URL) da API deverá responder com o nome correto
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Teste 2 : O endpoint (URL) da API deve responder com o nome correto
|
||||
|
||||
```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: Obter a entrada do parâmetro de roteamento do client
|
||||
challengeType: 2
|
||||
forumTopicId: 301513
|
||||
dashedName: get-route-parameter-input-from-the-client
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Ao construir uma API, temos que permitir que os usuários nos comuniquem o que querem obter com o nosso serviço. Por exemplo, se o client estiver solicitando informações sobre um usuário armazenado no banco de dados, ele precisa de um modo de nos informar em qual usuário ele está interessado. Uma maneira possível de alcançar este resultado é utilizando parâmetros de roteamento. Parâmetros de roteamento são segmentos nomeados do URL, delimitados por barras (/). Cada segmento captura o valor da parte do URL que corresponde à sua posição. Os valores capturados podem ser encontrados no objeto `req.params`.
|
||||
|
||||
<blockquote>route_path: '/user/:userId/book/:bookId'<br>actual_request_URL: '/user/546/book/6754' <br>req.params: {userId: '546', bookId: '6754'}</blockquote>
|
||||
|
||||
# --instructions--
|
||||
|
||||
Crie um servidor de eco, montado na rota `GET /:word/echo`. Responda com um documento JSON, pegando a estrutura `{echo: word}`. Você pode encontrar a palavra a ser repetida em `req.params.word`. Você pode testar sua rota através da barra de endereços do seu navegador, visitando algumas rotas correspondentes, como, por exemplo, `your-app-rootpath/freecodecamp/echo`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Teste 1: o servidor de eco deve repetir palavras corretamente
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Teste 2: o servidor de eco deve repetir palavras corretamente
|
||||
|
||||
```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: Implementar um middleware de solicitação ao nível de root
|
||||
challengeType: 2
|
||||
forumTopicId: 301514
|
||||
dashedName: implement-a-root-level-request-logger-middleware
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Anteriormente, você apresentamos a você a função de middleware `express.static()`. Agora é hora de ver o que é o middleware, em mais detalhes. As funções de middleware são funções que recebem 3 argumentos: o objeto de solicitação, o objeto de resposta e a próxima função no ciclo de solicitação e resposta do aplicativo. Estas funções executam algum código que pode ter efeitos colaterais no aplicativo. Geralmente, elas adicionam informações aos objetos de solicitação ou resposta. Elas também podem acabar com o ciclo enviando uma resposta quando alguma condição é satisfeita. Se elas não enviarem a resposta quando terminarem, iniciam a execução da próxima função na pilha. Isso dispara o chamado do terceiro argumento, `next()`.
|
||||
|
||||
Observe o exemplo abaixo:
|
||||
|
||||
```js
|
||||
function(req, res, next) {
|
||||
console.log("I'm a middleware...");
|
||||
next();
|
||||
}
|
||||
```
|
||||
|
||||
Vamos supor que você montou esta função em uma rota. Quando uma solicitação corresponde à rota, ela exibe a string "I'm a middleware…" e então executa a próxima função na pilha. Neste exercício, você vai criar um middleware ao nível de root. Como você viu no desafio 4, para montar uma função de middleware no nível de root, você pode usar o método `app.use(<mware-function>)`. Neste caso, a função será executada para todas as solicitações, mas você também pode definir condições mais específicas. Por exemplo, se você quiser que uma função seja executada somente para solicitações de POST, você poderia usar `app.post(<mware-function>)`. Existem métodos análogos para todos os verbos de HTTP (GET, DELETE, PUT, …).
|
||||
|
||||
# --instructions--
|
||||
|
||||
Crie um registrador simples. Para cada solicitação, ele deve registrar no console uma string com o seguinte formato: `method path - ip`. Um exemplo ficaria assim: `GET /json - ::ffff:127.0.0.1`. Note que há um espaço entre `method` e `path` e que o traço separando o `path` e `ip` está cercado por um espaço de ambos os lados. Você pode obter o método de solicitação (verbo do http), o caminho da rota relativo e o IP de quem fez a chamada a partir do objeto de solicitação usando `req.method`, `req.path` e `req.ip`. Lembre-se de chamar `next()` quando você estiver pronto, ou o servidor ficará travado para sempre. Certifique-se de que os 'Logs' estejam abertos e veja o que acontece quando algumas solicitações chegarem.
|
||||
|
||||
**Observação:** o Express avalia as funções na ordem em que elas aparecem no código. Isto se aplica também ao middleware. Se você quer que ele funcione para todas as rotas, é preciso montá-lo antes delas.
|
||||
|
||||
# --hints--
|
||||
|
||||
O middleware do registrador de root deve estar ativo
|
||||
|
||||
```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: Conhecer o console do Node
|
||||
challengeType: 2
|
||||
forumTopicId: 301515
|
||||
dashedName: meet-the-node-console
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Trabalhar nesses desafios vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-express/) e complete esses desafios localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-express) para completar esses desafios.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`.
|
||||
|
||||
Durante o processo de desenvolvimento, é importante poder verificar o que está acontecendo no código.
|
||||
|
||||
O Node é apenas um ambiente JavaScript. Como o JavaScript lado do client, você pode usar o console para exibir informações úteis de depuração. Em sua máquina local, você veria a saída do console em um terminal. No Replit, um terminal está aberto no painel direito por padrão.
|
||||
|
||||
Recomendamos que o terminal continue aberto enquanto você trabalha nesses desafios. Ao ler a saída no terminal, você poderá ver os erros que podem ocorrer.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique o arquivo `myApp.js` para registrar "Hello World" no console.
|
||||
|
||||
# --hints--
|
||||
|
||||
`"Hello World"` deve estar no console
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url') + '/_api/hello-console').then(
|
||||
(data) => {
|
||||
assert.isTrue(data.passed, '"Hello World" is not in the server console');
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --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: Servir um arquivo HTML
|
||||
challengeType: 2
|
||||
forumTopicId: 301516
|
||||
dashedName: serve-an-html-file
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Você pode responder às solicitações com um arquivo usando o método `res.sendFile(path)`. Você pode colocá-lo dentro do manipulador de rota `app.get('/', ...)`. Nos bastidores, este método definirá os cabeçalhos apropriados para instruir o navegador sobre como lidar com o arquivo que você deseja enviar, de acordo com o tipo. Então, ele lerá e enviará o arquivo. Este método precisa de um caminho de arquivo absoluto. Recomendamos que use a variável global `__dirname` do Node para calcular o caminho assim:
|
||||
|
||||
```js
|
||||
absolutePath = __dirname + relativePath/file.ext
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Envie o arquivo `/views/index.html` como uma resposta para solicitações de GET para o caminho `/`. Ao ver sua aplicação ao vivo, você deverá perceber um grande título em HTML (e um formulário, que usaremos mais tarde…), sem nenhum estilo aplicado.
|
||||
|
||||
**Observação:** você pode editar a solução do desafio anterior ou criar uma nova. Se você criar uma nova solução, tenha em mente que o Express avalia rotas de cima para baixo e executa o manipulador para a primeira correspondência. Você tem que deixar comentada a solução anterior, ou o servidor continuará respondendo com uma string.
|
||||
|
||||
# --hints--
|
||||
|
||||
O aplicativo deve servir o arquivo 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: Servir JSON em uma rota específica
|
||||
challengeType: 2
|
||||
forumTopicId: 301517
|
||||
dashedName: serve-json-on-a-specific-route
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Enquanto um servidor HTML serve arquivos em HTML, uma API serve dados. Uma API <dfn>REST</dfn> (Transferência de Estado Representacional) permite a troca de dados de uma maneira simples sem a necessidade de os clients saberem qualquer detalhe sobre o servidor. O client só precisa saber onde o recurso está (qual o seu URL) e a ação que quer realizar nele (o verbo). O verbo GET é usado quando você busca algumas informações, sem modificar nada. Hoje em dia, o formato de dados preferencial para mover informações pela web é o JSON. Simplificando, JSON é uma maneira conveniente de representar um objeto JavaScript como uma string, que então pode ser facilmente transmitido.
|
||||
|
||||
Vamos criar uma API simples, gerando uma rota que responda com JSON no caminho `/json`. Você pode fazer isso como de costume, com o método `app.get()`. Dentro do manipulador de rota, use o método `res.json()`, passando um objeto como um argumento. Este método fecha o loop de solicitação-resposta, retornando os dados. Nos bastidores, ele converte um objeto JavaScript válido em uma string. Em seguida, define os cabeçalhos apropriados para dizer ao navegador que você está servindo JSON e envia os dados de volta. Um objeto válido tem a estrutura usual `{key: data}`. `data` pode ser um número, uma string, um objeto aninhado ou um array. `data` também podem ser uma variável ou o resultado de uma chamada de função. Nesse caso, ele será avaliado antes de ser convertido em uma string.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Sirva o objeto `{"message": "Hello json"}` como uma resposta, no formato JSON, para solicitações de GET feitas à rota `/json`. Em seguida, aponte o navegador para `your-app-url/json`. Você deverá ver a mensagem na tela.
|
||||
|
||||
# --hints--
|
||||
|
||||
O `/json` do endpoint deve servir o objeto 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: Servir ativos estáticos
|
||||
challengeType: 2
|
||||
forumTopicId: 301518
|
||||
dashedName: serve-static-assets
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Um servidor HTML geralmente tem um ou mais diretórios acessíveis pelo usuário. Você pode colocar lá os recursos estáticos necessários para a aplicação (folhas de estilos, scripts e imagens).
|
||||
|
||||
No Express, você pode colocar esta funcionalidade usando o middleware `express.static(path)`, onde o parâmetro `path` é o caminho absoluto da pasta que contém os arquivos.
|
||||
|
||||
Se você não sabe o que é um middleware... não se preocupe. Discutiremos isso em detalhes mais tarde. Basicamente, middleware são funções que interceptam manipuladores da rota, adicionando algum tipo de informação. Um middleware precisa ser montado usando o método `app.use(path, middlewareFunction)`. O primeiro argumento, `path`, é opcional. Se você não passar esse argumento, o middleware será executado em todas as solicitações.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Monte o middleware `express.static()` para o caminho `/public` com `app.use()`. O caminho absoluto para a pasta de arquivos é `__dirname + /public`.
|
||||
|
||||
Agora, seu aplicativo deve ser capaz de servir uma folha de estilos de CSS. Observe que o arquivo `/public/style.css` é referenciado em `/views/index.html` no boilerplate do projeto. A página inicial deve estar um pouco melhor agora!
|
||||
|
||||
# --hints--
|
||||
|
||||
Seu aplicativo deve servir arquivos de ativos do diretório `/public` no caminho `/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: Iniciar um servidor de Express funcional
|
||||
challengeType: 2
|
||||
forumTopicId: 301519
|
||||
dashedName: start-a-working-express-server
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Nas duas primeiras linhas do arquivo `myApp.js`, você pode ver como é fácil criar um objeto do aplicativo Express. Este objeto tem vários métodos e você aprenderá muitos deles nestes desafios. Um método fundamental é o `app.listen(port)`. Ele diz ao servidor para que escute em uma determinada porta, colocando-o em estado de execução. Para fins de teste, precisamos que o aplicativo esteja sendo executado em segundo plano para que adicionemos este método no arquivo `server.js` para você.
|
||||
|
||||
Vamos servir nossa primeira string! No Express, as rotas têm a seguinte estrutura: `app.METHOD(PATH, HANDLER)`. METHOD é um método http em letras minúsculas. PATH é um caminho relativo no servidor (pode ser uma string ou até mesmo uma expressão regular). HANDLER é uma função que o Express chama quando a rota tem correspondência. Os manipuladores têm o formato `function(req, res) {...}`, onde req é o objeto solicitado, e res é o objeto de resposta. Por exemplo, o manipulador
|
||||
|
||||
```js
|
||||
function(req, res) {
|
||||
res.send('Response String');
|
||||
}
|
||||
```
|
||||
|
||||
servirá a string 'Response String'.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use o método `app.get()` para servir a string "Hello Express" para solicitações de GET que correspondam ao caminho `/` (root). Certifique-se de que seu código funciona olhando os logs e, em seguida, veja os resultados na pré-visualização se você estiver usando o Replit.
|
||||
|
||||
**Observação:** todo o código para estas lições deve ser adicionado entre as poucas linhas de código que fornecemos para você no início.
|
||||
|
||||
# --hints--
|
||||
|
||||
Seu aplicativo deve servir a string 'Hello Express'
|
||||
|
||||
```js
|
||||
(getUserInput) =>
|
||||
$.get(getUserInput('url')).then(
|
||||
(data) => {
|
||||
assert.equal(
|
||||
data,
|
||||
'Hello Express',
|
||||
'Your app does not serve the text "Hello Express"'
|
||||
);
|
||||
},
|
||||
(xhr) => {
|
||||
throw new Error(xhr.responseText);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
# --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: Usar o body-parser para analisar solicitações de POST
|
||||
challengeType: 2
|
||||
forumTopicId: 301520
|
||||
dashedName: use-body-parser-to-parse-post-requests
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Além do GET, existe um outro verbo comum de HTTP, o POST. POST é o método padrão usado para enviar dados do client com formulários HTML. Na convenção de REST, POST é usado para enviar dados para criar novos itens no banco de dados (um novo usuário, ou um nova publicação no blog). Você não tem um banco de dados neste projeto, mas vai aprender como lidar com solicitações de POST, mesmo assim.
|
||||
|
||||
Nesse tipo de solicitação, os dados não aparecem no URL. Eles estão ocultos no corpo da solicitação. O corpo (body) é uma parte da solicitação do HTTP, também chamada de payload. Mesmo que os dados não sejam visíveis no URL, isso não significa que sejam privados. Para saber o porquê, consulte o conteúdo bruto de uma solicitação de POST de HTTP:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Como você pode ver, o body é codificado como a string de consulta. Este é o formato padrão usado pelos formulários de HTML. Com o Ajax, você também pode usar JSON para tratar os dados tendo uma estrutura mais complexa. Existe também um outro tipo de codificação: multipart/form-data. Esta é usada para enviar arquivos binários. Neste exercício, você usará um body urlencoded. Para analisar os dados provenientes de solicitações de POST, você deve instalar o pacote `body-parser`. Este pacote permite que você use uma série de middleware, que pode decodificar os dados em diferentes formatos.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Instale o módulo `body-parser` no `package.json`. Em seguida, faça o `require` dele no topo do arquivo. Armazene-o em uma variável chamada `bodyParser`. O middleware para manipular dados urlencoded é retornado por `bodyParser.urlencoded({extended: false})`. Passe a função retornada pela chamada do método anterior para `app.use()`. Como sempre, o middleware deve ser montado antes de todas as rotas que dependem dele.
|
||||
|
||||
**Observação:** `extended` é uma opção de configuração que informa ao `body-parser` que a análise (parsing) precisa ser usada. Quando `extended=false` ele usa a biblioteca clássica de codificação, `querystring`. Quando `extended=true` ele usa a biblioteca `qs` para a análise.
|
||||
|
||||
Ao usar `extended=false`, os valores podem ser apenas strings ou arrays. O objeto retornado ao usar `querystring` não herda prototipicamente do `Object` de JavaScript padrão, o que significa que funções como `hasOwnProperty` e `toString` não estarão disponíveis. A versão estendida permite mais flexibilidade aos dados, mas é superada por JSON.
|
||||
|
||||
# --hints--
|
||||
|
||||
O middleware 'body-parser' deve estar montado
|
||||
|
||||
```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,52 @@
|
||||
---
|
||||
id: 587d7fb1367417b2b2512bf2
|
||||
title: Usar o arquivo .env
|
||||
challengeType: 2
|
||||
forumTopicId: 301521
|
||||
dashedName: use-the--env-file
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
O arquivo `.env` é um arquivo oculto que é usado para passar variáveis de ambiente para seu aplicativo. Este arquivo é secreto, ninguém além de você pode acessá-lo. Ele pode ser usado para armazenar dados que você deseja manter privados ou ocultos. Por exemplo, você pode armazenar chaves da API de serviços externos ou o URI do seu banco de dados. Você também pode usá-lo para armazenar as opções de configuração. Ao definir as opções de configuração, você pode alterar o comportamento de sua aplicação sem a necessidade de reescrever algum código.
|
||||
|
||||
As variáveis de ambiente podem ser acessadas pelo aplicativo usando `process.env.VAR_NAME`. O objeto `process.env` é um objeto global do Node e suas variáveis são passadas como strings. Por convenção, os nomes de variáveis ficam todos em letras maiúsculas, com palavras separadas por um sublinhado. O `.env` é um arquivo shell. Assim, você não precisa encapsular nomes ou valores entre aspas. Também é importante notar que não pode haver espaço em torno do sinal de igual quando você estiver atribuindo valores às suas variáveis, como, por exemplo, `VAR_NAME=value`. Normalmente, você colocará cada definição de variável em uma linha separada.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Vamos adicionar uma variável de ambiente como uma opção de configuração.
|
||||
|
||||
Crie um arquivo `.env` na raiz do diretório do seu projeto e armazene a variável `MESSAGE_STYLE=uppercase` nele.
|
||||
|
||||
Em seguida, no manipulador de rota `/json` do GET que você criou no último desafio, transforme a mensagem do objeto de resposta em letras maiúsculas com `process.env.MESSAGE_STYLE` é igual a `uppercase`. O objeto de resposta deve ser `{"message": "Hello json"}` ou `{"message": "HELLO JSON"}`, dependendo do valor de `MESSAGE_STYLE`.
|
||||
|
||||
**Observação:** se você estiver usando o Replit, você não poderá criar um arquivo `.env`. Em vez disso, use a aba embutida <dfn>SECRETS</dfn> para adicionar a variável.
|
||||
|
||||
# --hints--
|
||||
|
||||
A resposta do endpoint `/json` deve ser alterada de acordo com a variável de ambiente `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: Adicionar uma descrição ao package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301522
|
||||
dashedName: add-a-description-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A próxima parte de um bom arquivo package.json é o campo `description`. É aqui que você deve colocar uma descrição curta, mas informativa, do projeto.
|
||||
|
||||
Se você planeja publicar um pacote no npm, esta é a string que deve vender a ideia ao usuário para que ele decida se deseja instalar o pacote ou não. No entanto, esse não é o único caso de uso para a descrição. Ela é uma ótima maneira de resumir o que um projeto faz. Também é importante, em qualquer projeto do Node.js, ajudar outros desenvolvedores, futuros mantenedores ou, até mesmo, seu futuro eu a entender rapidamente o projeto.
|
||||
|
||||
Independentemente do que você planeja para seu projeto, uma descrição é definitivamente recomendada. Exemplo:
|
||||
|
||||
```json
|
||||
"description": "A project that does something awesome",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione uma `description` ao arquivo package.json do projeto.
|
||||
|
||||
**Observação:** lembre-se de usar aspas duplas para nomes de campo (") e vírgulas (,) para separar os campos.
|
||||
|
||||
# --hints--
|
||||
|
||||
O package.json deve ter uma chave "description" válida
|
||||
|
||||
```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: Adicionar uma licença ao package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301523
|
||||
dashedName: add-a-license-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
O campo `license` é onde você informa aos usuários o que eles têm permissão para fazer com o seu projeto.
|
||||
|
||||
Algumas licenças comuns para projetos de código aberto incluem a MIT e a BSD. Informações de licença não são necessárias. As leis de direitos autorais na maioria dos países lhe darão a propriedade do que você criou por padrão. No entanto, é sempre uma boa prática indicar explicitamente o que os usuários podem e não podem fazer. Aqui está um exemplo do campo license:
|
||||
|
||||
```json
|
||||
"license": "MIT",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Preencha o campo `license` no arquivo package.json do seu projeto conforme achar adequado.
|
||||
|
||||
# --hints--
|
||||
|
||||
O package.json deve ter uma chave "license" válida
|
||||
|
||||
```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: Adicionar uma versão ao package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301525
|
||||
dashedName: add-a-version-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Um dos campos obrigatórios do seu arquivo package.json é o `version`. Este campo descreve a versão atual do seu projeto. Exemplo:
|
||||
|
||||
```json
|
||||
"version": "1.2.0",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione uma `version` ao arquivo package.json do projeto.
|
||||
|
||||
# --hints--
|
||||
|
||||
O package.json deve ter uma chave "version" válida
|
||||
|
||||
```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: Adicionar palavras-chave ao seu package.json
|
||||
challengeType: 2
|
||||
forumTopicId: 301526
|
||||
dashedName: add-keywords-to-your-package-json
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
O campo `keywords` é onde você pode descrever seu projeto usando palavras-chave relacionadas. Exemplo:
|
||||
|
||||
```json
|
||||
"keywords": [ "descriptive", "related", "words" ],
|
||||
```
|
||||
|
||||
Como você pode ver, este campo está estruturado como um array de frases cercadas por aspas duplas.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione uma array de strings adequadas para o campo `keywords` no arquivo package.json do seu projeto.
|
||||
|
||||
Uma das palavras-chave deve ser "freecodecamp".
|
||||
|
||||
# --hints--
|
||||
|
||||
package.json deve ter uma chave "keywords" válida
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
O campo "keywords" deve ser um array
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
O campo "keywords" devem incluir "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: Expandir seu projeto com pacotes externos do npm
|
||||
challengeType: 2
|
||||
forumTopicId: 301527
|
||||
dashedName: expand-your-project-with-external-packages-from-npm
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Uma das maiores razões para usar um gerenciador de pacotes é a sua poderosa gestão de dependências. Em vez de ter que garantir manualmente que tem todas as dependências sempre que você configurar um projeto em um novo computador, o npm instala tudo automaticamente para você. Mas como o npm pode saber exatamente de que seu projeto precisa? Conheça a seção `dependencies` do seu arquivo package.json.
|
||||
|
||||
Nesta seção, pacotes de que seu projeto necessita são armazenados usando o seguinte formato:
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"package-name": "version",
|
||||
"express": "4.14.0"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione a versão "2.14.0" do pacote "moment" ao campo `dependencies` do seu arquivo package.json.
|
||||
|
||||
**Observação:** o moment é uma biblioteca útil para trabalhar com horas e datas.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" deve incluir o "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
A versão do "moment" deve ser a "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: 'Utilizar o package.json, o centro de qualquer projeto do Node.js ou pacote npm'
|
||||
challengeType: 2
|
||||
forumTopicId: 301528
|
||||
dashedName: how-to-use-package-json-the-core-of-any-node-js-project-or-npm-package
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Trabalhar nesses desafios vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-npm/) e complete esses desafios localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-npm) para completar esses desafios.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`. Como opção, envie também um link para o código-fonte do projeto no campo `GitHub Link`.
|
||||
|
||||
O arquivo `package.json` é o centro de qualquer projeto do Node.js ou pacote do npm. Ele armazena informações sobre seu projeto, de modo semelhante ao que a seção <head> de um documento HTML usa para descrever o conteúdo de uma página da web. Ele consiste em um único objeto JSON, onde as informações são armazenadas em pares de chave-valor. Existem apenas dois campos obrigatórios: "name" e "version". Porém, é uma boa prática fornecer informações adicionais sobre o seu projeto que possam ser úteis para futuros usuários ou mantenedores.
|
||||
|
||||
Se você olhar a árvore de arquivos do projeto, você encontrará o arquivo package.json no nível superior da árvore. Este é o arquivo que você vai melhorar nos próximos desafios.
|
||||
|
||||
Uma das informações mais comuns neste arquivo é o campo `author`. Especifica quem criou o projeto e pode consistir em uma string ou um objeto com detalhes de contato ou outros. Um objeto é recomendado para projetos maiores, mas uma string simples como o exemplo a seguir já servirá para este projeto.
|
||||
|
||||
```json
|
||||
"author": "Jane Doe",
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione seu nome como o `author` do projeto no arquivo package.json.
|
||||
|
||||
**Observação:** lembre-se de que você está escrevendo JSON. Então, todos os nomes de campos devem usar aspas duplas (") e ser separados por uma vírgula (,).
|
||||
|
||||
# --hints--
|
||||
|
||||
O package.json deve ter uma chave "author" válida
|
||||
|
||||
```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: Gerenciar dependências do npm entendendo o versionamento semântico
|
||||
challengeType: 2
|
||||
forumTopicId: 301529
|
||||
dashedName: manage-npm-dependencies-by-understanding-semantic-versioning
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As `Versions` (versões) dos pacotes do npm na seção de dependências do seu arquivo package.json seguem o que chamamos de Semantic Versioning (SemVer), um padrão do setor para versionamento de software, com o objetivo de facilitar o gerenciamento de dependências. Bibliotecas, frameworks ou outras ferramentas publicadas no npm devem usar o SemVer para comunicar claramente que tipo de mudanças os projetos podem esperar caso eles atualizem.
|
||||
|
||||
Conhecer o SemVer pode ser útil quando você desenvolve um software que usa dependências externas (algo que você faz quase sempre). Um dia, seu entendimento desses números vai evitar que você introduza acidentalmente alterações que causem problemas em seu projeto, sem compreender por que as coisas que funcionaram ontem, de repente, não funcionam hoje. É assim que o Versionamento Semântico funciona de acordo com o site oficial:
|
||||
|
||||
```json
|
||||
"package": "MAJOR.MINOR.PATCH"
|
||||
```
|
||||
|
||||
A versão MAJOR (principal) deve incrementar quando você fizer alterações incompatíveis na API. A versão MINOR (secundária) deve incrementar quando adicionar funcionalidades retrocompatíveis. A versão PATCH deve incrementar quando você fizer consertos de bugs retrocompatíveis. Isso significa que PATCHes são correções de bugs e MINORs adicionam novas funcionalidades, mas nenhum deles quebra o que funcionava antes. Por fim, as MAJORs adicionam alterações que não funcionarão com versões anteriores.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Na seção de dependências do seu arquivo package.json, altere a `version` do moment para que corresponda à versão MAJOR 2, à versão MINOR 10 e à versão 2 de PATCH
|
||||
|
||||
# --hints--
|
||||
|
||||
As "dependencies" devem incluir o "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
A versão do "moment" deve ser a "2.14.0"
|
||||
|
||||
```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: Remover um pacote de suas dependências
|
||||
challengeType: 2
|
||||
forumTopicId: 301530
|
||||
dashedName: remove-a-package-from-your-dependencies
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Você agora já testou algumas maneiras de gerenciar as dependências do seu projeto usando a seção de dependências do package.json. Você também incluiu pacotes externos, adicionando-os ao arquivo e até dizendo ao npm quais tipos de versões você quer, usando caracteres especiais como o til ou o circunflexo.
|
||||
|
||||
Mas e se você quisesse remover um pacote externo do qual você não precisa mais? Você já deve ter adivinhado: apenas remova o par chave-valor correspondente a esse pacote das dependências.
|
||||
|
||||
Este mesmo método também se aplica à remoção de outros campos no seu package.json
|
||||
|
||||
# --instructions--
|
||||
|
||||
Remover o pacote do moment de suas dependências.
|
||||
|
||||
**Observação:** certifique-se de que você tem a quantidade certa de vírgulas depois de removê-lo.
|
||||
|
||||
# --hints--
|
||||
|
||||
As "dependencies" não devem incluir o "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: Usar o circunflexo para usar a última versão secundária de uma dependência
|
||||
challengeType: 2
|
||||
forumTopicId: 301531
|
||||
dashedName: use-the-caret-character-to-use-the-latest-minor-version-of-a-dependency
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Da mesma forma que o til, que aprendemos no último desafio e que permite que o npm instale o último PATCH de uma dependência, o circunflexo (`^`) permite que o npm instale atualizações futuras também. A diferença é que o circunflexo permitirá tanto atualizações MINOR quanto PATCHes.
|
||||
|
||||
Sua versão atual neste momento deve ser "~2.10.2", o que permite que o npm instale a versão 2.10.x mais recente. Se você usasse o circunflexo (^) como um prefixo de versão, o npm teria permissão para atualizar para qualquer versão 2.x.x.
|
||||
|
||||
```json
|
||||
"package": "^1.3.8"
|
||||
```
|
||||
|
||||
Isso permitiria atualizações para qualquer versão 1.x.x do pacote.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use o circunflexo (`^`) para prefixar a versão do momento em suas dependências e permitir que o npm atualize para qualquer versão MINOR.
|
||||
|
||||
**Observação:** os números da versão em si não devem ser alterados.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" deve incluir o "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
A versão do "moment" deve corresponder a "^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: Usar o til para usar sempre a última versão de patch de uma dependência
|
||||
challengeType: 2
|
||||
forumTopicId: 301532
|
||||
dashedName: use-the-tilde-character-to-always-use-the-latest-patch-version-of-a-dependency
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
No último desafio, você disse ao npm para incluir apenas uma versão específica de um pacote. Essa é uma maneira útil de congelar suas dependências, caso você precise garantir que diferentes partes do seu projeto permaneçam compatíveis entre si. Mas, na maioria dos casos de uso, você não quer perder as correções de erros, já que elas geralmente incluem correções de segurança importantes e (esperamos que) não quebrem nada ao fazer isso.
|
||||
|
||||
Para permitir que uma dependência do npm atualize para a última versão de PATCH, você pode prefixar a versão da dependência com o caractere de til (`~`). Aqui está um exemplo de como permitir atualizações para qualquer versão 1.3.x.
|
||||
|
||||
```json
|
||||
"package": "~1.3.8"
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
No arquivo package.json, sua regra atual de como o npm pode atualizar o moment é usar uma versão específica (2.10.2). Mas agora, você deseja permitir a última versão de 2.10.x.
|
||||
|
||||
Use o caractere de til (`~`) para prefixar a versão do momento em suas dependências e permitir que o npm atualize para qualquer versão de PATCH.
|
||||
|
||||
**Observação:** os números da versão em si não devem ser alterados.
|
||||
|
||||
# --hints--
|
||||
|
||||
"dependencies" deve incluir o "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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
A versão do "moment" deve corresponder a "~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: Encadear auxiliares de consulta para restringir resultados de pesquisa
|
||||
challengeType: 2
|
||||
forumTopicId: 301533
|
||||
dashedName: chain-search-query-helpers-to-narrow-search-results
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Se você não passar o callback como o último argumento para `Model.find()` (ou para outros métodos de pesquisa), a consulta não é executada. Você pode armazenar a consulta em uma variável para uso posterior. Esse tipo de objeto permite que você crie uma consulta usando a sintaxe de encadeamento. A pesquisa real do banco de dados é executada quando você finalmente encadear o método `.exec()`. Você sempre precisa passar seu callback para este último método. Existem muitos auxiliares de consulta. Aqui, usaremos os mais comuns.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `queryChain` para que encontre pessoas que gostam do alimento especificado pela variável `foodToSearch`. Classifique-os por `name`, limite os resultados a dois documentos e oculte idade deles. Encadeie `.find()`, `.sort()`, `.limit()`, `.select()`e, então, `.exec()`. Passe a callback `done(err, data)` para `exec()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso em encadear auxiliares de consulta
|
||||
|
||||
```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: Criar um modelo
|
||||
challengeType: 2
|
||||
forumTopicId: 301535
|
||||
dashedName: create-a-model
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**C**RUD I Parte I - CREATE
|
||||
|
||||
Em primeiro lugar, precisamos de um schema. Cada schema mapeia para uma coleção do MongoDB. Ele define a forma dos documentos dentro daquela coleção. Os schemas são os blocos que compõem os modelos. Eles podem ser aninhados para criar modelos complexos, mas nesse caso vamos simplificar as coisas. Um modelo permite que você crie instâncias de seus objetos, chamados documentos.
|
||||
|
||||
O Replit é um servidor real. Em servidores reais, as interações com o banco de dados acontecem em funções de manipulador. Estas funções são executadas quando algum evento acontece (por exemplo, alguém atinge um endpoint na sua API). Seguiremos a mesma abordagem nestes exercícios. A função `done()` é um callback que nos diz que podemos prosseguir após concluir uma operação assíncrona, como inserir, pesquisar, atualizar ou excluir. Ela segue a convenção do Node e deve ser chamada como `done(null, data)` quando houver sucesso, ou `done(err)` quando houver erro.
|
||||
|
||||
Aviso - Ao interagir com serviços remotos, podem ocorrer erros!
|
||||
|
||||
```js
|
||||
/* Example */
|
||||
|
||||
const someFunc = function(done) {
|
||||
//... do something (risky) ...
|
||||
if (error) return done(error);
|
||||
done(null, result);
|
||||
};
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Crie um schema de pessoa chamado `personSchema` que tenha este protótipo:
|
||||
|
||||
```markup
|
||||
- Person Prototype -
|
||||
--------------------
|
||||
name : string [required]
|
||||
age : number
|
||||
favoriteFoods : array of strings (*)
|
||||
```
|
||||
|
||||
Use os tipos de schemas básicos de Mongoose. Se você quiser, também pode adicionar mais campos, usar validadores simples, como required ou unique, e definir valores padrão. Veja a [documentação do Mongoose](http://mongoosejs.com/docs/guide.html).
|
||||
|
||||
Agora, crie um modelo chamado `Person` do `personSchema`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve criar uma instância de um esquema mongoose com sucesso
|
||||
|
||||
```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: Criar e salvar um registro de um modelo
|
||||
challengeType: 2
|
||||
forumTopicId: 301536
|
||||
dashedName: create-and-save-a-record-of-a-model
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Neste desafio, você terá que criar e salvar um registro de um modelo.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Dentro da função `createAndSavePerson`, crie uma instância de documento usando o construtor de modelo `Person` que você criou antes. Passe para o construtor um objeto que tenha os campos `name`, `age` e `favoriteFoods`. Seus tipos devem estar em conformidade com os que estão no `personSchema`. Em seguida, chame o método `document.save()` na instância do documento retornado. Passe a ele um callback usando a convenção do Node. Este é um padrão comum. Todos os métodos CRUD a seguir recebem uma função de callback como essa como o último argumento.
|
||||
|
||||
```js
|
||||
/* Example */
|
||||
|
||||
// ...
|
||||
person.save(function(err, data) {
|
||||
// ...do your stuff here...
|
||||
});
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso na criação e no salvamento de itens do banco de dados
|
||||
|
||||
```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: Criar muitos registros com model.create()
|
||||
challengeType: 2
|
||||
forumTopicId: 301537
|
||||
dashedName: create-many-records-with-model-create
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Às vezes, você precisa criar muitas instâncias dos seus modelos. Por exemplo, ao fazer o seeding de um banco de dados com os dados iniciais. `Model.create()` recebe um array de objetos como `[{name: 'John', ...}, {...}, ...]` como o primeiro argumento e o salva no banco de dados.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `createManyPeople` para criar muitas pessoas usando `Model.create()` com o argumento `arrayOfPeople`.
|
||||
|
||||
**Observação:** você pode reutilizar o modelo que você instanciou no exercício anterior.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso na criação de muitos itens de banco de dados ao mesmo tempo
|
||||
|
||||
```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: Excluir vários documentos com model.remove()
|
||||
challengeType: 2
|
||||
forumTopicId: 301538
|
||||
dashedName: delete-many-documents-with-model-remove
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`Model.remove()` é útil para excluir todos os documentos que correspondem a determinados critérios.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `removeManyPeople` para excluir todas as pessoas cujo nome esteja dentro da variável `nameToRemove`, usando `Model.remove()`. Passe-a a um documento de consulta com o campo `name` definido e uma função de callback.
|
||||
|
||||
**Observação:** `Model.remove()` não retorna o documento excluído, mas um objeto JSON que contém o resultado da operação e o número de itens afetado. Não se esqueça de passar o objeto para a função de callback `done()`, já que a usamos nos testes.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso na exclusão de vários itens
|
||||
|
||||
```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: Excluir um documento usando model.findByIdAndRemove
|
||||
challengeType: 2
|
||||
forumTopicId: 301539
|
||||
dashedName: delete-one-document-using-model-findbyidandremove
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`findByIdAndRemove` e `findOneAndRemove` são como os métodos da atualização anterior. Eles passam o documento removido para a db. Como de costume, use o argumento da função `personId` como chave de pesquisa.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `removeById` para excluir uma pessoa pelo `_id` da pessoa. Você deve usar um dos métodos `findByIdAndRemove()` ou `findOneAndRemove()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
A exclusão de um item deve ser bem-sucedida
|
||||
|
||||
```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: Instalar e configurar o Mongoose
|
||||
challengeType: 2
|
||||
forumTopicId: 301540
|
||||
dashedName: install-and-set-up-mongoose
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Trabalhar nesses desafios vai fazer com que você escreva seu código usando um dos seguintes métodos:
|
||||
|
||||
- Clone [este repositório do GitHub](https://github.com/freeCodeCamp/boilerplate-mongomongoose/) e complete esses desafios localmente.
|
||||
- Use [nosso projeto inicial do Replit](https://replit.com/github/freeCodeCamp/boilerplate-mongomongoose) para completar esses desafios.
|
||||
- Use um construtor de site de sua escolha para completar o projeto. Certifique-se de incorporar todos os arquivos do nosso repositório no GitHub.
|
||||
|
||||
Quando terminar, certifique-se de que uma demonstração funcional do seu projeto está hospedada em algum lugar público. Em seguida, envie o URL para ela no campo `Solution Link`.
|
||||
|
||||
Neste desafio, você vai configurar um banco de dados do MongoDB Atlas e importar os pacotes necessários para se conectar a ele.
|
||||
|
||||
Siga <a href='https://www.freecodecamp.org/news/get-started-with-mongodb-atlas/' rel='noopener noreferrer' target='_blank'>este tutorial</a> para configurar um banco de dados hospedado no MongoDB Atlas.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Adicione `mongodb` e `mongoose` ao `package.json` do projeto. Depois, solicite o mongoose como `mongoose` no `myApp.js`. Crie um arquivo `.env` e adicione uma variável `MONGO_URI` a ele. Esse valor deve ser o URI de banco de dados do MongoDB Atlas. Não se esqueça de cercar o URI com aspas simples ou duplas. Lembre-se de que você não pode usar espaços ao redor de `=` em variáveis de ambiente. Por exemplo, `MONGO_URI='VALUE'`. Quando terminar, conecte-se ao banco de dados utilizando a seguinte sintaxe:
|
||||
|
||||
```js
|
||||
mongoose.connect(<Your URI>, { useNewUrlParser: true, useUnifiedTopology: true });
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
A dependência "mongodb" deve estar no 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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
A dependência "mongoose" deve estar no 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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
O "mongoose" deve estar conectado a um banco de dados
|
||||
|
||||
```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: 'Realizar atualizações clássicas executando Find, Edit e Save'
|
||||
challengeType: 2
|
||||
forumTopicId: 301541
|
||||
dashedName: perform-classic-updates-by-running-find-edit-then-save
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Nos bons e velhos tempos, era isso que você precisava fazer se você quisesse editar um documento e ser capaz de usá-lo de algum modo (ou seja, enviando o documento de volta em uma resposta do servidor). O Mongoose tem um método dedicado à atualização: `Model.update()`. Ele está vinculado ao driver do mongo de nível mais baixo. Ele pode editar em massa muitos documentos que correspondem a certos critérios, mas não envia de volta o documento atualizado, apenas uma mensagem de 'status'. Além disso, ele dificulta as validações de modelo, porque apenas chama diretamente o driver do mongo.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `findEditThenSave` para encontrar uma pessoa por `_id` (use qualquer um dos métodos acima) com o parâmetro `personId` como chave de pesquisa. Adicione `"hamburger"` à lista dos `favoriteFoods` da pessoa (você pode usar `Array.push()`). Em seguida, dentro do callback de find, use `save()` para salvar a `Person` atualizada.
|
||||
|
||||
**Observação:** isso pode ser complicado, se em seu Schema você declarou as `favoriteFoods` como um array, sem especificar o tipo (por exemplo, `[String]`). Nesse caso, `favoriteFoods` tem como padrão o tipo Mixed e você precisa marcá-lo manualmente como editado usando `document.markModified('edited-field')`. Consulte a [documentação do Mongoose](https://mongoosejs.com/docs/schematypes.html#Mixed)
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso em encontrar, editar e atualizar um item
|
||||
|
||||
```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: Executar novas atualizações em um documento usando model.findOneAndUpdate()
|
||||
challengeType: 2
|
||||
forumTopicId: 301542
|
||||
dashedName: perform-new-updates-on-a-document-using-model-findoneandupdate
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Versões recentes do Mongoose possuem métodos para simplificar a atualização dos documentos. Alguns recursos mais avançados (como os hooks pre/post, validação, entre outros) se comportam de modo diferente com esta abordagem. Assim, o método clássico ainda é útil em muitas situações. `findByIdAndUpdate()` pode ser usado na busca por id.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `findAndUpdate` para encontrar uma pessoa por `Name` e defina a idade da pessoa como `20`. Use o parâmetro `personName` da função como chave de pesquisa.
|
||||
|
||||
**Observação:** você deve retornar o documento atualizado. Para fazer isso, você precisa passar o documento de opções `{ new: true }` como o terceiro argumento para `findOneAndUpdate()`. Por padrão, esses métodos retornam o objeto não modificado.
|
||||
|
||||
# --hints--
|
||||
|
||||
Usar findOneAndUpdate em um item deve ser bem-sucedido
|
||||
|
||||
```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: Usar model.find() para procurar no seu banco de dados
|
||||
challengeType: 2
|
||||
forumTopicId: 301543
|
||||
dashedName: use-model-find-to-search-your-database
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Em seu uso mais simples, `Model.find()` aceita um documento de consulta (um objeto JSON) como o primeiro argumento e depois um callback. Ele retorna um array de correspondências. Ele dá suporte a uma variedade extremamente ampla de opções de pesquisa. Leia mais na documentação.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `findPeopleByName` para encontrar todas as pessoas que tenham um determinado nome, usando <code>Model.find() -\> [Person]</code>
|
||||
|
||||
Use o argumento `personName` da função como chave de pesquisa.
|
||||
|
||||
# --hints--
|
||||
|
||||
Localize todos os itens correspondentes a um critério com sucesso
|
||||
|
||||
```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: Usar model.findById() para procurar no seu banco de dados por _id
|
||||
challengeType: 2
|
||||
forumTopicId: 301544
|
||||
dashedName: use-model-findbyid-to-search-your-database-by-id
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Ao salvar um documento, o MongoDB adiciona automaticamente o campo `_id`, e define-o como uma chave alfanumérica única. Procurar por `_id` é uma operação extremamente frequente, então o Mongoose fornece um método dedicado para isso.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique `findPersonById` para encontrar a única pessoa com um `_id` dado, usando `Model.findById() -> Person`. Use o argumento `personId` da função como chave de pesquisa.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso em encontrar um item por 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: Usar model.findOne() para retornar um único documento correspondente a partir do seu banco de dados
|
||||
challengeType: 2
|
||||
forumTopicId: 301545
|
||||
dashedName: use-model-findone-to-return-a-single-matching-document-from-your-database
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`Model.findOne()` se comporta como `Model.find()`, mas retorna apenas um documento (não um array), mesmo que existam vários itens. É especialmente útil ao pesquisar por propriedades que você declarou como exclusivas.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Modifique a função `findOneByFood` para encontrar apenas uma pessoa que tenha uma certa comida nos seus favoritos, usando o modelo `Model.findOne() -> Person`. Use o argumento `food` da função como chave de pesquisa.
|
||||
|
||||
# --hints--
|
||||
|
||||
Você deve ter sucesso em encontrar um item
|
||||
|
||||
```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