Vessel positions search works according to specifications and responses are made in json, csv and xml. Results are paginated (see config/app). For the correct responses I created an ApiResponder class (see app/Lib). ApiResponder subclasses have their own implementation using different packages for CSV and XML to demostrate a basic Adapter Design Pattern (ApiResponderJson works with native Laravel response object). A new adapter/driver can be easily created by extending the abstract class and implementing the abstract response method.
Sample CRUD operations were made for an imaginary Vessels entity (just a test table) and in json format only (resource controller).
Download here.
Basic generated PHP Docs can be found in /phpdocs folder.
Basic unit and feature/integration tests are written in tests folder for all controllers/models.
C:\xampp\htdocs\test\laravel-mt-291017>phpunit PHPUnit 5.7.23 by Sebastian Bergmann and contributors. .............. 14 / 14 (100%) Time: 1.85 seconds, Memory: 18.00MB OK (14 tests, 32 assertions)
Below is a list of the registered routes:
+-----------+---------------------------+------------------+------------------------------------------------------------------------+--------------+
| Method | URI | Name | Action | Middleware |
+-----------+---------------------------+------------------+------------------------------------------------------------------------+--------------+
| GET|HEAD | / | | App\Http\Controllers\IndexController@index | web |
| GET|HEAD | api/positions/search | | App\Http\Controllers\Api\PositionController@search | api,auth:api |
| GET|HEAD | api/user | | Closure | api,auth:api |
| POST | api/vessels | vessels.store | App\Http\Controllers\Api\VesselController@store | api,auth:api |
| GET|HEAD | api/vessels | vessels.index | App\Http\Controllers\Api\VesselController@index | api,auth:api |
| GET|HEAD | api/vessels/create | vessels.create | App\Http\Controllers\Api\VesselController@create | api,auth:api |
| DELETE | api/vessels/{vessel} | vessels.destroy | App\Http\Controllers\Api\VesselController@destroy | api,auth:api |
| GET|HEAD | api/vessels/{vessel} | vessels.show | App\Http\Controllers\Api\VesselController@show | api,auth:api |
| PUT|PATCH | api/vessels/{vessel} | vessels.update | App\Http\Controllers\Api\VesselController@update | api,auth:api |
| GET|HEAD | api/vessels/{vessel}/edit | vessels.edit | App\Http\Controllers\Api\VesselController@edit | api,auth:api |
+-----------+---------------------------+------------------+------------------------------------------------------------------------+--------------+
Search positions without filters
Search positions with filter_mmsi (array - for multiple use filter_mmsi[]=aaa&filter_mmsi[]=bbb)
Search positions with filter_lat_from / filter_lat_to (numeric - use dot for decimal)
Search positions with filter_lot_from / filter_lot_to (numeric - use dot for decimal)
Search positions with filter_timestamp_from / filter_timestamp_to (string - any valid date/datetime in mysql format YYYY-MM-DD HH:MM:SS)
Any combination that makes sense.. For example...
For rate limit functionality, Laravel's default api middleware is used. The only change made was in Kernel.php configuration: throttle:10,60 (10 requests per 60 minutes).
Cache-Control: no-cache, private
Connection: Keep-Alive
Content-Type: application/xml
Date: Wed, 01 Nov 2017 01:19:21 GMT
Keep-Alive: timeout=5, max=96
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2h PHP/5.6.31
Transfer-Encoding: chunked
X-Powered-By: PHP/5.6.31
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 3
Cache-Control: no-cache, private Connection: Keep-Alive Content-Length: 18 Content-Type: text/html; charset=UTF-8 Date: Wed, 01 Nov 2017 01:20:36 GMT Keep-Alive: timeout=5, max=95 Retry-After: 3600 Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2h PHP/5.6.31 X-Powered-By: PHP/5.6.31 X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1509502836