PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/README.md

https://bitbucket.org/emrahsifoglu/yoyo-cinema-api
Markdown | 400 lines | 321 code | 79 blank | 0 comment | 0 complexity | 5ab54927e123c5d1dcddb671be971a38 MD5 | raw file
  1. # Yoyo Cinema API
  2. This is a light-weight api that exposes the following endpoints and requirements:
  3. - GET /search/movie - This should take `api_key` and `search_query` as parameters and return a well structured JSON collection of matching movies.
  4. - GET /movie/{id} - This should take `api_key` as a parameter and return full details of the requested movie in well structured JSON
  5. 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.
  6. 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?
  7. Therefore I wrote a custom guard and provider to receive `api_key` as token in GET variables.
  8. `search_query` could be in json format however rather then using only one parameter, I developed a simple filtering system.
  9. My goal is to find the best practice among other solutions but based on my current knowledge thus this version can certainly be improved.
  10. In additionally, GraphQL can be an alternative to REST services. Previously I attempted to use [it in Laravel](https://bitbucket.org/emrahsifoglu/laravel-graphql).
  11. ## Table of Contents
  12. * [Getting Started](#getting-started)
  13. * [Prerequisite](#prerequisite)
  14. * [Installation](#installation)
  15. * [Running](#running)
  16. * [How it works?](#how-it-works?)
  17. * [Admin](#admin)
  18. * [Login](#login)
  19. * [About me](#about-me)
  20. * [Create a movie](#create-a-movie)
  21. * [User](#user)
  22. * [Register](#register)
  23. * [About me](#about-me)
  24. * [Get a movie](#get-a-movie)
  25. * [Search movies](#search-movies)
  26. * [Built with](#built-with)
  27. * [Development Environment](#development-environment)
  28. * [Third Party Dependencies](#third-party-dependencies)
  29. * [Authors](#authors)
  30. * [License](#license)
  31. * [Resources](#resources)
  32. ## Getting Started
  33. These instructions will guide you to up and running the project on your local machine.
  34. ### Prerequisite
  35. * Composer
  36. * PHP
  37. * Apache( or Nginx)
  38. * MySQL
  39. ### Installation
  40. At first you can update parameters in [.env](.env) and [.env.testing](.env.testing) then you can install dependencies.
  41. Before executing migrations it might be better to clear cache because sometime migration files can not be found.
  42. Current migrations will create users and admins tables. Seeder will generate 20 random users but only one admin.
  43. You can simply follow instructions below. Depending your user role on Unix based os, you may need to use `sudo` to run commands.
  44. 1. Update parameters
  45. 2. composer install
  46. 3. php artisan cache:clear && composer dump-autoload
  47. 4. php artisan migrate && php artisan db:seed
  48. ## Running
  49. You can start the server with `php artisan serve`. If you need to change ip address, you can define it with `--host=`.
  50. ## How it works?
  51. There are two APIs, one for [admin](#admin) and the other one for [users](#user).
  52. ### Admin
  53. Admin can login, logout and create movies via api which uses JWT.
  54. There is only one admin with following credentials; `email: admin@example.com`, `password: secret`
  55. Below you may find route list.
  56. | Method | URI | Action (App\Http\Controllers) | Middleware |
  57. |-----------|-------------------------|----------------------------------------|---------------------|
  58. | POST | api/admin/login | Admin\Api\AuthController@login | api |
  59. | POST | api/admin/logout | Admin\Api\AuthController@logout | api, auth:admin-api |
  60. | GET, HEAD | api/admin/me | Admin\Api\AuthController@getDetails | api, auth:admin-api |
  61. | POST | api/admin/movie/create | Admin\Api\MovieController@create | api, auth:admin-api |
  62. | POST | api/admin/refresh | Admin\Api\AuthController@refresh | api, auth:admin-api |
  63. #### Login
  64. **Request:**
  65. ```
  66. $ curl -X POST \
  67. http://localhost:8000/api/admin/login \
  68. -H 'Accept: application/json' \
  69. -H 'Content-Type: application/json' \
  70. -H 'Cache-Control: no-cache' \
  71. -d '{"email":"admin@example.com", "password":"secret"}'
  72. ```
  73. **Response on error:**
  74. ```json
  75. {
  76. "error":"Unauthorized"
  77. }
  78. ```
  79. **Response on success:**
  80. ```json
  81. {
  82. "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k",
  83. "token_type": "bearer",
  84. "expires_in": 3600
  85. }
  86. ```
  87. #### About me
  88. **Request:**
  89. ```
  90. $ curl -X GET \
  91. 'http://localhost:8000/api/admin/me?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k' \
  92. -H 'Accept: application/json' \
  93. -H 'Content-Type: application/json' \
  94. -H 'Cache-Control: no-cache'
  95. ```
  96. **Response on error:**
  97. ```json
  98. {
  99. "error":"Unauthenticated"
  100. }
  101. ```
  102. **Response on success:**
  103. ```json
  104. {
  105. "id": 1,
  106. "name": "admin",
  107. "email": "admin@example.com",
  108. "created_at": "2018-05-02 14:22:13",
  109. "updated_at": "2018-05-02 14:22:13"
  110. }
  111. ```
  112. #### Create a movie
  113. **Request:**
  114. ```
  115. $ curl -X POST \
  116. http://localhost:8000/api/admin/movie/create \
  117. -H 'Accept: application/json' \
  118. -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC8xOTIuMTY4LjIyMi4xMjg6ODAwMFwvYXBpXC9hZG1pblwvbG9naW4iLCJpYXQiOjE1MjUyNzYxNjgsImV4cCI6MTUyNTI3OTc2OCwibmJmIjoxNTI1Mjc2MTY4LCJqdGkiOiJ5UGZpR1VGQkZ4ZEpaeUxVIiwic3ViIjoxLCJwcnYiOiJjZjI4NGMyYjFlMDZmMzNjMjZiZDU3OTc1NjZkOWZkNzRiZTExYmY1In0.-5jNTrni1guDue3akqFvD_StfkwqcjguD7TownEKg2k' \
  119. -H 'Content-Type: application/json' \
  120. -H 'Cache-Control: no-cache' \
  121. -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"}'
  122. ```
  123. **Response on error:**
  124. ```json
  125. {
  126. "error":"Unauthenticated"
  127. }
  128. ```
  129. **Response on success:**
  130. ```json
  131. {
  132. "success": {
  133. "id": 1
  134. }
  135. }
  136. ```
  137. ### User
  138. Users can actually register but they can not login which is not required because they will only consume the api.
  139. However on production rate limiting can be used.
  140. Below you may find route list.
  141. | Method | URI | Action (App\Http\Controllers) | Middleware |
  142. |-----------|-------------------------|----------------------------------------|--------------------|
  143. | GET, HEAD | api/me | Api\AuthController@getDetails | api,auth:api |
  144. | GET, HEAD | api/movie/{id} | Api\MovieController@getMovie | api,auth:api |
  145. | POST | api/register | Api\AuthController@register | api |
  146. | GET, HEAD | api/search/movie | Api\MovieController@searchMovie | api,auth:api |
  147. #### Register
  148. **Request:**
  149. ```
  150. $ curl -X POST \
  151. http://localhost:8000/api/register \
  152. -H 'Accept: application/json' \
  153. -H 'Content-Type: application/json' \
  154. -H 'Cache-Control: no-cache' \
  155. -d '{"first_name":"first_name", "last_name":"last_name", "email":"example@example.com", "password":"12345", "c_password":"123456"}'
  156. ```
  157. **Response on error:**
  158. ```json
  159. {
  160. "error": {
  161. "password": [
  162. "The password must be at least 6 characters."
  163. ],
  164. "c_password": [
  165. "The c password and password must match."
  166. ]
  167. }
  168. }
  169. ```
  170. **Response on success:**
  171. ```json
  172. {
  173. "success": {
  174. "full_name": "first_name last_name",
  175. "email": "exampleg@example.com",
  176. "api_key": "pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5"
  177. }
  178. }
  179. ```
  180. #### About me
  181. **Request:**
  182. ```
  183. $ curl -X GET \
  184. 'http://localhost:8000/api/me?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5' \
  185. -H 'Accept: application/json' \
  186. -H 'Content-Type: application/json' \
  187. -H 'Cache-Control: no-cache'
  188. ```
  189. **Response on error:**
  190. ```json
  191. {
  192. "error":"Unauthenticated"
  193. }
  194. ```
  195. **Response on success:**
  196. ```json
  197. {
  198. "success": {
  199. "id": 1,
  200. "first_name": "first_name",
  201. "last_name": "last_name",
  202. "email": "example@example.com",
  203. "api_key": "pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5",
  204. "created_at": "2018-05-02 16:26:40",
  205. "updated_at": "2018-05-02 16:26:40"
  206. }
  207. }
  208. ```
  209. #### Get a movie
  210. Following request will return only one result for movie with id 1.
  211. **Request:**
  212. ```
  213. $ curl -X GET \
  214. 'http://localhost:8000/api/movie/1?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5' \
  215. -H 'Accept: application/json' \
  216. -H 'Content-Type: application/json' \
  217. -H 'Cache-Control: no-cache'
  218. ```
  219. **Response on error:**
  220. ```json
  221. {
  222. "error":"Unauthenticated"
  223. }
  224. ```
  225. **Response on success:**
  226. ```json
  227. {
  228. "success": [
  229. {
  230. "id": 1,
  231. "imdb_id": "tt0109071",
  232. "title": "Accumulator 1",
  233. "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 ...",
  234. "length": "102.00",
  235. "rating": 7,
  236. "released_date": "1994-03-24",
  237. "created_at": "2018-05-02 16:33:31",
  238. "updated_at": "2018-05-02 16:33:31"
  239. }
  240. ]
  241. }
  242. ```
  243. #### Search movies
  244. Following request will return only movies which ratings are equal or higher than 7.
  245. You can find other filters in app/Filters/Movie.
  246. **Request:**
  247. ```
  248. $ curl -X GET \
  249. 'http://localhost:8000/api/search/movie?api_key=pus4U79QXVoIddSaXOuHSb6a6Q3GaZdZwxZElJJWj6A6cFy3tphWnzgIh0N5&rating=7' \
  250. -H 'Accept: application/json' \
  251. -H 'Content-Type: application/json' \
  252. -H 'Cache-Control: no-cache'
  253. ```
  254. **Response on error:**
  255. ```json
  256. {
  257. "error":"Unauthenticated"
  258. }
  259. ```
  260. **Response on success:**
  261. ```json
  262. {
  263. "success": [
  264. {
  265. "id": 1,
  266. "imdb_id": "tt0109071",
  267. "title": "Accumulator 1",
  268. "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 ...",
  269. "length": "102.00",
  270. "rating": 7,
  271. "released_date": "1994-03-24",
  272. "created_at": "2018-05-02 16:33:31",
  273. "updated_at": "2018-05-02 16:33:31"
  274. }
  275. ]
  276. }
  277. ```
  278. ## Testing
  279. Tests are running in a different database thus mocking methods is not necessary because actual data won't get affected.
  280. There are also some functionalities used only for testing purposes.
  281. ## Built with
  282. #### Development Environment
  283. * [Ubuntu 16](https://www.ubuntu.com/download/server) - Server
  284. * [MySQL](https://www.mysql.com/) - Database
  285. * [PHP 7.1](http://php.net/) - Language
  286. * [Linux Mint 18](https://www.linuxmint.com/) - OS
  287. * [PhpStorm](https://www.jetbrains.com/phpstorm/) - IDE
  288. * [Chromium](https://www.chromium.org/Home) - Browser
  289. #### Third Party Dependencies
  290. * [jwt-auth](https://github.com/tymondesigns/jwt-auth) - JSON Web Token Authentication for Laravel & Lumen
  291. ## Authors
  292. * **Emrah Sifoğlu** - *Initial work* - [emrahsifoglu](https://github.com/emrahsifoglu)
  293. ## License
  294. This project is licensed under the [MIT License](http://opensource.org/licenses/MIT).
  295. ## Resources
  296. - https://medium.com/@mcasciato/no-imdb-api-check-out-these-options-75917d0fe923
  297. - http://www.omdbapi.com/
  298. - https://www.youtube.com/playlist?list=PLe30vg_FG4OSUxdFfNYvlm4fcqoC_oJQA
  299. - https://softwareengineering.stackexchange.com/questions/298973/rest-api-security-stored-token-vs-jwt-vs-oauth
  300. - https://www.reddit.com/r/laravel/comments/5x4r65/does_laravelpassport_and_tymonjwtauth_serve_the/
  301. - https://laravel-news.com/laravel-5-4-key-too-long-error
  302. - https://laravelcode.com/post/laravel-passport-create-rest-api-with-authentication
  303. - https://stackoverflow.com/questions/46319639/how-to-change-api-token-column-in-token-guard
  304. - https://code.i-harness.com/en/q/213bcd1
  305. - https://gistlog.co/JacobBennett/090369fbab0b31130b51
  306. - https://laravel.io/forum/09-05-2014-php-artisan-serve-on-another-adress
  307. - https://stackoverflow.com/questions/45340855/laravel-5-5-change-unauthenticated-login-redirect-url
  308. - https://stackoverflow.com/questions/40942367/how-validate-unique-email-out-of-the-user-that-is-updating-it-in-laravel
  309. - https://www.youtube.com/watch?v=D2071bufBjk
  310. - https://medium.com/@sirajul.anik/laravel-api-authenticate-user-with-custom-driver-different-table-using-auth-middleware-fa2cabec2d61
  311. - http://www.brandsoftonline.com/rest-laravel-5-4-token-authentication/
  312. - https://www.dunebook.com/database-testing-with-phpunit-in-laravel/3/
  313. - http://www.phplab.info/categories/laravel/how-to-specify-a-separate-database-for-unit-testing-on-laravel-5
  314. - https://laracasts.com/discuss/channels/general-discussion/laravel-5-catch-notfound- httpexception
  315. - https://dev.mysql.com/doc/sakila/en/sakila-structure-tables-film.html
  316. - https://laravel.com/docs/5.6/migrations
  317. - https://stackoverflow.com/questions/19201266/mysql-size-of-decimal-data-type
  318. - https://www.youtube.com/watch?v=l201RSQ7Ti4
  319. - https://gist.github.com/technoknol/a3b58e35262d1a552fd29b614b383861
  320. - https://m.dotdev.co/writing-advanced-eloquent-search-query-filters-de8b6c2598db
  321. - https://github.com/mnabialek/laravel-eloquent-filter