Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

MyFlix Backend

A backend for retrieving films, saving them with personal content and with the possibility of having users.

Installation

Use Node.js 24.9.0 or newer. Jest needs this version's synchronous VM-module support to load Nock 15 from the CommonJS test suite.

Clone the repo and:

$ npm install

Also you'll need sequelize-cli installed globally:

$ npm install -g sequelize-cli

The first thing is to run the migration with Sequelize:

$ sequelize-cli db:migrate

Then create a file used for the secret keys:

$ touch secrets.js

and populate like this:

exports.API_KEY = "YOUR_TMDB_API_KEY";
exports.PRIVATE_KEY = "A RANDOM KEY TO SIGN THE JWT";

Finally you can run the server by:

$ npm start

Validation

Run ESLint across the backend with:

$ npm run lint

Formatting

Prettier is configured in .prettierrc.json, with exclusions in .prettierignore. Both scripts cover the whole repo, including the test/ suite. Recorded TMDB fixtures are excluded, since they are generated API dumps.

Format everything in place:

$ npm run format

Check formatting without writing (useful in CI):

$ npm run format:check

Testing

Run the whole suite:

$ npm test

Or one project at a time:

$ npm run test:unit
$ npm run test:integration

The test scripts enable Node's --experimental-vm-modules flag for Nock 15's ESM entry point. CommonJS consumers use require("nock").default. Both project setups restore Nock's HTTP interception after each suite to avoid leaking it into the next Jest environment. PDF client-abort checks wait for server-side document destruction rather than Supertest's end callback, which may not run after an abort.

Tests don't need a secrets.js file. The test setup injects API_KEY and PRIVATE_KEY as environment variables, so you can clone and run the suite without any local secrets.

Coverage

$ npm run test:coverage

This prints a per-file table in the terminal with statement, branch, function and line percentages, plus the exact uncovered line numbers for each file. It also writes a browsable HTML report to coverage/lcov-report/index.html, where you can click into a file and see the uncovered lines highlighted, and an coverage/lcov.info for CI tools. The coverage directory is gitignored.

Coverage is measured over src/**/*.js only. You can scope a run to one project:

$ npm run test:coverage:unit
$ npm run test:coverage:integration

Note that a single-project run reports low coverage for code the other project exercises, so use npm run test:coverage for the real picture. Those two scripts pass --coverageThreshold={} for exactly this reason.

src currently sits at 100% of statements, lines and functions, and 95.62% of branches. jest.config.js enforces that as a floor, so npm run test:coverage fails if a change drops below it.

The seven uncovered branches are deliberate, not gaps:

  • error?.message ?? "Internal server error" fallbacks in recommendation and userFavs. Sequelize always rejects with a real Error, so the right-hand side is unreachable.
  • if (res.headersSent) in the PDF route. doc.pipe(res) flushes PDFKit's header immediately, so the headers are always already sent by the time that catch runs.

Recording fixtures

$ npm run fixtures:record

This hits the real TMDB API, so it needs a valid TMDB key in the environment.

Status: fixture recording can't complete right now. The recorder looks for a pair of actor discover pages that naturally overlap, and no such pair was found in the TMDB data we sampled. As a documented interim substitution, tests 20, 21 and 29-31 use synthetic data served through nock, shaped like real TMDB responses. These should be swapped for real fixtures once recording works.

TODO

Some tests fail on purpose. They pin down bugs that are still in the codebase:

  • IDOR in userFavs: a user can read and modify another user's favourites. This is a live security issue and it's still unfixed. Treat it as the priority.
  • signUp returns an HTML error page instead of JSON when bcrypt throws.
  • search throws a TypeError on certain inputs.
  • the recommendation route answers 204 where it should answer 404.
  • userFavs uses a truthy check on the limit value, so a limit of 0 is ignored.
  • the PDF response is missing its content-type header.
  • search doesn't encode the search term into the URL properly.

B5 and B8 are missing from that list on purpose. Both were investigated and turned out not to be bugs, and the original numbering was kept so the notes and test names still line up.

Auth middleware

Checks the presence of the auth headers and tries to decode it, if successful create a property on the req object with the actual user ID, if not return a 401.`

Almost, now it checks the presence of the cookie.

Routes breakdown

Auth

Signing up

The route accepts a POST request with the body containing the first name, last name (the only optional field), a unique email address and a password, that will be hashed when saving it to the DB. It either responds with 201 if successful or a 500 status code if errors were encountered.

Signing in

The route accepts a POST request with the body containing the unique email address and the password. It finds the user by email and compares the hashed password with the received one, if successful it creates a JWT to be sent back to the client, if something doesn't match it send a 401 and if anything else goes wring a 404 status code.

Logout

A DELETE request to the route will delete the specified cookie/s.

Actor movies

Accepts a GET request with the actor's ID in the params, it then goes through all the existing pages and builds a list with all of the actor's films. In case of error return 501.

Actor Info

Accepts a GET request with the actor's ID in the params, it return an object with the actor's info, such as name.

Movie

Accepts a GET request with the film's ID in the params, retrieves it and before sending it back to the client it caches it in a Map for future use. In case of error return 404.

OR

"/:movieId/:movieResource"

Which can query a similar movie by sending an ID, or by sending a string that can't be parsed to an INT you could get other resources, comments in the file.

Movie credits

Accepts a GET request with the film's ID in the params, retrieves its credits and before sending it back to the client it caches it in a Map for future use. In case of error return 404.

Movies

Accepts a GET request with an optional query &page=INT, and retrieves the films from TMDB sorted by popularity.

Movie trailer

Accepts a GET request with the film's ID in the params, retrieves its trailer/s and before sending it back to the client it caches it in a Map for future use. In case of error return 404.

Ping

A health check route. Responds to GET request to which, if alive, returns a 200 status code.

Random

Accepts a GET request, and returns a random list of films. If it enters an infinite loop there is a fail safe mechanism to break out of it and return the list.

Search

Accepts a GET request with two optional queries &pageNum=INT and &includeAdult=STRING and the search term. If successful returns the films found otherwise 501.

User favs

This route uses the auth middleware.

GET

Return the user with it's favs.

POST

Providing all the required info it create a new UserFavourite with the user requesting it as the owner.

PATCH

Modifies the UserFavourite entry either with the boolean 'seen' and 'watchlist' or the string 'description', also it accepts a 'rating' property.

DELETE

Removes the UserFavourite entry of the requesting user.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages