Giter Site home page Giter Site logo

fullstack-hy2020.github.io's People

Contributors

abdoulbaguim avatar alirezaghey avatar avrh avatar cassivsgabriellis avatar fcole90 avatar flyingmandarine avatar guymelef avatar jakousa avatar juanescacha avatar juhoan avatar juhq avatar kaltsoon avatar kkiilas avatar leagian avatar marklaatikainen avatar mayconblopes avatar micpob avatar minzen avatar mluukkai avatar niinasaarelainen avatar onzfonz avatar orvalho avatar pablo-maff avatar parttis avatar richardstark avatar rikurauhala avatar sahilrajput03 avatar teroajk avatar vlondonoma avatar woltsu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fullstack-hy2020.github.io's Issues

5b Critique: Students should reap the benefit of following instructor's lead

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."

Part 5b: use the official way to customize ESLint

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 to true. [...]

Note that any rules set to "error" will stop the project from building.

There are a few things to remember:

  1. We highly recommend extending the base config, as removing it could introduce hard-to-find issues.
  2. 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"
        }
      }
    ]
  }
}

Exercise solution

Where could I get the exercise solution after I submit the answer?

Incorrect object null check in pictures of code example in part 9c

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.

part 2a - Refactoring modules using index as a key

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.

Page Not Found

In part 3a, on line 20, link in part 1, leads to a 404 - Page not found; Uncaught ReferenceError: unknown is not defined.

Part 3b - Proxy - Working in dev-mode resulting in 431 error

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?

image

Thanks in advance.

Part 9.c orthographic variants

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.

Part 2c: npm --save deprecated

The use of the --save flag is deprecated for npm version 5 and up. Npm now saves dependencies by default. This is done multiple times throughout the course.

2020-05-27_19-45

The --save-dev flag is correct usage.

Part 1.2: course information, step2

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>
  );
}

Multiple React Apps in Part1 Nested Weirdly

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.

part 8a - links to resolvers/default resolvers aren't correct

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:

Mongoose 5.9.7 Breaking Error Handler Middleware (Part 3c onwards)

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.

Debugging react: course is using an old version of React Developer Tools

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:

image

So the text and image in the course should be removed or updated

Spelling corrections in part 9.b and dead link

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

Infinite (nearly) page reloads on Firefox Developer Edition on Fedora 32

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.

Wrong code highlighting and wrong code provided in part 8b react-graphql

I have encountered below two issues while learning mutations in Graphql-React app:-

  1. In image below an extra bit of code is provided after onError handler as highlighted in image below
    image

  2. 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.
    image

Exercises 6.19-6.20 instructions appear to begin with an obsolete assumption

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.

Invalid js in part 2 a

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.

Osa 0a kappale jäänyt kesken

Osassa 0 kappaleessa Full stack -harjoitustyö päättyy varmaankin liian aikaisin ja siinä pitäisi lopussa varmaan vielä jotain lukea (lause ainakin jää kesken).

Part 4c: jwt.verify error handling

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"
  },

translate into russian

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 logger instead of morgan

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)     

Part 5d: Testing new note form - test runs before login is completed

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')
    })
  })
})

image

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.

Part 5a: add a note that persisting session information in localStorage is not secure

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.

Incorrect example response in 9.16

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.

Suggested improvements to index.js in the example solution of part3

  • The cropped image of the script doesn't show the full morgan function call (including the newly defined body token).
  • When using 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.
  • We should have probably added an unknown endpoint error handler as well? and if so, we should then catch errors of the first two route handlers.
  • In the third route handler, I assume the intention was to name the variable person instead of note.

Suggestion: showcase react apps that students built while learning your course

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 part 3a, bodyParser is required to get the body of a request

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.