Skip to content

Latest commit

 

History

History
204 lines (153 loc) · 8.99 KB

TASKS.md

File metadata and controls

204 lines (153 loc) · 8.99 KB

RS School NodeJS course

You can generate a new repository with the same directory structure and files as an existing repository using GitHub article: Creating a repository from a template.

N.B. This structure is recommended for the implementation tasks starting from the second. The first task is not related to subsequent ones.

Task 1. Caesar cipher CLI tool

Implement CLI tool that will encode and decode a text by Caesar cipher.

CLI tool should accept 4 options (short alias and full name):

  1. -s, --shift: a shift
  2. -i, --input: an input file
  3. -o, --output: an output file
  4. -a, --action: an action encode/decode

Details:

  1. For command-line arguments could be used one of
  1. Action (encode/decode) and the shift are required, if one of them missed - an error should be shown, the process should exit with non-zero status code.
  2. If the input file is missed - use stdin as an input source.
  3. If the output file is missed - use stdout as an output destination.
  4. If the input and/or output file is given but doesn't exist or you can't read it (e.g. because of permissions or it is a directory) - human-friendly error should be printed in stderr.
  5. If passed params are fine the output (file or stdout) should contain encoded/decoded content of input (file or stdin).
  6. For encoding/decoding use only the English alphabet, all other characters should be kept untouched.

Hints: As suggested solution to make streams code more robust, and memory effective, consider to use pipeline method. Structure can be the following:

pipeline(
  input_stream, // input file stream or stdin stream
  transform_stream, // standard Transform stream or https://github.com/rvagg/through2
  output_stream // output file stream or stdout stream
)
.then(success and error callbacks)

Usage example:

$ node my_caesar_cli -a encode -s 7 -i "./input.txt" -o "./output.txt"
$ node my_caesar_cli --action encode --shift 7 --input plain.txt --output encoded.txt
$ node my_caesar_cli --action decode --shift 7 --input decoded.txt --output plain.txt

input.txt This is secret. Message about "_" symbol!

output.txt Aopz pz zljyla. Tlzzhnl hivba "_" zftivs!

Task 2. Express REST service

Let's try to create a competitor for Trello!

Create an Express application, the application should operate with the following resources:

  • User (with attributes):
    { id, name, login, password }
  • Board (set of columns):
    { id, title, columns }
  • Column (set of tasks):
     { id, title, order }
  • Task:
    {
      id,
      title,
      order,
      description,
      userId, //assignee
      boardId,
      columnId
    }

Details:

  1. For User, Board and Task REST endpoints with separate router paths should be created

    • /users
      • GET /users - get all users (remove password from response)
      • GET /users/:id - get the user by id (ex. “/users/123”) (remove password from response)
      • POST /users - create user
      • PUT /users/:id - update user
      • DELETE /users/:id - delete user
    • /boards
      • GET all
      • GET by id
      • POST
      • PUT
      • DELETE
    • /tasks
      • GET all by boardId
      • GET by id
      • POST
      • PUT
      • DELETE
  2. When somebody DELETE Board, all its Tasks should be deleted as well.

  3. When somebody DELETE User, all Tasks where User is assignee should be updated to put userId=null.

  4. For now, these endpoints should operate only with in-memory (hardcoded) data, in the next tasks we will use a DB for it. You may organize your modules with the consideration that the data source will be changed soon.

  5. An application/json format should be used for request and response body.

  6. Do not put everything in one file - use a separate file for application creation (bootstrapping), for controllers (routers) and code related to business logic. Also split files to different modules depends on a domain (user-related, board-related, etc...).

  7. To run the service “npm start” command should be used.

  8. Service should listen on PORT 4000.

Hints

  • To test the service CRUD methods you can use Swagger html (see README.md).
  • To generate all entities “id”s use uuid package.

Task 3. Logging & Error Handling

Add logging functionality to already existing REST service.

  1. Add express middleware which will log incoming requests to service (url, query parameters, body).

  2. Add express middleware which will log all unhandled errors and return a standard message with HTTP code 500 (Internal Server Error).

  3. Add errors handling to process.on(‘uncaughtException’,...).

  4. Add Unhandled promise rejection listener to log error

  5. console.log or writing to a file can be used for logging. Any third-party logging library can also be used for this purpose.

Task 4. Database MongoDB

  1. Use MongoDB database to store REST service data (Users, Boards, Tasks).
  • Follow the MongoDB Atlas registration link.
  • Fill all mandatory fields and click create account button.
  • Choose “Starter Cluster” option and click Create a cluster.
  • The next screen choose: cloud provider - AWS, region - Ireland (eu-west-1) and click “Create Cluster” button (Not change another options).
  • Click Security - Database access tab.
  • Click Add new user button.
  • Choose method - Password and fill the username and the password fields (remember them, you will use them to connect mongodb database).
  • User Privileges - Set read and write to any database.
  • Click “Add user” button.
  • Click Security - Network Access tab.
  • Click “Add IP Address” button.
  • Click “Allow access from anywhere” button.
  • Click “Confirm” button.
  • You can generate connect string, by the following: in Atlas - Clusters tab click “Connect” button.
  • On Modal window (Connect to Cluster) click “Connect your Application” button. The window should look similar as in the picture:

alt text

  1. Use Mongoose ODM to store and update data.
  2. The information on DB connection (connection string) should be stored in .env file and should be passed to the application using the environment variables with the help of the following dotenv package.

Task 5. Authentication and JWT

  1. POST /users should accept password field and before save replace it with hash (use bcrypt package).
  2. Add a POST /login method which accepts json with login and password and should return JWT token in response body: { token: <jwt_token> } (use jsonwebtoken package).
  3. JWT token should contain userId and login in a payload.
  4. Secret that used for signing the token should be stored in .env file
  5. For all client requests the JWT token should be added in HTTP Authorization header to all requests that requires authentication. HTTP authentication must follow Bearer scheme, e.g.:
Authorization: Bearer <jwt_token>
  1. Add a middleware which will proxy all the requests (except /login) and check that HTTP Authorization header has the correct value of JWT token.
  2. In case of the HTTP Authorization header in the request is absent or invalid or doesn’t follow Bearer scheme, the middleware should stop further router method execution and return HTTP 401 code (Unauthorized error) and the corresponding error message.
  3. Add admin user to DB on service start with login=admin and password=admin.

bcrypt installation issues:

If you see an error that starts with:

gyp ERR! stack Error: "pre" versions of node cannot be installed, use the --nodedir flag instead

Please check compatibility between Node.JS and Bcrypt versions.

If you face an error like this:

node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v48-linux-x64.tar.gz

Make sure you have the appropriate dependencies installed and configured for your platform. You can find installation instructions for the dependencies for some common platforms in this page.