curriculum/challenges/english/blocks/information-security-projects/587d824a367417b2b2512c44.md
Build a full-stack JavaScript app that is functionally similar to this: <a href="https://stock-price-checker.freecodecamp.rocks/" target="_blank" rel="noopener noreferrer nofollow">https://stock-price-checker.freecodecamp.rocks/</a>.
Since all reliable stock price APIs require an API key, we've built a workaround. Use <a href="https://stock-price-checker-proxy.freecodecamp.rocks/" target="_blank" rel="noopener noreferrer nofollow">https://stock-price-checker-proxy.freecodecamp.rocks/</a> to get up-to-date stock price information without needing to sign up for your own key.
Working on this project will involve you writing your code using one of the following methods:
NODE_ENV environment variable to test, without quotesroutes/api.js or by creating a handler/controllerserver.jstests/2_functional-tests.jsNote Privacy Considerations: Due to the requirement that only 1 like per IP should be accepted, you will have to save IP addresses. It is important to remain compliant with data privacy laws such as the General Data Protection Regulation. One option is to get permission to save the user's data, but it is much simpler to anonymize it. For this challenge, remember to anonymize IP addresses before saving them to the database. If you need ideas on how to do this, you may choose to hash the data, truncate it, or set part of the IP address to 0.
Write the following tests in tests/2_functional-tests.js:
/api/stock-prices//api/stock-prices//api/stock-prices//api/stock-prices//api/stock-prices/You can provide your own project, not the example URL.
assert(
!/.*\/stock-price-checker\.freecodecamp\.rocks/.test(code)
);
You should set the content security policies to only allow loading of scripts and CSS from your server.
const data = await fetch(code + '/_api/app-info');
const parsed = await data.json();
assert.isTrue(
parsed.headers['content-security-policy'].includes("script-src 'self'")
);
assert.isTrue(
parsed.headers['content-security-policy'].includes("style-src 'self'")
);
You can send a GET request to /api/stock-prices, passing a NASDAQ stock symbol to a stock query parameter. The returned object will contain a property named stockData.
const data = await fetch(
code + '/api/stock-prices?stock=GOOG'
);
const parsed = await data.json();
assert.property(parsed, 'stockData');
The stockData property includes the stock symbol as a string, the price as a number, and likes as a number.
const data = await fetch(
code + '/api/stock-prices?stock=GOOG'
);
const parsed = await data.json();
const ticker = parsed.stockData;
assert.typeOf(ticker.price, 'number');
assert.typeOf(ticker.likes, 'number');
assert.typeOf(ticker.stock, 'string');
You can also pass along a like field as true (boolean) to have your like added to the stock(s). Only 1 like per IP should be accepted.
If you pass along 2 stocks, the returned value will be an array with information about both stocks. Instead of likes, it will display rel_likes (the difference between the likes on both stocks) for both stockData objects.
const data = await fetch(
code + '/api/stock-prices?stock=GOOG&stock=MSFT'
);
const parsed = await data.json();
const ticker = parsed.stockData;
assert.typeOf(ticker, 'array');
assert.property(ticker[0], 'rel_likes');
assert.property(ticker[1], 'rel_likes');
All 5 functional tests are complete and passing.
const tests = await fetch(code + '/_api/get-tests');
const parsed = await tests.json();
assert.isTrue(parsed.length >= 5);
parsed.forEach((test) => {
assert.equal(test.state, 'passed');
});