From cdd7152edeadd4618fbf43c1a9c7d5bd72b7fcf3 Mon Sep 17 00:00:00 2001 From: Mahmoud Zalt Date: Wed, 22 Mar 2017 20:36:16 -0400 Subject: [PATCH] some refactoring in the docs generator container --- .gitignore | 2 +- .../Actions/GenerateDocumentationAction.php | 3 +- .../ApiDocJs/private/apidoc.json | 2 +- .../Documentation/ApiDocJs/public/apidoc.json | 2 +- ...platesTask.php => RenderTemplatesTask.php} | 15 +- .../.gitkeep | 0 public/api-rendered-markdowns/header.md | 309 ++++++++++++++++++ 7 files changed, 325 insertions(+), 8 deletions(-) rename app/Containers/Documentation/Tasks/{ProcessMarkdownTemplatesTask.php => RenderTemplatesTask.php} (73%) rename public/{api-markdowns => api-rendered-markdowns}/.gitkeep (100%) create mode 100644 public/api-rendered-markdowns/header.md diff --git a/.gitignore b/.gitignore index a449e8266..580ff517c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,6 @@ Homestead.yaml .env storage/logs/laravel.log /public/api/ -/public/api-markdowns/ +/public/api-rendered-markdowns/ /public/uploads/ /laradock*/ diff --git a/app/Containers/Documentation/Actions/GenerateDocumentationAction.php b/app/Containers/Documentation/Actions/GenerateDocumentationAction.php index 4aff96ffb..0d78531bf 100644 --- a/app/Containers/Documentation/Actions/GenerateDocumentationAction.php +++ b/app/Containers/Documentation/Actions/GenerateDocumentationAction.php @@ -5,6 +5,7 @@ use App\Containers\Documentation\Tasks\GenerateAPIDocsTask; use App\Containers\Documentation\Tasks\GetDocsTypesTask; use App\Containers\Documentation\Tasks\ProcessMarkdownTemplatesTask; +use App\Containers\Documentation\Tasks\RenderTemplatesTask; use App\Ship\Parents\Actions\Action; /** @@ -21,7 +22,7 @@ class GenerateDocumentationAction extends Action public function run($console) { // parse the markdown file. - $this->call(ProcessMarkdownTemplatesTask::class); + $this->call(RenderTemplatesTask::class); // get docs types that needs to be generated by the user base on his configs. $types = $this->call(GetDocsTypesTask::class); diff --git a/app/Containers/Documentation/ApiDocJs/private/apidoc.json b/app/Containers/Documentation/ApiDocJs/private/apidoc.json index 7836ac08e..7a5188dac 100644 --- a/app/Containers/Documentation/ApiDocJs/private/apidoc.json +++ b/app/Containers/Documentation/ApiDocJs/private/apidoc.json @@ -10,7 +10,7 @@ }, "header": { "title": "API Overview", - "filename": "../public/api-markdowns/header.md" + "filename": "../public/api-rendered-markdowns/header.md" }, "order": [ diff --git a/app/Containers/Documentation/ApiDocJs/public/apidoc.json b/app/Containers/Documentation/ApiDocJs/public/apidoc.json index 32002a1af..3da3a327c 100644 --- a/app/Containers/Documentation/ApiDocJs/public/apidoc.json +++ b/app/Containers/Documentation/ApiDocJs/public/apidoc.json @@ -10,7 +10,7 @@ }, "header": { "title": "API Overview", - "filename": "../public/api-markdowns/header.md" + "filename": "../public/api-rendered-markdowns/header.md" }, "order": [ diff --git a/app/Containers/Documentation/Tasks/ProcessMarkdownTemplatesTask.php b/app/Containers/Documentation/Tasks/RenderTemplatesTask.php similarity index 73% rename from app/Containers/Documentation/Tasks/ProcessMarkdownTemplatesTask.php rename to app/Containers/Documentation/Tasks/RenderTemplatesTask.php index c384fcf95..d5bfaabbd 100644 --- a/app/Containers/Documentation/Tasks/ProcessMarkdownTemplatesTask.php +++ b/app/Containers/Documentation/Tasks/RenderTemplatesTask.php @@ -7,18 +7,19 @@ use Illuminate\Support\Facades\Config; /** - * Class ProcessMarkdownTemplatesTask. + * Class RenderTemplatesTask. * * @author Mahmoud Zalt */ -class ProcessMarkdownTemplatesTask extends Task +class RenderTemplatesTask extends Task { + use DocsGeneratorTrait; protected $headerMarkdownContent; const TEMPLATE_PATH = 'Containers/Documentation/ApiDocJs/shared/'; - const OUTPUT_PATH = 'api-markdowns/'; + const OUTPUT_PATH = 'api-rendered-markdowns/'; /** * Read the markdown header template and fill it with some real data from the .env file. @@ -35,8 +36,14 @@ public function run() $this->replace('{{token-expires-minutes}}', Config::get('jwt.ttl')); $this->replace('{{pagination-limit}}', Config::get('repository.pagination.limit')); + // this is what the apidoc.json file will point to to load the header.md + // example: "filename": "../public/api-rendered-markdowns/header.md" + $path = public_path(self::OUTPUT_PATH . 'header.md'); + // write the actual file - file_put_contents(public_path(self::OUTPUT_PATH . 'header.md'), $this->headerMarkdownContent); + file_put_contents($path, $this->headerMarkdownContent); + + return $path; } } diff --git a/public/api-markdowns/.gitkeep b/public/api-rendered-markdowns/.gitkeep similarity index 100% rename from public/api-markdowns/.gitkeep rename to public/api-rendered-markdowns/.gitkeep diff --git a/public/api-rendered-markdowns/header.md b/public/api-rendered-markdowns/header.md new file mode 100644 index 000000000..8a185f266 --- /dev/null +++ b/public/api-rendered-markdowns/header.md @@ -0,0 +1,309 @@ +## Usage Overview + +Here are some information that should help you understand the basic usage of our RESTful API. +Including info about authenticating users, making requests, responses, potential errors, rate limiting, pagination, query parameters and more. + + + +## **Headers** + +Certain API calls require you to send data in a particular format as part of the API call. +By default, all API calls expect input in `JSON` format, however you need to inform the server that you are sending a JSON-formatted payload. +And to do that you must include the `Accept => application/json` HTTP header with every call. + + +| Header | Value Sample | When to send it | +|---------------|------------------------------|------------------------------------------------------------------------------| +| Accept | `application/json` | MUST be sent with every endpoint. | +| Authorization | `Bearer {Access-Token-Here}` | MUST be sent whenever the endpoint requires (Authenticated User) permission. | + + + +## **Rate limiting** + +All REST API requests are throttled to prevent abuse and ensure stability. +The exact number of calls that your application can make per day varies based on the type of request you are making. + +The rate limit window is `5` minutes per endpoint, with most individual calls allowing for `100` requests in each window. + +*In other words, each user is allowed `100` calls per endpoint per `5` minutes for each unique access token.* + + +For how many hits you can preform on an endpoint, you can always check the header: + +``` +X-RateLimit-Limit →100 +X-RateLimit-Remaining →50 +X-RateLimit-Reset →1487227542 +``` + + +## **Tokens** + +The Access Token lives for `30 days, 0 hours, 0 minutes and 0 seconds`. (equivalent to `43200` minutes). + +*You will need to re-autneticate the user when the token expires.* + + +## **Pagination** + +By default, all fetch requests return the first `10` items in the list. Check the **Query Parameters** for how to controll the pagination. + + +## **Responses** + +Unless otherwise specified, all of API endpoints will return the information that you request in the JSON data format. + + +#### Normal response example + +```shell +{ + "data": { + "object": "Role", + "id": "owpmaymq", + "name": "admin", + "description": "Administrator", + "display_name": null, + "permissions": { + "data": [ + { + "object": "Permission", + "id": "wkxmdazl", + "name": "update-users", + "description": "Update a User.", + "display_name": null + }, + { + "object": "Permission", + "id": "qrvzpjzb", + "name": "delete-users", + "description": "Delete a User.", + "display_name": null + } + ] + } + } +} +``` + + +#### Pagination + +*The pagination object is always returned in the **meta** when pagination is available on the endpoint.* + +```shell + "data": [...], + "meta": { + "pagination": { + "total": 2000, + "count": 30, + "per_page": 30, + "current_page": 22, + "total_pages": 1111, + "links": { + "previous": "http://api.hello.dev/endpoint?page=21" + } + } + } +``` + +#### Header + +Header Response : + +``` +Cache-Control →private, must-revalidate +Connection →keep-alive +Content-Type →application/json +Date →Thu, 14 Feb 2014 22:33:55 GMT +ETag →"9c83bf4cf0d09c34782572727281b85879dd4ff6" +Server →nginx +Transfer-Encoding →chunked +X-Powered-By →PHP/7.0.9 +X-RateLimit-Limit →100 +X-RateLimit-Remaining →99 +X-RateLimit-Reset →1487277532 +``` + + + +## **Query Parameters** + +Query parameters are optional, you can apply them to some endopints whenever you need them. + +### Ordering + +The `?orderBy=` parameter can be applied to any **`GET`** HTTP request responsible for listing records. + + +**Usage:** + +``` +api.hello.dev/endpoint?orderBy=created_at +``` + + + +### Sorting + +The `?sortedBy=` parameter is usually used with the `orderBy` parameter. + +By default the `orderBy` sorts the data in **Ascending** order, if you want the data sorted in **Descending** order, you can add `&sortedBy=desc`. + + + +**Usage:** + +``` +api.hello.dev/endpoint?orderBy=name&sortedBy=desc +``` + +Order By Accepts: + +- `asc` for Ascending. +- `desc` for Descending. + + + + + +### Searching + +The `?search=` parameter can be applied to any **`GET`** HTTP request. + + +**Usage:** + +#### Search any field: + +``` +api.hello.dev/endpoint?search=keyword here +``` + +> Space should be replaced with `%20` (search=keyword%20here). + +#### Search any field for multiple keywords: + +``` +api.hello.dev/endpoint?search=first keyword;second keyword +``` + +#### Search in specific field: +``` +api.hello.dev/endpoint?search=field:keyword here +``` + +#### Search in specific fields for multiple keywords: +``` +api.hello.dev/endpoint?search=field1:first field keyword;field2:second field keyword +``` + +#### Define query condition: + +``` +api.hello.dev/endpoint?search=field:keyword&searchFields=name:like +``` + +Available Conditions: + +- `like`: string like the field. (SQL query `%keyword%`). +- `=`: string exact match. + + +#### Define query condition for multiple fields: + +``` +api.hello.dev/endpoint?search=field1:first keyword;field2:second keyword&searchFields=field1:like;field2:=; +``` + + + +### Filtering + +The `?orderBy=` parameter can be applied to any **`GET`** HTTP request. And is used to request only certain fields. + +**Usage:** + +Return only ID and Name from that Model, (everything else will be returned as `null`). + +``` +api.hello.dev/endpoint?filter=id;name +``` + + +### Paginating + +The `?page=` parameter can be applied to any **`GET`** HTTP request responsible for listing records (mainly for Paginated data). + +**Usage:** + +``` +api.hello.dev/endpoint?page=200 +``` + + +### Relationships + +The `?include=` parameter can be used with any endpoint, only if it supports it. + +How to use it: let's say there's a Driver object and Car object. And there's an endopint `/cars` that returns all the cars objects. +The include allows getting the cars with their drivers `/cars?include=drivers`. + +However, for this parameter to work, the endpoint `/cars` should clearly define that it +accepts `driver` as relationship (in the **Available Relationships** section). + +**Usage:** + +``` +api.hello.dev/endpoint?include=relationship +``` + + + +### Caching + +Some endpoints stores their response data in memory (chaching) after quering them for the first time, to speed up the response time. +The `?skipCache=` parameter can be used to force skip loading the response data from the server cache and instead get a fresh data from the database upon the request. + +**Usage:** + +``` +api.hello.dev/endpoint?skipCache=true +``` + + + + +## **Errors** + + +General Errors: + +| Error Code | Message | Reason | +|------------|---------------------------------------------------------------------------------------|-----------------------------------------------------| +| 401 | Wrong number of segments. | Wrong Token. | +| 401 | Failed to authenticate because of bad credentials or an invalid authorization header. | Missing parts of the Token. | +| 401 | Could not decode token: The token ... is an invalid JWS. | Missing Token. | +| 405 | Method Not Allowed. | Wrong Endpoint URL. | +| 422 | Invalid Input. | Validation Error. | +| 500 | Internal Server Error. | {Report this error as soon as you get it.} | +| 500 | This action is unauthorized. | Using wrong HTTP Verb. OR using unauthorized token. | + +TO BE CONTINUE... + + +## **Requests** + +Calling unprotected endpoint example: + +```shell +curl -X POST -H "Accept: application/json" -H "Content-Type: multipart/form-data; -F "email=admin@admin.com" -F "password=admin" -F "=" "http://api.hello.dev/login" +``` + +Calling protected endpoint (passing Bearer Token) example: + +```shell +curl -X GET -H "Accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." -H "http://api.hello.dev/users" +``` +