/api-movies

Primary LanguageJavaScriptMIT LicenseMIT

Build Status Scrutinizer Code Quality Code Coverage Build Status

Install

Clone repo: git clone https://github.com/ollebergkvist/api-movie

Install dependencies: npm install

Create .env file: touch .env

Create folders: mkdir uploads logs

Start development: npm run dev

Start production: npm run start

Environment variables

Set the required env variables in the .env file

SECRET={jwtSecret}
MONGDODB_URI={URI}
PORT={PORT}

Database

Path to db dump:
/db/dump

Backup
mongodump --db movies --archive=movies.archive --gzip

Restore
mongorestore --gzip --archive=movies.archive

Precreated users

User
username: user@user.com
password: Password#1

Admin
username: admin@admin.com
password: Password#1

Postman collection

Development (localhost):
https://www.getpostman.com/collections/7a71e416d915d809cea9

Deployed (heroku):
https://www.getpostman.com/collections/76d500b0ba866b15bbb4

Docker

docker build -t {tagname} .
docker run -d -p {port}:{port} {tagname}
docker-compose up --detach

Tests

npm test

Movie API documentation

Routes open to the public:
GET /movies
GET /movies/:id
GET /search
Routes secured by JWT:
POST /movies/rent
POST /movies/purchase
PUT /favorite

The mentioned routes need a valid JSON Web Token (JWT) set in the HTTP-header.
The 'x-access-token' header should contain the JWT. In order to retrieve a token, a user
need to register and login successfully via the routes stated below:
POST /register
POST /login
Routes secured with JWT plus admin rights:
GET /admin/movies
GET /admin/movies/:id
GET /admin/search
POST /movies
PUT /movies/:id
DELETE /movies/:id
POST /remove/:id
PUT /availability/:id
PUT /return/:id
GET /users
PUT /users/:id

Movies

A movie has the following attributes:

id
title
description
image
stock
deleted
rental_price
sales_price
availability
likes
createdAt
updatedAt

Get all movies:

Resource URL

GET /api/movies

Description

Regular users can only fetch movies marked as available in the collection.
Pagination, sorting (all collection fields) and limiting is supported by default.

Use - prefixes to sort in descending order and no prefixes to sort in ascending order.

Example

Example URL:
http://localhost:3000/api/movies?sort=title&limit=3&page=1

Result:

{
    "type": "Success",
    "source": "/movies",
    "detail": "Movies fetched",
    "document": {
        "docs": [
            {
                "stock": 5,
                "rental_price": 10,
                "sales_price": 20,
                "availability": true,
                "likes": 1,
                "deleted": false,
                "_id": "604935b38b6af1337936a9ad",
                "title": "Fight Club ",
                "description": "An insomniac office worker and a devil-may-care soapmaker form an underground fight club that evolves into something much, much more.",
                "image": "https://m.media-amazon.com/images/M/MV5BMmEzNTkxYjQtZTc0MC00YTVjLTg5ZTEtZWMwOWVlYzY0NWIwXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_UX182_CR0,0,182,268_AL_.jpg",
                "__v": 0,
                "createdAt": "2021-03-10T21:10:11.183Z",
                "updatedAt": "2021-03-11T00:24:59.146Z"
            },
            {
                "stock": 5,
                "rental_price": 10,
                "sales_price": 20,
                "availability": true,
                "likes": 0,
                "deleted": false,
                "_id": "604935b38b6af1337936a9ae",
                "title": "Forrest Gump",
                "description": "The presidencies of Kennedy and Johnson, the Vietnam War, the Watergate scandal and other historical events unfold from the perspective of an Alabama man with an IQ of 75, whose only desire is to be reunited with his childhood sweetheart.",
                "image": "https://m.media-amazon.com/images/M/MV5BNWIwODRlZTUtY2U3ZS00Yzg1LWJhNzYtMmZiYmEyNmU1NjMzXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_UY268_CR1,0,182,268_AL_.jpg",
                "__v": 0,
                "createdAt": "2021-03-10T21:10:11.183Z",
                "updatedAt": "2021-03-10T21:10:11.183Z"
            },
            {
                "stock": 5,
                "rental_price": 10,
                "sales_price": 20,
                "availability": true,
                "likes": 0,
                "deleted": false,
                "_id": "604935b38b6af1337936a9af",
                "title": "Inception",
                "description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
                "image": "https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_UX182_CR0,0,182,268_AL_.jpg",
                "__v": 0,
                "createdAt": "2021-03-10T21:10:11.183Z",
                "updatedAt": "2021-03-10T21:10:11.183Z"
            }
        ],
        "totalDocs": 12,
        "limit": 3,
        "totalPages": 4,
        "page": 1,
        "pagingCounter": 1,
        "hasPrevPage": false,
        "hasNextPage": true,
        "prevPage": null,
        "nextPage": 2
    }
}

Get all movies (admin):

Resource URL

GET /api/admin/movies

Description

Admin can only fetch all movies in the collection.
Meaningg movies where the availability is marked as false or true.
Filtering (all collection fields), pagination, sorting (all collection fields) and limiting is supported by default.

Use - prefixes to sort in descending order and no prefixes to sort in ascending order.

Example

Example URL:
http://localhost:3000/api/admin/movies?availability=false&sort=-title&limit=2

Result:

{
    "type": "Success",
    "source": "/admin/movies",
    "detail": "Movies fetched",
    "document": {
        "docs": [
            {
                "stock": 0,
                "rental_price": 10,
                "sales_price": 20,
                "availability": false,
                "likes": 1,
                "deleted": false,
                "_id": "604935b38b6af1337936a9a5",
                "title": "The Godfather: Part II",
                "description": "The early life and career of Vito Corleone in 1920s New York City is portrayed, while his son, Michael, expands and tightens his grip on the family crime syndicate.",
                "image": "https://m.media-amazon.com/images/M/MV5BMWMwMGQzZTItY2JlNC00OWZiLWIyMDctNDk2ZDQ2YjRjMWQ0XkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_UY268_CR3,0,182,268_AL_.jpg",
                "__v": 0,
                "createdAt": "2021-03-10T21:10:11.181Z",
                "updatedAt": "2021-03-12T00:38:32.344Z"
            },
            {
                "stock": 3,
                "rental_price": 5,
                "sales_price": 10,
                "availability": false,
                "likes": 0,
                "deleted": false,
                "_id": "604aa9a7ab706913f38bb032",
                "title": "Tenet8",
                "description": "A secret agent is given a single word as his weapon and sent to prevent the onset of World War III. He must travel through time and bend the laws of nature in order to be successful in his mission.",
                "image": "uploads/bc59560594d5305d2085a7d4c8b220a6.jpg",
                "createdAt": "2021-03-11T23:37:11.718Z",
                "updatedAt": "2021-03-11T23:37:11.718Z",
                "__v": 0
            }
        ],
        "totalDocs": 4,
        "offset": 0,
        "limit": 2,
        "totalPages": 2,
        "page": 1,
        "pagingCounter": 1,
        "hasPrevPage": false,
        "hasNextPage": true,
        "prevPage": null,
        "nextPage": 2
    }
}

Get specific movie:

Resource URL

GET /api/movies/:id

Description

Regular users can only fetch movies marked as available in the collection.

Example

Example URL:
http://localhost:3000/api/movies/604935b38b6af1337936a9af

Result

{
    "type": "Success",
    "source": "/movies/604935b38b6af1337936a9af",
    "detail": "Movie fetched",
    "document": {
        "stock": 5,
        "rental_price": 10,
        "sales_price": 20,
        "availability": true,
        "likes": 0,
        "deleted": false,
        "_id": "604935b38b6af1337936a9af",
        "title": "Inception",
        "description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
        "image": "https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_UX182_CR0,0,182,268_AL_.jpg",
        "__v": 0,
        "createdAt": "2021-03-10T21:10:11.183Z",
        "updatedAt": "2021-03-10T21:10:11.183Z"
    }
}

Get specific movie (admin):

Resource URL

GET /api/admin/movies/:id

Description

Admin users can fetch all movies marked as available in the collection.

Example

Example URL:
http://localhost:3000/api/admin/movies/604935b38b6af1337936a9af

Result

{
    "type": "Success",
    "source": "/admin/movies/604935b38b6af1337936a9a3",
    "detail": "Movie fetched",
    "document": {
        "stock": 22,
        "rental_price": 22,
        "sales_price": 100,
        "availability": false,
        "likes": 7,
        "deleted": false,
        "_id": "604935b38b6af1337936a9a3",
        "title": "Shawshank Redemption",
        "description": "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.",
        "image": "https://m.media-amazon.com/images/M/MV5BMDFkYTc0MGEtZmNhMC00ZDIzLWFmNTEtODM1ZmRlYWMwMWFmXkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_UX182_CR0,0,182,268_AL_.jpg",
        "__v": 0,
        "createdAt": "2021-03-10T21:10:11.179Z",
        "updatedAt": "2021-03-12T03:09:11.869Z"
    }
}

Search movies:

POST /api/movies/search/title?

Description

Regular users can only search for movies marked as available in the collection.

Example

Example URL:
http://localhost:3000/api/search?title=inception

Example response

{
    "type": "Success",
    "source": "/search",
    "detail": "Movie fetched",
    "document": [
        {
            "stock": 5,
            "rental_price": 10,
            "sales_price": 20,
            "availability": true,
            "likes": 0,
            "deleted": false,
            "_id": "604935b38b6af1337936a9af",
            "title": "Inception",
            "description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
            "image": "https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_UX182_CR0,0,182,268_AL_.jpg",
            "__v": 0,
            "createdAt": "2021-03-10T21:10:11.183Z",
            "updatedAt": "2021-03-10T21:10:11.183Z"
        }
    ]
}

Search movies (admin):

POST /api/admin/movies/search/title?

Description

Admin can search for all movies in the collection.

Example

Example URL:
http://localhost:3000/api/admin/search?title=shawshank redemption

Example response

{
    "type": "Success",
    "source": "/admin/search",
    "detail": "Movie fetched",
    "document": [
        {
            "stock": 22,
            "rental_price": 22,
            "sales_price": 100,
            "availability": false,
            "likes": 7,
            "deleted": false,
            "_id": "604935b38b6af1337936a9a3",
            "title": "Shawshank Redemption",
            "description": "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.",
            "image": "https://m.media-amazon.com/images/M/MV5BMDFkYTc0MGEtZmNhMC00ZDIzLWFmNTEtODM1ZmRlYWMwMWFmXkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_UX182_CR0,0,182,268_AL_.jpg",
            "__v": 0,
            "createdAt": "2021-03-10T21:10:11.179Z",
            "updatedAt": "2021-03-12T03:09:11.869Z"
        }
    ]
}

Add movie (admin)

POST /api/movies

Description

Supports upload functionality of images, in order for this to work form-data need to be used
and a image has to be selected.
Images are stored in the uploads folder.

Required parameters:

title
description
image

Optional parameters (if not set default values are used):

stock
rental_price
sales_price
availability
likes

Result

HTTP Status Code 201 Created

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/movies",
    "title": "Movie exists already"
}

Delete movie (admin)

DELETE /api/movies/:id

Description

Deletes item from collection.
Hard delete.

Response

HTTP Status Code 204 No Content

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/movies/:id",
    "title": "Movie with given id could not be found"
}

Remove movie (admin)

PUT /api/movies/:id

Description

Marks item as deleted.
Updates field: deleted as true.
Soft delete.

Response

HTTP Status Code 204 No Content

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/movies/:id",
    "title": "Movie with given id could not be found"
}

Update movie (admin)

PUT /api/movies/:id

Required parameters (one of the following):

title
description
image
stock
rental_price
sales_price
availability
likes

Result

HTTP Status Code 204 No Content

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/movies/:id",
    "title": "Movie with given id could not be found"
}

Change availability of a movie (admin)

PUT /api/availability/:id

Result

HTTP Status Code 204 No Content

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/availability/604935b38b6af1337936a9a2",
    "title": "Movie with given id could not be found"
}

Rentals

A rental has the following attributes:

movie_id
customer_id
amount
cost
return_date
returned
rental_price
penalty
returnedAt
createdAt
updatedAt

Add rental

POST /api/movies

Required parameters:

movie_id
customer_id
amount
cost

Optional parameters:

return_date
returned
penalty

Result

{
    "status": "201",
    "type": "Success",
    "source": "/movies/rent",
    "message": "Movie successfully rented",
    "document": {
        "returnDate": "2021-03-15T14:30:22.499Z",
        "returned": false,
        "_id": "604b7f83224fc02506fb5d9a",
        "movieID": "604935b38b6af1337936a9a9",
        "customerID": "604961a685abaa3ee96a4ec5",
        "amount": 2,
        "cost": 33,
        "createdAt": "2021-03-12T14:49:39.782Z",
        "updatedAt": "2021-03-12T14:49:39.782Z",
        "__v": 0
    }
}

Possible error, besides errors returned from db:

{
    "status": 400,
    "type": "Error",
    "source": "/movies/purchase",
    "message": "Insufficient stock to complete order"
}

Purchases

A purchase has the following attributes:

movie_id
customer_id
amount
cost
createdAt
updatedAt

Add purchase

POST /api/movies/purchase

Required parameters:

movie_id
customer_id
amount
cost

Result

{
    "status": "201",
    "type": "Success",
    "source": "/movies/purchase",
    "message": "Movie successfully purchased",
    "document": {
        "_id": "604b7dda224fc02506fb5d83",
        "movieID": "604935b38b6af1337936a9a9",
        "customerID": "604961a685abaa3ee96a4ec5",
        "amount": 1,
        "cost": 1,
        "createdAt": "2021-03-12T14:42:34.320Z",
        "updatedAt": "2021-03-12T14:42:34.320Z",
        "__v": 0
    }
}

Possible error, besides errors returned from db:

{
    "status": 400,
    "type": "Error",
    "source": "/movies/purchase",
    "message": "Insufficient stock to complete order"
}

Return movie (admin):

PUT /api/admin/movies/return/:id

Example response

{
    "status": "204",
    "type": "Success",
    "source": "/return/604b913add61ac25900135b8",
    "message": "Movie successfully returned"
}

Register

Resource URL

POST /api/register

Required parameters:

email
password

Result:

{   "status": 201,
    "type": "Success",
    "source": "/register",
    "detail": "Registration succeeded"
}

Login

Resource URL

POST /api/login

Required parameters:

email
password

Result:

{
    "status": "200"
    "type": "Success",
    "source": "/login",
    "detail": "User logged in",
    "user": "admin@admin.com",
    "admin": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFkbWluQGFkbWluLmNvbSIsImFkbWluIjp0cnVlLCJpYXQiOjE2MTU1NjAwNTEsImV4cCI6MTYxNTY0NjQ1MX0.y3f7c5kRUbMTLEr-wgYfRDHh1lciPn-ju_Rt61zRKdM"
}

N.B. The access token expires after 24 hours.

Get all users (admin):

GET /api/admin/movies/return/:id

Example response

{
    "type": "Success",
    "message": "Users retrieved successfully",
    "documents": [
        {
            "admin": true,
            "_id": "604961a685abaa3ee96a4ec4",
            "email": "admin@admin.com",
            "password": "$2a$10$jJnGhCVxf/VMUcmCdc387uhI8e1Q8dq2Ko76huSsnqAbx9mLrIuHG",
            "favorites": [],
            "createdAt": "2021-03-11T00:17:42.809Z",
            "updatedAt": "2021-03-11T00:17:42.809Z",
            "__v": 0
        },
        {
            "admin": false,
            "_id": "604961a685abaa3ee96a4ec5",
            "email": "user@user.com",
            "password": "$2a$10$jJnGhCVxf/VMUcmCdc387uhI8e1Q8dq2Ko76huSsnqAbx9mLrIuHG",
            "favorites": [],
            "createdAt": "2021-03-11T00:17:42.841Z",
            "updatedAt": "2021-03-11T00:25:32.380Z",
            "__v": 8
        },
    ]
}

Get specific movie (admin):

Resource URL

GET /api/users/:id

Result

{
    "type": "Success",
    "source": "/users/604961a685abaa3ee96a4ec4",
    "detail": "User found",
    "document": {
        "admin": true,
        "_id": "604961a685abaa3ee96a4ec4",
        "email": "admin@admin.com",
        "password": "$2a$10$jJnGhCVxf/VMUcmCdc387uhI8e1Q8dq2Ko76huSsnqAbx9mLrIuHG",
        "favorites": [],
        "createdAt": "2021-03-11T00:17:42.809Z",
        "updatedAt": "2021-03-11T00:17:42.809Z",
        "__v": 0
    }
}

Possible error, besides errors returned from db:

{
    "status": "400"
    "type": "Error",
    "source": "/users/604961a685abaa3ee96a4ec3",
    "detail": "User with given id could not be found"
}

Change user permissions (admin):

Resource URL

PUT /api/users/:id

Required parameters:

admin

Result

{
    "status": "204",
    "type": "Success",
    "source": "/users/604961a685abaa3ee96a4ec5",
    "detail": "User rights updated successfully"
}

Possible error, besides errors returned from db:

{
    "status": "404"
    "type": "Error",
    "source": "/users/:id",
    "detail": "User with given id could not be found"
}

Add movie to favorites:

Resource URL

PUT /api/favorite

Required parameters:

id
movie_id

Result

{
    "status": "200",
    "type": "Success",
    "source": "/favorite",
    "detail": "Movie added to user favorites and number of likes in given movie was incremented with 1"
}

Possible error, besides errors returned from db:

{
    "status": "400",
    "type": "Error",
    "source": "/favorite",
    "detail": "Movie has already been added to user's favorites"
}