fullstack-hy2020 / fullstack-hy2020.github.io Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://fullstack-hy2020.github.io
License: Other
Home Page: https://fullstack-hy2020.github.io
License: Other
Lesson 5b introduces a pattern to create reusable components that wrap child components, in particular a Toggleable component.
Excercise 5.5 encourages students to use the Toggleable component. As with most coding that is meant to be robust and reusable, this approach is more involved.
Exercise 5.7 is written in a manner that makes the investment in reuseable code worthless. From the course text, "even though the functionality implemented in this part is almost identical to the functionality provided by the Togglable component, the component can not be used directly to achieve the desired behavior."
In Part 5b a custom ESLint configuration is created that tries to override the one supplied by create-react-app
. This approach is not quite optimal: the editor integration and the npm lint
task work, but create-react-app
does not pick up it up, thus not showing the lint warnings in the terminal and in-browser lint output.
The official and experimental way to customize the ESLint config is described in the CRA docs:
[...] It is now possible to extend the base ESLint config by setting the
EXTEND_ESLINT
environment variable totrue
. [...]Note that any rules set to
"error"
will stop the project from building.There are a few things to remember:
- We highly recommend extending the base config, as removing it could introduce hard-to-find issues.
- When working with TypeScript, you'll need to provide an overrides object for rules that should only target TypeScript files.
In the below example:
- the base config has been extended by a shared ESLint config,
- a new rule has been set that applies to all JavaScript and TypeScript files, and
- a new rule has been set that only targets TypeScript files.
{ "eslintConfig": { "extends": ["react-app", "shared-config"], "rules": { "additional-rule": "warn" }, "overrides": [ { "files": ["**/*.ts?(x)"], "rules": { "additional-typescript-only-rule": "warn" } } ] } }
Where could I get the exercise solution after I submit the answer?
replace xx/yy in part zero
Part 9c contains a section on proofing requests where parseComment function implements a check as if (!comment || !isString(comment))
.
However, both picture 28 and 29 show the same check implemented as if (comment || !isValidString(comment))
. The missing exclamation mark causes the check to throw an error if comment is not null.
Pictures should be updated to match the code presented in text to show a proper null check and prevent people running into issues when creating their own implementations based on the pictures.
I realize that these are small code snippets but I feel like it conflicts with the paragraph right before "refactoring modules", which is aptly named "Anti-pattern: array indexes as keys" and emphasizes that such practice should be avoided.
I feel like, for beginners, the rule that array indexes should be avoided must be also followed down to the last snippet, otherwise confusion will ensue.
The following example:
const App = ({ notes }) => {
return (
<div>
<h1>Notes</h1>
<ul>
{notes.map((note, i) =>
<li key={i}>
{note.content}
</li>
)}
</ul>
</div>
)
}
should become:
const App = ({ notes }) => {
return (
<div>
<h1>Notes</h1>
<ul>
{notes.map(note =>
<li key={note.id}>
{note.content}
</li>
)}
</ul>
</div>
)
}
And again the example right after:
const Note = ({ note }) => {
return (
<li>{note.content}</li>
)
}
const App = ({ notes }) => {
return (
<div>
<h1>Notes</h1>
<ul>
{notes.map((note, i) =>
<Note key={i} note={note} />
)}
</ul>
</div>
)
}
should change into:
const Note = ({ note }) => {
return (
<li>{note.content}</li>
)
}
const App = ({ notes }) => {
return (
<div>
<h1>Notes</h1>
<ul>
{notes.map(note =>
<Note key={note.id} note={note} />
)}
</ul>
</div>
)
}
I understand that with these code snippets such issues are of no consequence, but I still believe that it's important to demonstrate best practices as much as possible.
In part 3a, on line 20, link in part 1, leads to a 404 - Page not found; Uncaught ReferenceError: unknown is not defined.
Add the steps for declaring environment variables in heroku as env file is not available on github so it is not present for heroku.
The verb "consists" is misspelled as "concists" at the page below:
Part 9.a
Hi, so I followed the steps in this chapter with the phonebook exercise.
But after incuding the proxy, when I try to use development-mode (to see changes to the frontend on the fly), the request to the http://localhost:3001/api/persons
results in a 431 Request Header Fields Too Large
.
How can I fix this?
Thanks in advance.
In Part 9.c, there are orthographic variants between addEntry, addDiary and addDiaryEntry.
The learners may be confused because they have been swapped in the middle of the story.
Modern JavaScript versions are incorrectly called by their edition, for example ES6, ES7 or ES10 instead of their official name ES2015, ES2016 and ES2019. The book "You don't know JS" recommends using the official names too:
Don't use terms like "JS6" or "ES8" to refer to the language. Some do, but those terms only serve to perpetuate confusion. "ES20xx" or just "JS" are what you should stick to.
Toolbar title sets course's year to 2019 instead of current year 2020.
Refactor the Content component so that it does not render any names of parts or their number of exercises by itself. Instead, it only renders three Part components of which each renders the name and number of exercises of one part.
const Content = ... {
return (
<div>
<Part .../>
<Part .../>
<Part .../>
</div>
)
}
A look at the above code and the explanation given is confusing as the part component is to be called three (3) times but the parts and their exercises are declared in the App component. Can you please share a code snippet of your implementation.
Here is what I have achieved based on the above, Kindly let me know if that is the intended out put
const Part = (props) => {
return (
<p>{props.part} - {props.exercises} exercises</p>
)
}
const Content = (props) => {
return (
<div>
<Part part={props.part} exercises={props.exercises} />
</div>
)
}
const App = () => {
const course = 'Half Stack application development'
const part1 = 'Fundamentals of React'
const exercises1 = 10
const part2 = 'Using props to pass data'
const exercises2 = 7
const part3 = 'State of a component'
const exercises3 = 14
return (
<div>
<Header course={course} />
<Content part={part1} exercises={exercises1} />
<Content part={part2} exercises={exercises2} />
<Content part={part3} exercises={exercises3} />
<Total exercises={exercises1 + exercises2 + exercises3} />
</div>
);
}
In the first part of the course, we're asked to create a new react app, part1
npx create-react-app part1
cd part1
Towards the end of the unit, we're recommended to create multiple create-react-apps in the following folder structure:
part0
part1
courseinfo
unicafe
anectodes
Is this intended? If so, then at this point of the lecture, we'll have react apps nested within a react app.
resolvers/defaults resolvers links to the root page of the graphql-tools page (rather than what seems like previously the apollographql webpage):
https://www.graphql-tools.com/docs/introduction/#Resolver-function-signature
i think ultimately you want the following:
https://fullstackopen.com/en/part5/testing_react_apps#snapshot-testing introduces snapshot testing as another tool but does not show its relationship to integration and units tests, nor provide guidance when to use it. Can it completely replace the other ones? Does it make sense to combine them? How does a snapshot test look like? How and where are the snapshot stored? Updated?
Mongoose 5.9.7 is breaking the error handler middleware and causing the "invalid id" unit test to fail because the middleware no longer recognises that the CastError
should yield a 400 HTTP response.
More specifically when the "invalid id" is sent to the database during the unit test, version 5.9.7 of the Mongoose library is raising an exception where the kind
property of the error is undefined
instead of ObjectId
. This in turn is causing the error handler middleware to fall though and yield a 500 response instead of the 400 the unit test expects.
// Error handler middleware from utils\middleware.js
const errorHandler = (error, request, response, next) => {
// The if statement below is broken in Mongoose 5.9.7 because error.kind is undefined
if (error.name === 'CastError' && error.kind === 'ObjectId') {
return response.status(400).send({ error: 'malformatted id' })
}
An example of the exception from Mongoose 5.9.7 is shown below:
console.error utils/logger.js:8
Cast to ObjectId failed for value "5a3d5da59070081a82a3445" at path "_id" for model "Note"
console.log utils/middleware.js:18
error: MongooseError {
message: 'Cast to ObjectId failed for value "5a3d5da59070081a82a3445" at path "_id" for model "Note"',
name: 'CastError',
messageFormat: undefined,
stringValue: '"5a3d5da59070081a82a3445"',
kind: undefined,
value: '5a3d5da59070081a82a3445',
path: '_id',
reason: Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
I've tested Mongoose 5.9.6 and earlier versions and they do not appear to be affected. I only noticed this because npm install --save mongoose
currently installs 5.9.7 by default.
The changelog for the 5.9.7 Mongoose release would indicate cast related functionality has been changed but I have been unable to ascertain whether this CastError
behaviour change was intentional.
I'm happy to submit a PR for a note in the course somewhere if someone can advise how this problem should be addressed. I imagine more people will be hitting this issue soon if npm
is installing 5.9.7 Mongoose by default.
Only shows:
(koodi tähän)
instead of the actual code
The course is using an old version of the React Developer Tools. I first noticed it when the screenshot in the course looks very different from the current extension I installed today: instead of having a React
tab in the developer toolbar, now there are two tabs named Components
and Profiler
.
The UI has improved a lot, so the following paragraph in the course is no longer true:
Unfortunately the current version of React developer tools leaves something to be desired when displaying component state created with hooks:
This is how it looks now:
So the text and image in the course should be removed or updated
Bug found as explained in the title. When google translate is enabled to translate the page to another languages and the page is scrolled upward, the navigation bar will keep flashing.
Google auto-translate to English, Japanese, Arabic, were tested and all showed the same issues. Test was done with Google Chrome.
The following spelling corrections should be performed in part 9.b:
princibles -> principles
running running -> running the
ts-nodeby -> ts-node by
unexcpeted -> unexpected
sript -> script
Also, the link "tsconfig page" sends the user to an already non-existing page, with the alert: the page has been removed.
Dead link
This happens on Firefox Developer edition, especially on a restored session where I have exited the browser with say, part0 section b in one of the tabs. On reopening the browser the page may end up in a loop refreshing things - I have duckduckgo privacy essentials, and uBlock origin enabled.
I have encountered below two issues while learning mutations in Graphql-React app:-
In image below an extra bit of code is provided after onError handler as highlighted in image below
Additionally as shown in image below, there is new code in app.js for error handling while mutation, most of which, is highlighted by lighter shade but there is some missed new code not being highlighted.
In the exercises of part 2b it says
Brief reminder from the previous part: when you are forming strings that contain values from variables, it is recommended to use a template string:
But template strings were never mentioned before. They should probably be mentioned in part 1b that talks about javascript
Exercise 6.19 begins with the following assumption:
The redux store is currently passed to all of the components through props.
Which, if I am not mistaken, is untrue if we've been following the previous exercises that required us to use the newer useSelector()
hook. It was also stated in the beginning of the chapter that
In new applications you should absolutely use the hook-api, but knowing how to use connect is useful when maintaining older projects using redux.
It seems the instructions for the exercises should reflect this and mention that we are to use an older method for legacy purposes, and reiterate that for new projects we should probably be using the useSelector()
hook-api.
Also, perhaps it would be helpful for many of the students if a separate project could be provided, so we will not be thoughtlessly overwriting the newer method of state management that we can later reference as notes.
Here is the code
const App = ({ notes }) =>
return (
<div>
<h1>Notes</h1>
<ul>
{notes.map((note, i) =>
<Note key={i} note={note} />
)}
</ul>
</div>
)
}
Shorthand arrow functions can't take a return statement.
Osassa 0 kappaleessa Full stack -harjoitustyö päättyy varmaankin liian aikaisin ja siinä pitäisi lopussa varmaan vielä jotain lukea (lause ainakin jää kesken).
When you are talking about the developer consel in part0:
https://fullstackopen.com/en/part0/fundamentals_of_web_apps
you could add something funny in the console.log for curious people that tried the tool at the exact same page. Or like a comment in the code of a HTTP GET request ;)
When testing token verification where the token is missing one letter, I receive the following error instead of the one mentioned in the lesson (JsonWebTokenError: invalid signature). Extending my error handling middleware like as instructed in the lesson did not fix this issue. I tried googling and couldn't find a solution I understood. I need help debugging this
Unexpected token < in JSON at position 25
Unexpected token < in JSON at position 25
SyntaxError: Unexpected token < in JSON at position 25
at JSON.parse (<anonymous>)
Here is my list of dependency:
"dependencies": {
"bcrypt": "^5.0.0",
"cors": "^2.8.5",
"cross-env": "^7.0.2",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.15",
"mongoose": "^5.9.20",
"mongoose-unique-validator": "^2.0.3",
"morgan": "^1.10.0"
},
good day! tnx for your work.
can we translate this course into russian?
we can fork the repository and add a ru
folder.
also we can write here about our progress.
Part 3C uses the following code -
app.use(express.static('build'))
app.use(express.json())
app.use(logger)
app.post('/api/notes', (request, response) => {
const body = request.body
// ...
})
Here is my code -
require("dotenv").config()
const express = require("express")
const cors = require("cors")
const Blog = require("./models/blog")
const app = express()
app.use(express.static("build"))
app.use(express.json())
app.use(logger)
app.use(cors())
// home page
app.get("/", (req, res) => {
res.send("This is a blogpost.")
})
.
.
.
I get the following error -
app.use(logger)
^
ReferenceError: logger is not defined
at Object.<anonymous> (/full_stack_js/part_4/A/index.js:9:9)
Encountered an error where the test fails if your app already contains 'new note' somewhere on the page.
fullstack-hy2020.github.io/src/content/5/en/part5d.md
Section: Testing new note form (line 365)
describe('Note app', function() {
// ..
describe('when logged in', function() {
beforeEach(function() {
cy.contains('login').click()
cy.get('input:first').type('mluukkai')
cy.get('input:last').type('salainen')
cy.get('#login-button').click()
})
it('a new note can be created', function() {
cy.contains('new note').click()
cy.get('input').type('a note created by cypress')
cy.contains('save').click()
cy.contains('a note created by cypress')
})
})
})
As you can see in the screenshot, the login succeeds, but the test is run before the login response is rendered.
What's confusing is the test passes if your db doesn't contain anything with 'new note' even if we don't confirm login success. This is due to the default assertions of cypress commands.
cy.contains()
expects the element with content to eventually exist in the DOM.
If 'new note' text doesn't exist on the page, cy.contains()
automatically retries when it does (in this case, after login success). However, since 'new note' existed in one of my note objects, cy.contains()
referenced the rendered note object text right away instead of the new note button that would appear after our login success.
I think a small section on Assertions should be added to the course material to expand on the core functionality of Cypress commands.
To temporarily get around this, I added cy.contains('<your user name> logged in')
to the beforeEach() function after the login button is clicked. This confirms your login state before moving on to the tests.
describe('Note app', function() {
// ..
describe('when logged in', function() {
beforeEach(function() {
cy.contains('login').click()
cy.get('input:first').type('<your user name>')
cy.get('input:last').type('<your password>')
cy.get('#login-button').click()
cy.contains('<your user name> logged in')
})
it('a new note can be created', function() {
//...
})
})
})
This issue is avoided in the following section, Bypassing the UI (line 745), by using cy.request()
to login rather than relying on the form.
It happened a lot of time, that when I just gobbled up searching where is the code talking about, in which file the code belongs, although the code repositories are good though. But if we could get the file names at the top of each snippet to which they belog, it would be huge help to newcomers throughout the course.
Thanks!!
In Part 5a the JWT, user name and name are stored in the localStorage
so the user is still authenticated after a page reload. This suggests the reader to be a "best practice". This method should never be used in production due to security risks:
From the OWASP Cheat Sheet Series - HTML 5 Security:
- [...] any authentication your application requires can be bypassed by a user with local privileges to the machine on which the data is stored. Therefore, it's recommended not to store any sensitive information in local storage.
[...]- A single Cross Site Scripting can be used to steal all the data in these objects, so again it's recommended not to store sensitive information in local storage.
A single Cross Site Scripting can be used to load malicious data into these objects too, so don't consider objects in these to be trusted.- Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
[...]
From the OWASP Cheat Sheet Series - Session Management:
In general, secure or sensitive data should not be stored persistently in browser data stores as this may permit information leakage on shared systems. Because the Web Storage mechanisms are APIs, this also permits access from injected scripts, making it less secure than cookies with the httponly flag applied. While a case could be made for storing workflow specific data in sessionStorage for use by that specific tab/window across reloads, the Web Storage APIs should be treated as insecure storage. Because of this, if a business solution requires the use of the localStorage or sessionStorage to store sensitive data, such a solution should encipher data and apply replay protections. Due to the potential to access Web Storage APIs via an XSS attack, session identifiers should be stored using non-persistent cookies, with the appropriate flags to protect from insecure access (Secure), XSS (HttpOnly) and CSRF issues (SameSite).
A note should be added to clarify that the persistence of JWTs or session information in general in localStorage/sessionStorage is not recommended in production applications.
Exercise 9.16 instructs students to expand Patient interface by adding an array for entries. Attached image 38a shows an empty array of entries should be included in the response. However, this seems to require additional measures such as adding an empty array to each patient's JSON object or adding the array when creating the response.
I believe additional steps should be documented or image updated to reflect the actual expected response.
The code for the notes application uploaded to github in part 7.1 returns "TypeError: Cannot read property 'location' of undefined" on line 124: const match = useRouteMatch("/notes/:id");
morgan
function call (including the newly defined body
token).findByIdAnUpdate
, mongoose doesn't automatically run validation, so a configuration object needs to be passed: { runValidators: true, context: 'query' }
. Because, if we don't we will be able to update the number of a person with less than 8 digits.person
instead of note
.As I'm sure you're aware @mluukkai , this course was shared on reddit (and probably other websites as well) and is receiving a lot of usage outside of your university.
I've been meaning to learn react for years, and this course has made me finally take that step. To put what I learn into use, I made a small project of my own, to test my knowledge halfway through part 2. I'm sure there are many others who also build small projects as a direct result of this course, so perhaps it would be motivational and inspirational to have a section on your course where you show what students are able to do after just 1-2 weeks of taking your course.
In your example bodyParser is not used. From reading the documentation it says:
req.body
Contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when you use body-parsing middleware such as body-parser and multer.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.