/README.md
Markdown | 400 lines | 321 code | 79 blank | 0 comment | 0 complexity | 5ab54927e123c5d1dcddb671be971a38 MD5 | raw file
- # Yoyo Cinema API
- This is a light-weight api that exposes the following endpoints and requirements:
- - GET /search/movie - This should take `api_key` and `search_query` as parameters and return a well structured JSON collection of matching movies.
- - GET /movie/{id} - This should take `api_key` as a parameter and return full details of the requested movie in well structured JSON
- Lavarel already supports token based authentication like [passport](https://laravel.com/docs/5.6/passport) or adding `api_token` column to user table and using **auth::api** middleware can also be a solution.
- For the sake of security, it actually is better to send token as POST variable but what if this was a on going project that I get involved with?
- Therefore I wrote a custom guard and provider to receive `api_key` as token in GET variables.
- `search_query` could be in json format however rather then using only one parameter, I developed a simple filtering system.
- My goal is to find the best practice among other solutions but based on my current knowledge thus this version can certainly be improved.
- In additionally, GraphQL can be an alternative to REST services. Previously I attempted to use [it in Laravel](https://bitbucket.org/emrahsifoglu/laravel-graphql).
- ## Table of Contents
- * [Getting Started](#getting-started)
- * [Prerequisite](#prerequisite)
- * [Installation](#installation)
- * [Running](#running)
- * [How it works?](#how-it-works?)
- * [Admin](#admin)
- * [Login](#login)
- * [About me](#about-me)
- * [Create a movie](#create-a-movie)
- * [User](#user)
- * [Register](#register)
- * [About me](#about-me)
- * [Get a movie](#get-a-movie)
- * [Search movies](#search-movies)
- * [Built with](#built-with)
- * [Development Environment](#development-environment)
- * [Third Party Dependencies](#third-party-dependencies)
- * [Authors](#authors)
- * [License](#license)
- * [Resources](#resources)
- ## Getting Started
- These instructions will guide you to up and running the project on your local machine.
- ### Prerequisite
- * Composer
- * PHP
- * Apache( or Nginx)
- * MySQL
- ### Installation
- At first you can update parameters in [.env](.env) and [.env.testing](.env.testing) then you can install dependencies.
- Before executing migrations it might be better to clear cache because sometime migration files can not be found.
- Current migrations will create users and admins tables. Seeder will generate 20 random users but only one admin.
- You can simply follow instructions below. Depending your user role on Unix based os, you may need to use `sudo` to run commands.
- 1. Update parameters
- 2. composer install
- 3. php artisan cache:clear && composer dump-autoload
- 4. php artisan migrate && php artisan db:seed
- ## Running
- You can start the server with `php artisan serve`. If you need to change ip address, you can define it with `--host=`.
- ## How it works?
- There are two APIs, one for [admin](#admin) and the other one for [users](#user).
- ### Admin
- Admin can login, logout and create movies via api which uses JWT.
- There is only one admin with following credentials; `email: admin@example.com`, `password: secret`
- Below you may find route list.
- | Method | URI | Action (App\Http\Controllers) | Middleware |
- |-----------|-------------------------|----------------------------------------|---------------------|
- | POST | api/admin/login | Admin\Api\AuthController@login | api |
- | POST | api/admin/logout | Admin\Api\AuthController@logout | api, auth:admin-api |
- | GET, HEAD | api/admin/me | Admin\Api\AuthController@getDetails | api, auth:admin-api |
- | POST | api/admin/movie/create | Admin\Api\MovieController@create | api, auth:admin-api |
- | POST | api/admin/refresh | Admin\Api\AuthController@refresh | api, auth:admin-api |
- #### Login
- **Request:**
- ```
- $ curl -X POST \
- http://localhost:8000/api/admin/login \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache' \
- -d '{"email":"admin@example.com", "password":"secret"}'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthorized"
- }
- ```
- **Response on success:**
- ```json
- {
- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k",
- "token_type": "bearer",
- "expires_in": 3600
- }
- ```
- #### About me
- **Request:**
- ```
- $ curl -X GET \
- 'http://localhost:8000/api/admin/me?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k' \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthenticated"
- }
- ```
- **Response on success:**
- ```json
- {
- "id": 1,
- "name": "admin",
- "email": "admin@example.com",
- "created_at": "2018-05-02 14:22:13",
- "updated_at": "2018-05-02 14:22:13"
- }
- ```
- #### Create a movie
- **Request:**
- ```
- $ curl -X POST \
- http://localhost:8000/api/admin/movie/create \
- -H 'Accept: application/json' \
- -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache' \
- -d '{"imdb_id":"tt0109071", "title":"Accumulator 1", "description":"In this movie, TV sets are full of life. If a person is in TV (e.g. because it was filmed on the street) it has a double that'\''s right in the TV set. This double needs energy from the true ...", "length":"102.0", "rating":"7", "released_date":"1994-03-24"}'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthenticated"
- }
- ```
- **Response on success:**
- ```json
- {
- "success": {
- "id": 1
- }
- }
- ```
- ### User
- Users can actually register but they can not login which is not required because they will only consume the api.
- However on production rate limiting can be used.
- Below you may find route list.
- | Method | URI | Action (App\Http\Controllers) | Middleware |
- |-----------|-------------------------|----------------------------------------|--------------------|
- | GET, HEAD | api/me | Api\AuthController@getDetails | api,auth:api |
- | GET, HEAD | api/movie/{id} | Api\MovieController@getMovie | api,auth:api |
- | POST | api/register | Api\AuthController@register | api |
- | GET, HEAD | api/search/movie | Api\MovieController@searchMovie | api,auth:api |
- #### Register
- **Request:**
- ```
- $ curl -X POST \
- http://localhost:8000/api/register \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache' \
- -d '{"first_name":"first_name", "last_name":"last_name", "email":"example@example.com", "password":"12345", "c_password":"123456"}'
- ```
- **Response on error:**
- ```json
- {
- "error": {
- "password": [
- "The password must be at least 6 characters."
- ],
- "c_password": [
- "The c password and password must match."
- ]
- }
- }
- ```
- **Response on success:**
- ```json
- {
- "success": {
- "full_name": "first_name last_name",
- "email": "exampleg@example.com",
- "api_key": "pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5"
- }
- }
- ```
- #### About me
- **Request:**
- ```
- $ curl -X GET \
- 'http://localhost:8000/api/me?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5' \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthenticated"
- }
- ```
- **Response on success:**
- ```json
- {
- "success": {
- "id": 1,
- "first_name": "first_name",
- "last_name": "last_name",
- "email": "example@example.com",
- "api_key": "pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5",
- "created_at": "2018-05-02 16:26:40",
- "updated_at": "2018-05-02 16:26:40"
- }
- }
- ```
- #### Get a movie
- Following request will return only one result for movie with id 1.
- **Request:**
- ```
- $ curl -X GET \
- 'http://localhost:8000/api/movie/1?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5' \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthenticated"
- }
- ```
- **Response on success:**
- ```json
- {
- "success": [
- {
- "id": 1,
- "imdb_id": "tt0109071",
- "title": "Accumulator 1",
- "description": "In this movie, TV sets are full of life. If a person is in TV (e.g. because it was filmed on the street) it has a double that's right in the TV set. This double needs energy from the true ...",
- "length": "102.00",
- "rating": 7,
- "released_date": "1994-03-24",
- "created_at": "2018-05-02 16:33:31",
- "updated_at": "2018-05-02 16:33:31"
- }
- ]
- }
- ```
- #### Search movies
- Following request will return only movies which ratings are equal or higher than 7.
- You can find other filters in app/Filters/Movie.
- **Request:**
- ```
- $ curl -X GET \
- 'http://localhost:8000/api/search/movie?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5&rating=7' \
- -H 'Accept: application/json' \
- -H 'Content-Type: application/json' \
- -H 'Cache-Control: no-cache'
- ```
- **Response on error:**
- ```json
- {
- "error":"Unauthenticated"
- }
- ```
- **Response on success:**
- ```json
- {
- "success": [
- {
- "id": 1,
- "imdb_id": "tt0109071",
- "title": "Accumulator 1",
- "description": "In this movie, TV sets are full of life. If a person is in TV (e.g. because it was filmed on the street) it has a double that's right in the TV set. This double needs energy from the true ...",
- "length": "102.00",
- "rating": 7,
- "released_date": "1994-03-24",
- "created_at": "2018-05-02 16:33:31",
- "updated_at": "2018-05-02 16:33:31"
- }
- ]
- }
- ```
- ## Testing
- Tests are running in a different database thus mocking methods is not necessary because actual data won't get affected.
- There are also some functionalities used only for testing purposes.
- ## Built with
- #### Development Environment
- * [Ubuntu 16](https://www.ubuntu.com/download/server) - Server
- * [MySQL](https://www.mysql.com/) - Database
- * [PHP 7.1](http://php.net/) - Language
- * [Linux Mint 18](https://www.linuxmint.com/) - OS
- * [PhpStorm](https://www.jetbrains.com/phpstorm/) - IDE
- * [Chromium](https://www.chromium.org/Home) - Browser
- #### Third Party Dependencies
- * [jwt-auth](https://github.com/tymondesigns/jwt-auth) - JSON Web Token Authentication for Laravel & Lumen
- ## Authors
- * **Emrah Sifoğlu** - *Initial work* - [emrahsifoglu](https://github.com/emrahsifoglu)
- ## License
- This project is licensed under the [MIT License](http://opensource.org/licenses/MIT).
- ## Resources
- - https://medium.com/@mcasciato/no-imdb-api-check-out-these-options-75917d0fe923
- - http://www.omdbapi.com/
- - https://www.youtube.com/playlist?list=PLe30vg_FG4OSUxdFfNYvlm4fcqoC_oJQA
- - https://softwareengineering.stackexchange.com/questions/298973/rest-api-security-stored-token-vs-jwt-vs-oauth
- - https://www.reddit.com/r/laravel/comments/5x4r65/does_laravelpassport_and_tymonjwtauth_serve_the/
- - https://laravel-news.com/laravel-5-4-key-too-long-error
- - https://laravelcode.com/post/laravel-passport-create-rest-api-with-authentication
- - https://stackoverflow.com/questions/46319639/how-to-change-api-token-column-in-token-guard
- - https://code.i-harness.com/en/q/213bcd1
- - https://gistlog.co/JacobBennett/090369fbab0b31130b51
- - https://laravel.io/forum/09-05-2014-php-artisan-serve-on-another-adress
- - https://stackoverflow.com/questions/45340855/laravel-5-5-change-unauthenticated-login-redirect-url
- - https://stackoverflow.com/questions/40942367/how-validate-unique-email-out-of-the-user-that-is-updating-it-in-laravel
- - https://www.youtube.com/watch?v=D2071bufBjk
- - https://medium.com/@sirajul.anik/laravel-api-authenticate-user-with-custom-driver-different-table-using-auth-middleware-fa2cabec2d61
- - http://www.brandsoftonline.com/rest-laravel-5-4-token-authentication/
- - https://www.dunebook.com/database-testing-with-phpunit-in-laravel/3/
- - http://www.phplab.info/categories/laravel/how-to-specify-a-separate-database-for-unit-testing-on-laravel-5
- - https://laracasts.com/discuss/channels/general-discussion/laravel-5-catch-notfound- httpexception
- - https://dev.mysql.com/doc/sakila/en/sakila-structure-tables-film.html
- - https://laravel.com/docs/5.6/migrations
- - https://stackoverflow.com/questions/19201266/mysql-size-of-decimal-data-type
- - https://www.youtube.com/watch?v=l201RSQ7Ti4
- - https://gist.github.com/technoknol/a3b58e35262d1a552fd29b614b383861
- - https://m.dotdev.co/writing-advanced-eloquent-search-query-filters-de8b6c2598db
- - https://github.com/mnabialek/laravel-eloquent-filter