From ceb8c77c82834d3ca069ba15b0a6ddd6af6cd062 Mon Sep 17 00:00:00 2001 From: arhimede Date: Sat, 5 Sep 2026 18:34:53 +0300 Subject: [PATCH] Use one sentence per line in v4, v5 and v6 docs Reflows hard-wrapped prose so each sentence occupies its own line. Line breaks only, no wording changes. Signed-off-by: arhimede --- docs/book/v4/core-features/authentication.md | 40 +- docs/book/v4/core-features/authorization.md | 26 +- .../v4/core-features/content-validation.md | 58 +-- docs/book/v4/core-features/cors.md | 9 +- docs/book/v4/core-features/exceptions.md | 19 +- docs/book/v4/installation/doctrine-orm.md | 5 +- docs/book/v4/installation/getting-started.md | 5 +- .../v4/installation/test-the-installation.md | 3 +- docs/book/v4/introduction/file-structure.md | 6 +- docs/book/v4/introduction/introduction.md | 26 +- .../book/v4/tutorials/token-authentication.md | 5 +- docs/book/v5/core-features/authentication.md | 40 +- docs/book/v5/core-features/authorization.md | 26 +- .../v5/core-features/content-validation.md | 3 +- docs/book/v5/core-features/error-reporting.md | 3 +- docs/book/v5/installation/composer.md | 6 +- docs/book/v5/installation/doctrine-orm.md | 5 +- docs/book/v5/installation/getting-started.md | 5 +- .../v5/installation/test-the-installation.md | 3 +- docs/book/v5/introduction/introduction.md | 3 +- .../book/v5/openapi/generate-documentation.md | 6 +- docs/book/v5/openapi/getting-help.md | 3 +- .../book/v5/openapi/initialized-components.md | 11 +- docs/book/v5/openapi/introduction.md | 7 +- docs/book/v5/openapi/render-documentation.md | 28 +- docs/book/v5/openapi/use-documentation.md | 90 ++-- docs/book/v5/openapi/write-documentation.md | 25 +- docs/book/v5/tutorials/cors.md | 9 +- docs/book/v5/tutorials/create-book-module.md | 9 +- .../v5/tutorials/find-user-by-identity.md | 424 +++++++++--------- .../book/v5/tutorials/token-authentication.md | 5 +- docs/book/v5/upgrading/UPGRADE-5.3.md | 4 +- docs/book/v6/core-features/authentication.md | 40 +- docs/book/v6/core-features/authorization.md | 26 +- .../v6/core-features/content-validation.md | 3 +- docs/book/v6/core-features/error-reporting.md | 3 +- .../injectable-input-filters.md | 3 +- .../v6/extended-features/route-grouping.md | 3 +- docs/book/v6/installation/composer.md | 6 +- docs/book/v6/installation/getting-started.md | 5 +- .../v6/installation/test-the-installation.md | 3 +- docs/book/v6/introduction/introduction.md | 3 +- .../book/v6/openapi/generate-documentation.md | 6 +- docs/book/v6/openapi/getting-help.md | 3 +- .../book/v6/openapi/initialized-components.md | 11 +- docs/book/v6/openapi/introduction.md | 7 +- docs/book/v6/openapi/render-documentation.md | 28 +- docs/book/v6/openapi/use-documentation.md | 90 ++-- docs/book/v6/openapi/write-documentation.md | 25 +- docs/book/v6/security/basic-security.md | 3 +- docs/book/v6/security/oauth2-security.md | 6 +- docs/book/v6/tutorials/cors.md | 9 +- .../create-book-module-via-dot-maker.md | 9 +- docs/book/v6/tutorials/create-book-module.md | 9 +- .../v6/tutorials/find-user-by-identity.md | 424 +++++++++--------- .../book/v6/tutorials/token-authentication.md | 5 +- 56 files changed, 797 insertions(+), 850 deletions(-) diff --git a/docs/book/v4/core-features/authentication.md b/docs/book/v4/core-features/authentication.md index 86eced9b..c16f5f01 100644 --- a/docs/book/v4/core-features/authentication.md +++ b/docs/book/v4/core-features/authentication.md @@ -1,41 +1,35 @@ # Authentication -Authentication is the process by which an identity is presented to the application. It ensures that the entity -making the request has the proper credentials to access the API. +Authentication is the process by which an identity is presented to the application. +It ensures that the entity making the request has the proper credentials to access the API. **Dotkernel API** identities are delivered to the application from the client through the `Authorization` request. -If it is present, the application tries to find and assign the identity to the application. If it is not presented, -Dotkernel API assigns a default `guest` identity, represented by an instance of the class -`Mezzio\Authentication\UserInterface`. +If it is present, the application tries to find and assign the identity to the application. +If it is not presented, Dotkernel API assigns a default `guest` identity, represented by an instance of the class `Mezzio\Authentication\UserInterface`. ## Configuration -Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already -configured out of the box. But if you want to dig more, the configuration is stored in -`config/autoload/local.php` under the `authentication` key. +Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already configured out of the box. +But if you want to dig more, the configuration is stored in `config/autoload/local.php` under the `authentication` key. -> You can check the -> [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) -> configuration part for more info. +> You can check the [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) configuration part for more info. ## How it works -Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and -simple, token-based APIs. It allows each user of your application to generate API tokens for their accounts. +Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and simple, token-based APIs. +It allows each user of your application to generate API tokens for their accounts. The authentication happens through the middleware in the `Api\App\Middleware\AuthenticationMiddleware`. ## Database -When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. All the tables -required for authentication are automatically created and populated. +When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. +All the tables required for authentication are automatically created and populated. -In Dotkernel API, authenticated users come from either the `admin` or the `user` table. We choose to keep the admin -table separated from the users to prevent users of the application from accessing sensitive data, which only the -administrators of the application should access. +In Dotkernel API, authenticated users come from either the `admin` or the `user` table. +We choose to keep the admin table separated from the users to prevent users of the application from accessing sensitive data, which only the administrators of the application should access. -The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as -their names (**we recommend you change the default passwords**). +The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as their names (**we recommend you change the default passwords**). As you guessed each client serves to authenticate `admin` or `user`. @@ -43,8 +37,7 @@ Another table that is pre-populated is the `oauth_scopes` table, with the `api` ### Issuing API Tokens -Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows -authentication to an API using the user's credentials (generally a username and password). +Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows authentication to an API using the user's credentials (generally a username and password). The client sends a POST request to the `/security/generate-token` with the following parameters: @@ -80,8 +73,7 @@ The server responds with a JSON as follows: } ``` -Next time when you make a request to the server to an authenticated endpoint, the client should use -the `Authorization` header request. +Next time when you make a request to the server to an authenticated endpoint, the client should use the `Authorization` header request. ```shell GET /users/1 HTTP/1.1 diff --git a/docs/book/v4/core-features/authorization.md b/docs/book/v4/core-features/authorization.md index 7891a24b..77eab9e4 100644 --- a/docs/book/v4/core-features/authorization.md +++ b/docs/book/v4/core-features/authorization.md @@ -1,16 +1,13 @@ # Authorization -Authorization is the process by which a system takes a validated identity and checks if that identity has access to a -given resource. +Authorization is the process by which a system takes a validated identity and checks if that identity has access to a given resource. -**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of -Role-Based Access Control (RBAC). +**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of Role-Based Access Control (RBAC). ## How it works -In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define -roles for each entity. RBAC comes in to ensure that each entity has the appropriate role and permission to access a -resource. +In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define roles for each entity. +RBAC comes in to ensure that each entity has the appropriate role and permission to access a resource. The authorization happens through the `Api\App\Middleware\AuthorizationMiddleware` middleware. @@ -53,13 +50,11 @@ The configuration file for the role and permission definitions is `config/autolo ], ``` -> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) -> for more information. +> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) for more information. ## Usage -Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users -roles (`user`, `guest`). +Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users roles (`user`, `guest`). Roles inherit the permissions from their parents: @@ -68,10 +63,9 @@ Roles inherit the permissions from their parents: - `user` has no parent - `guest` has `user` as a parent which means `user` also has `guest` permissions -For each role we defined an array of permissions. A permission in Dotkernel API is basically a route name. +For each role we defined an array of permissions. +A permission in Dotkernel API is basically a route name. -As you can see, the `superuser` does not have its own permissions, because it gains all the permissions -from `admin`, no need to define explicit permissions. +As you can see, the `superuser` does not have its own permissions, because it gains all the permissions from `admin`, no need to define explicit permissions. -The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but -`guest` cannot access user-specific routes. +The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but `guest` cannot access user-specific routes. diff --git a/docs/book/v4/core-features/content-validation.md b/docs/book/v4/core-features/content-validation.md index ec01f34d..2a5d4a5e 100644 --- a/docs/book/v4/core-features/content-validation.md +++ b/docs/book/v4/core-features/content-validation.md @@ -6,21 +6,15 @@ application can deliver. - To determine the `Content-Type` of incoming data and deserialize it so the application can utilize it. -Essentially, content negotiation is the *client* telling the server what it is sending and what it wants in return, and -the server determining if it can do what the client requests. +Essentially, content negotiation is the *client* telling the server what it is sending and what it wants in return, and the server determining if it can do what the client requests. -Content negotiation validation in **Dotkernel API** happens through middleware, and it ensures that the incoming -request and the outgoing response conform to the content types specified in the config file for all routes or for a -specific route. +Content negotiation validation in **Dotkernel API** happens through middleware, and it ensures that the incoming request and the outgoing response conform to the content types specified in the config file for all routes or for a specific route. -It performs validation on the `Accept` and `Content-Type` headers of the request and response and returning appropriate -errors responses when necessary. +It performs validation on the `Accept` and `Content-Type` headers of the request and response and returning appropriate errors responses when necessary. ## Configuration -In Dotkernel API the configuration file for content negotiation is held -in `config/autoload/content-negotiation.global.php` -and the array looks like this: +In Dotkernel API the configuration file for content negotiation is held in `config/autoload/content-negotiation.global.php` and the array looks like this: ```php return [ @@ -43,39 +37,32 @@ return [ ]; ``` -Except the `default` key, all your keys must match the route name, for example in Dotkernel API we have the route to -list all admins, which name is `admin.list`. +Except the `default` key, all your keys must match the route name, for example in Dotkernel API we have the route to list all admins, which name is `admin.list`. -If you did not specify a route name to configure your specifications about content negotiation, the `default` one will -be in place. The `default` key is `mandatory`. +If you did not specify a route name to configure your specifications about content negotiation, the `default` one will be in place. +The `default` key is `mandatory`. -Every route configuration must come with `Accept` and `Content-Type` keys, basically this will be the keys that the -request headers will be validated against. +Every route configuration must come with `Accept` and `Content-Type` keys, basically this will be the keys that the request headers will be validated against. ## Accept Negotiation -This specifies that your server can return that representation, or at least one of the representation sent by the -client. +This specifies that your server can return that representation, or at least one of the representation sent by the client. ```shell GET /admin HTTP/1.1 Accept: application/json ``` -This request indicates the client wants `application/json` in return. Now the server, through the config file will try -to validate if that representation can be returned, basically if `application/json` is presented in the `Accept` key. +This request indicates the client wants `application/json` in return. +Now the server, through the config file will try to validate if that representation can be returned, basically if `application/json` is presented in the `Accept` key. If the representation cannot be returned, a status code `406 - Not Acceptable` will be returned. -If the representation can be returned, the server should report the media type through `Content-Type` header of the -response. +If the representation can be returned, the server should report the media type through `Content-Type` header of the response. -> Due to how these validations are made, for a `json` media type, the server can return a more generic media type, -> for example, if the clients send `Accept: application/vnd.api+json` and you configured your `Accept` key -> as `application/json` the representation will still be returned as `json`. +> Due to how these validations are made, for a `json` media type, the server can return a more generic media type, for example, if the clients send `Accept: application/vnd.api+json` and you configured your `Accept` key as `application/json` the representation will still be returned as `json`. -> If the `Accept` header of the request contains `*/*` it means that whatever the server can return it is OK, so it can -> return anything. +> If the `Accept` header of the request contains `*/*` it means that whatever the server can return it is OK, so it can return anything. ## Content-Type Negotiation @@ -90,23 +77,18 @@ Content-Type: application/json } ``` -The server will try to validate the `Content-Type` header against your configured `Content-Type` key from the config -file, and if the format is not supported, a status code `415 - Unsupported Media Type` will be returned. +The server will try to validate the `Content-Type` header against your configured `Content-Type` key from the config file, and if the format is not supported, a status code `415 - Unsupported Media Type` will be returned. -For example, if you have a route that needs a file to be uploaded , normally you will configure the `Content-Type` of -that route to be `multipart/form-data`. The above request will fail as the client send `application/json` as -`Content-Type`. +For example, if you have a route that needs a file to be uploaded , normally you will configure the `Content-Type` of that route to be `multipart/form-data`. +The above request will fail as the client send `application/json` as `Content-Type`. -> If the request does not contain "Content-Type" header, that means that the server will try to deserialize the data as -> it can. +> If the request does not contain "Content-Type" header, that means that the server will try to deserialize the data as it can. ## The `Request <-> Response` validation -In addition to the validation described above, a third one is happening and is the last one: the server will check if -the request `Accept` header can really be returned by the response. +In addition to the validation described above, a third one is happening and is the last one: the server will check if the request `Accept` header can really be returned by the response. Through the way **Dotkernel API** is returning a response in handler, a content type is always set. -This cannot be the case in any custom response but in any case the server will check what `Content-Type` the response is -returning and will try to validate that against the `Accept` header of the request. +This cannot be the case in any custom response but in any case the server will check what `Content-Type` the response is returning and will try to validate that against the `Accept` header of the request. If the validation fails, a status code `406 - Not Acceptable` will be returned. diff --git a/docs/book/v4/core-features/cors.md b/docs/book/v4/core-features/cors.md index dd5264d1..d2e2557b 100644 --- a/docs/book/v4/core-features/cors.md +++ b/docs/book/v4/core-features/cors.md @@ -2,15 +2,13 @@ ## What is CORS? -**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other -origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. +**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. ## Why do we need CORS? When integrating an API, most developers have encountered the following error message: -> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: -> No ‘Access-Control-Allow-Origin’ header is present on the requested resource. +> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. This happens because the API (_RESOURCE_URL_) is not configured to accept requests from the client (_ORIGIN_URL_). @@ -86,7 +84,6 @@ This list explains the above configuration values: Save and close the file. -> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` -> array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. +> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. For more info, see [mezzio/mezzio-cors documentation](https://docs.mezzio.dev/mezzio-cors/v1/middleware/#configuration). diff --git a/docs/book/v4/core-features/exceptions.md b/docs/book/v4/core-features/exceptions.md index 764287f8..100a8e48 100644 --- a/docs/book/v4/core-features/exceptions.md +++ b/docs/book/v4/core-features/exceptions.md @@ -2,15 +2,12 @@ ## What are exceptions? -Exceptions are a powerful mechanism for handling errors and other exceptional conditions that may occur during the -execution of a script. -They provide a way to manage errors in a structured and controlled manner, separating error-handling code from regular -code. +Exceptions are a powerful mechanism for handling errors and other exceptional conditions that may occur during the execution of a script. +They provide a way to manage errors in a structured and controlled manner, separating error-handling code from regular code. ## How we use exceptions? -When it comes to handling exceptions, **Dotkernel API** relies on the usage of easy-to-understand, problem-specific -exceptions. +When it comes to handling exceptions, **Dotkernel API** relies on the usage of easy-to-understand, problem-specific exceptions. Out-of-the-box we provide the following custom exceptions: @@ -53,8 +50,7 @@ Out-of-the-box we provide the following custom exceptions: ## How it works? -During a request, if there is no uncaught exception **Dotkernel API** will return a JSON response with the data provided -by the handler that handled the request. +During a request, if there is no uncaught exception **Dotkernel API** will return a JSON response with the data provided by the handler that handled the request. Else, it will build and send a response based on the exception thrown: @@ -69,9 +65,7 @@ Else, it will build and send a response based on the exception thrown: ## How to extend? -In this example we will create a custom exception called `CustomException`, place it next to the already existing custom -exceptions (you can use your preferred location) and finally return a custom HTTP status code when `CustomException` is -encountered. +In this example we will create a custom exception called `CustomException`, place it next to the already existing custom exceptions (you can use your preferred location) and finally return a custom HTTP status code when `CustomException` is encountered. ### Step 1: Create exception file @@ -106,8 +100,7 @@ Save and close the file. ### Step 3: Test for failure -Access your API's home page URL and make sure it returns `500 Internal Server Error` HTTP status code and the following -content: +Access your API's home page URL and make sure it returns `500 Internal Server Error` HTTP status code and the following content: ```json { diff --git a/docs/book/v4/installation/doctrine-orm.md b/docs/book/v4/installation/doctrine-orm.md index f36dcf32..286e9a4e 100644 --- a/docs/book/v4/installation/doctrine-orm.md +++ b/docs/book/v4/installation/doctrine-orm.md @@ -16,7 +16,10 @@ php vendor/bin/doctrine-migrations migrate This command will prompt you to confirm that you want to run it. -> WARNING! You are about to execute a migration in database "..." that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes]: +> WARNING! +> You are about to execute a migration in database "..." that could result in schema changes and data loss. +> Are you sure you wish to continue? +> (yes/no) [yes]: Hit `Enter` to confirm the operation. diff --git a/docs/book/v4/installation/getting-started.md b/docs/book/v4/installation/getting-started.md index 6302249f..884510c5 100644 --- a/docs/book/v4/installation/getting-started.md +++ b/docs/book/v4/installation/getting-started.md @@ -5,8 +5,9 @@ > If you are using Windows as OS on your machine, you can use WSL2 as development environment. > Read more here: [PHP-Mariadb-on-WLS2](https://www.dotkernel.com/php-development/almalinux-9-in-wsl2-install-php-apache-mariadb-composer-phpmyadmin/) -Using your terminal, navigate inside the directory you want to download the project files into. Make sure that the -directory is empty before proceeding to the download process. Once there, run the following command: +Using your terminal, navigate inside the directory you want to download the project files into. +Make sure that the directory is empty before proceeding to the download process. +Once there, run the following command: ```shell git clone https://github.com/dotkernel/api.git . diff --git a/docs/book/v4/installation/test-the-installation.md b/docs/book/v4/installation/test-the-installation.md index 9061b5d9..148266f8 100644 --- a/docs/book/v4/installation/test-the-installation.md +++ b/docs/book/v4/installation/test-the-installation.md @@ -12,8 +12,7 @@ php -S 0.0.0.0:8080 -t public ## Running tests -The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this -command: +The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this command: ```shell php vendor/bin/phpunit diff --git a/docs/book/v4/introduction/file-structure.md b/docs/book/v4/introduction/file-structure.md index b022e45e..84519a02 100644 --- a/docs/book/v4/introduction/file-structure.md +++ b/docs/book/v4/introduction/file-structure.md @@ -26,7 +26,8 @@ When using Dotkernel API, the following structure is installed by default: ## `src` directory -This directory contains all source code related to the Module. It should contain following directories, if they’re not empty: +This directory contains all source code related to the Module. +It should contain following directories, if they’re not empty: * Handler - Action classes (similar to Controllers but can only perform one action) * Entity - For database entities @@ -47,7 +48,8 @@ The `src` directory should also contain 2 files: This directory contains the template files, used for example to help render e-mail templates. -> Dotkernel API uses twig as Templating Engine. All template files have the extension .html.twig +> Dotkernel API uses twig as Templating Engine. +> All template files have the extension .html.twig ## `data` directory diff --git a/docs/book/v4/introduction/introduction.md b/docs/book/v4/introduction/introduction.md index 1d096f40..4f697585 100644 --- a/docs/book/v4/introduction/introduction.md +++ b/docs/book/v4/introduction/introduction.md @@ -32,7 +32,8 @@ The benefit of Doctrine for the programmer is the ability to focus on the object ## Documentation -Our documentation is Postman based. We use the following files in which we store information about every available endpoint ready to be tested: +Our documentation is Postman based. +We use the following files in which we store information about every available endpoint ready to be tested: * documentation/Dotkernel_API.postman_collection.json * documentation/Dotkernel_API.postman_environment.json @@ -43,15 +44,20 @@ For our API payloads (a value object for describing the API resource, its relati ## CORS -By using `MezzioCorsMiddlewareCorsMiddleware`, the CORS preflight will be recognized and the middleware will start to detect the proper CORS configuration. The Router is used to detect every allowed request method by executing a route match with all possible request methods. Therefore, for every preflight request, there is at least one Router request. +By using `MezzioCorsMiddlewareCorsMiddleware`, the CORS preflight will be recognized and the middleware will start to detect the proper CORS configuration. +The Router is used to detect every allowed request method by executing a route match with all possible request methods. +Therefore, for every preflight request, there is at least one Router request. ## OAuth 2.0 -OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts on your Dotkernel API. We are using mezzio/mezzio-authentication-oauth2 which provides OAuth 2.0 authentication for Mezzio and PSR-7/PSR-15 applications by using league/oauth2-server package. +OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts on your Dotkernel API. +We are using mezzio/mezzio-authentication-oauth2 which provides OAuth 2.0 authentication for Mezzio and PSR-7/PSR-15 applications by using league/oauth2-server package. ## Email -It is not unlikely for an API to send emails depending on the use case. Here is another area where Dotkernel API shines. Using `DotMailServiceMailService` provided by dotkernel/dot-mail you can easily send custom email templates. +It is not unlikely for an API to send emails depending on the use case. +Here is another area where Dotkernel API shines. +Using `DotMailServiceMailService` provided by dotkernel/dot-mail you can easily send custom email templates. ## Configuration @@ -59,19 +65,22 @@ From authorization at request route level to API keys for your application, you Registering a new module can be done by including its ConfigProvider.php in config.php. -Brand new middlewares should go into pipeline.php. Here you can edit the order in which they run and find more info about the currently included ones. +Brand new middlewares should go into pipeline.php. +Here you can edit the order in which they run and find more info about the currently included ones. You can further customize your api within the autoload directory where each configuration category has its own file. ## Routing -Each module has a `RoutesDelegator.php` file for managing existing routes inside that specific module. It also allows a quick way of adding new routes by providing the route path, Middlewares that the route will use and the route name. +Each module has a `RoutesDelegator.php` file for managing existing routes inside that specific module. +It also allows a quick way of adding new routes by providing the route path, Middlewares that the route will use and the route name. You can allocate permissions per route name in order to restrict access for a user role to a specific route in `config/autoload/authorization.global.php`. ## Commands -For registering new commands first make sure your command class extends `SymfonyComponentConsoleCommandCommand`. Then you can enable it by registering it in `config/autoload/cli.global.php`. +For registering new commands first make sure your command class extends `SymfonyComponentConsoleCommandCommand`. +Then you can enable it by registering it in `config/autoload/cli.global.php`. ## File locker @@ -89,7 +98,8 @@ Note: The File Locker System will create a `command-{command-default-name}.lock` ## Tests -One of the best ways to ensure the quality of your product is to create and run functional and unit tests. You can find factory-made tests in the tests/AppTest/ folder, and you can also register your own. +One of the best ways to ensure the quality of your product is to create and run functional and unit tests. +You can find factory-made tests in the tests/AppTest/ folder, and you can also register your own. We have 2 types of tests: functional and unit tests, you can run both types at the same type by executing this command: diff --git a/docs/book/v4/tutorials/token-authentication.md b/docs/book/v4/tutorials/token-authentication.md index a23088db..047ca9d4 100644 --- a/docs/book/v4/tutorials/token-authentication.md +++ b/docs/book/v4/tutorials/token-authentication.md @@ -2,9 +2,8 @@ ## What is token authentication? -Token authentication means making a request to an API endpoint while also sending a special header that contains an -access token. The access token was previously generated by (usually) the same API as the one you are sending requests to -and it consists of an alphanumeric string. +Token authentication means making a request to an API endpoint while also sending a special header that contains an access token. +The access token was previously generated by (usually) the same API as the one you are sending requests to and it consists of an alphanumeric string. ## How does it work? diff --git a/docs/book/v5/core-features/authentication.md b/docs/book/v5/core-features/authentication.md index 86eced9b..c16f5f01 100644 --- a/docs/book/v5/core-features/authentication.md +++ b/docs/book/v5/core-features/authentication.md @@ -1,41 +1,35 @@ # Authentication -Authentication is the process by which an identity is presented to the application. It ensures that the entity -making the request has the proper credentials to access the API. +Authentication is the process by which an identity is presented to the application. +It ensures that the entity making the request has the proper credentials to access the API. **Dotkernel API** identities are delivered to the application from the client through the `Authorization` request. -If it is present, the application tries to find and assign the identity to the application. If it is not presented, -Dotkernel API assigns a default `guest` identity, represented by an instance of the class -`Mezzio\Authentication\UserInterface`. +If it is present, the application tries to find and assign the identity to the application. +If it is not presented, Dotkernel API assigns a default `guest` identity, represented by an instance of the class `Mezzio\Authentication\UserInterface`. ## Configuration -Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already -configured out of the box. But if you want to dig more, the configuration is stored in -`config/autoload/local.php` under the `authentication` key. +Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already configured out of the box. +But if you want to dig more, the configuration is stored in `config/autoload/local.php` under the `authentication` key. -> You can check the -> [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) -> configuration part for more info. +> You can check the [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) configuration part for more info. ## How it works -Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and -simple, token-based APIs. It allows each user of your application to generate API tokens for their accounts. +Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and simple, token-based APIs. +It allows each user of your application to generate API tokens for their accounts. The authentication happens through the middleware in the `Api\App\Middleware\AuthenticationMiddleware`. ## Database -When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. All the tables -required for authentication are automatically created and populated. +When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. +All the tables required for authentication are automatically created and populated. -In Dotkernel API, authenticated users come from either the `admin` or the `user` table. We choose to keep the admin -table separated from the users to prevent users of the application from accessing sensitive data, which only the -administrators of the application should access. +In Dotkernel API, authenticated users come from either the `admin` or the `user` table. +We choose to keep the admin table separated from the users to prevent users of the application from accessing sensitive data, which only the administrators of the application should access. -The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as -their names (**we recommend you change the default passwords**). +The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as their names (**we recommend you change the default passwords**). As you guessed each client serves to authenticate `admin` or `user`. @@ -43,8 +37,7 @@ Another table that is pre-populated is the `oauth_scopes` table, with the `api` ### Issuing API Tokens -Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows -authentication to an API using the user's credentials (generally a username and password). +Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows authentication to an API using the user's credentials (generally a username and password). The client sends a POST request to the `/security/generate-token` with the following parameters: @@ -80,8 +73,7 @@ The server responds with a JSON as follows: } ``` -Next time when you make a request to the server to an authenticated endpoint, the client should use -the `Authorization` header request. +Next time when you make a request to the server to an authenticated endpoint, the client should use the `Authorization` header request. ```shell GET /users/1 HTTP/1.1 diff --git a/docs/book/v5/core-features/authorization.md b/docs/book/v5/core-features/authorization.md index 7891a24b..77eab9e4 100644 --- a/docs/book/v5/core-features/authorization.md +++ b/docs/book/v5/core-features/authorization.md @@ -1,16 +1,13 @@ # Authorization -Authorization is the process by which a system takes a validated identity and checks if that identity has access to a -given resource. +Authorization is the process by which a system takes a validated identity and checks if that identity has access to a given resource. -**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of -Role-Based Access Control (RBAC). +**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of Role-Based Access Control (RBAC). ## How it works -In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define -roles for each entity. RBAC comes in to ensure that each entity has the appropriate role and permission to access a -resource. +In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define roles for each entity. +RBAC comes in to ensure that each entity has the appropriate role and permission to access a resource. The authorization happens through the `Api\App\Middleware\AuthorizationMiddleware` middleware. @@ -53,13 +50,11 @@ The configuration file for the role and permission definitions is `config/autolo ], ``` -> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) -> for more information. +> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) for more information. ## Usage -Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users -roles (`user`, `guest`). +Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users roles (`user`, `guest`). Roles inherit the permissions from their parents: @@ -68,10 +63,9 @@ Roles inherit the permissions from their parents: - `user` has no parent - `guest` has `user` as a parent which means `user` also has `guest` permissions -For each role we defined an array of permissions. A permission in Dotkernel API is basically a route name. +For each role we defined an array of permissions. +A permission in Dotkernel API is basically a route name. -As you can see, the `superuser` does not have its own permissions, because it gains all the permissions -from `admin`, no need to define explicit permissions. +As you can see, the `superuser` does not have its own permissions, because it gains all the permissions from `admin`, no need to define explicit permissions. -The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but -`guest` cannot access user-specific routes. +The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but `guest` cannot access user-specific routes. diff --git a/docs/book/v5/core-features/content-validation.md b/docs/book/v5/core-features/content-validation.md index 33f7e707..8efc2193 100644 --- a/docs/book/v5/core-features/content-validation.md +++ b/docs/book/v5/core-features/content-validation.md @@ -83,8 +83,7 @@ Content-Type: application/json The server will try to validate the `Content-Type` header against your configured `Content-Type` key from the config file, and if the format is not supported, a status code `415 - Unsupported Media Type` will be returned. For example, if you have a route that needs a file to be uploaded, normally you will configure the `Content-Type` of that route to be `multipart/form-data`. -The above request will fail because the client sends `application/json` as -`Content-Type`. +The above request will fail because the client sends `application/json` as `Content-Type`. > If the request does not contain a "Content-Type" header, that means that the server will try to deserialize the data to the best of its abilities. diff --git a/docs/book/v5/core-features/error-reporting.md b/docs/book/v5/core-features/error-reporting.md index a429a08b..e06cb223 100644 --- a/docs/book/v5/core-features/error-reporting.md +++ b/docs/book/v5/core-features/error-reporting.md @@ -66,7 +66,8 @@ If both return `false`, a `ForbiddenException` is thrown and the error message d - The tokens under `ErrorReportServiceInterface::class` . `tokens` do not expire. - The log file stores the token value too, making it easy to identify which application sent the error message. -If your request passes all the checks, the message is saved in the log file specified in `ErrorReportServiceInterface::class` . `path`. +If your request passes all the checks, the message is saved in the log file specified in `ErrorReportServiceInterface::class` . +`path`. #### Tips and tricks diff --git a/docs/book/v5/installation/composer.md b/docs/book/v5/installation/composer.md index b5f83b7d..3b92c514 100644 --- a/docs/book/v5/installation/composer.md +++ b/docs/book/v5/installation/composer.md @@ -1,6 +1,7 @@ # Composer Installation of Packages -Composer is required to install Dotkernel `api`. You can install Composer from the [official site](https://getcomposer.org/). +Composer is required to install Dotkernel `api`. +You can install Composer from the [official site](https://getcomposer.org/). > First make sure that you have navigated your command prompt to the folder where you copied the files in the previous step. @@ -47,7 +48,8 @@ Type `0` to select `[0] Do not inject`. The next question is: -`Remember this option for other packages of the same type? (y/N)` +`Remember this option for other packages of the same type? +(y/N)` Type `y` here, and hit `enter` to complete this stage. diff --git a/docs/book/v5/installation/doctrine-orm.md b/docs/book/v5/installation/doctrine-orm.md index ddcd98a5..7bc485bf 100644 --- a/docs/book/v5/installation/doctrine-orm.md +++ b/docs/book/v5/installation/doctrine-orm.md @@ -16,7 +16,10 @@ php vendor/bin/doctrine-migrations migrate This command will prompt you to confirm that you want to run it. -> WARNING! You are about to execute a migration in database "..." that could result in schema changes and data loss. Are you sure you wish to continue? (yes/no) [yes]: +> WARNING! +> You are about to execute a migration in database "..." that could result in schema changes and data loss. +> Are you sure you wish to continue? +> (yes/no) [yes]: Hit `Enter` to confirm the operation. diff --git a/docs/book/v5/installation/getting-started.md b/docs/book/v5/installation/getting-started.md index 6302249f..884510c5 100644 --- a/docs/book/v5/installation/getting-started.md +++ b/docs/book/v5/installation/getting-started.md @@ -5,8 +5,9 @@ > If you are using Windows as OS on your machine, you can use WSL2 as development environment. > Read more here: [PHP-Mariadb-on-WLS2](https://www.dotkernel.com/php-development/almalinux-9-in-wsl2-install-php-apache-mariadb-composer-phpmyadmin/) -Using your terminal, navigate inside the directory you want to download the project files into. Make sure that the -directory is empty before proceeding to the download process. Once there, run the following command: +Using your terminal, navigate inside the directory you want to download the project files into. +Make sure that the directory is empty before proceeding to the download process. +Once there, run the following command: ```shell git clone https://github.com/dotkernel/api.git . diff --git a/docs/book/v5/installation/test-the-installation.md b/docs/book/v5/installation/test-the-installation.md index 31823fab..b03d14c4 100644 --- a/docs/book/v5/installation/test-the-installation.md +++ b/docs/book/v5/installation/test-the-installation.md @@ -12,8 +12,7 @@ php -S 0.0.0.0:8080 -t public ## Running tests -The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this -command: +The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this command: ```shell php vendor/bin/phpunit diff --git a/docs/book/v5/introduction/introduction.md b/docs/book/v5/introduction/introduction.md index a21d2097..43b1c762 100644 --- a/docs/book/v5/introduction/introduction.md +++ b/docs/book/v5/introduction/introduction.md @@ -43,7 +43,8 @@ From authorization at request route level to API keys for your application, you Registering a new module can be done by including its `ConfigProvider.php` in `config.php`. -Brand new middlewares should go into `pipeline.php`. Here you can edit the order in which they run and find more info about the currently included ones. +Brand new middlewares should go into `pipeline.php`. +Here you can edit the order in which they run and find more info about the currently included ones. You can further customize your api within the `autoload` directory that holds configuration files for each category. diff --git a/docs/book/v5/openapi/generate-documentation.md b/docs/book/v5/openapi/generate-documentation.md index 15d492ee..163f3bdd 100644 --- a/docs/book/v5/openapi/generate-documentation.md +++ b/docs/book/v5/openapi/generate-documentation.md @@ -1,12 +1,10 @@ # Generating the documentation file -> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of -> your instance of **Dotkernel API**. +> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of your instance of **Dotkernel API**. Using your terminal, move to the root directory of your project. -Dotkernel API stores the OpenAPI attributes in the `src` directory, so that's the path we will use for generating the -static documentation file. +Dotkernel API stores the OpenAPI attributes in the `src` directory, so that's the path we will use for generating the static documentation file. ## Methods of generating documentation file diff --git a/docs/book/v5/openapi/getting-help.md b/docs/book/v5/openapi/getting-help.md index be76626d..e53d6b28 100644 --- a/docs/book/v5/openapi/getting-help.md +++ b/docs/book/v5/openapi/getting-help.md @@ -5,8 +5,7 @@ reference of the presented objects - see more examples of OpenAPI object representations in `zircote/swagger-php`'s [GitHub repository](https://zircote.github.io/swagger-php/guide/examples.html) - consult `zircote/swagger-php`'s -[online documentation](http://zircote.github.io/swagger-php/guide/generating-openapi-documents.html) or run the -following command to see their help page: +[online documentation](http://zircote.github.io/swagger-php/guide/generating-openapi-documents.html) or run the following command to see their help page: ```shell ./vendor/bin/openapi --help diff --git a/docs/book/v5/openapi/initialized-components.md b/docs/book/v5/openapi/initialized-components.md index af131e11..84fc9987 100644 --- a/docs/book/v5/openapi/initialized-components.md +++ b/docs/book/v5/openapi/initialized-components.md @@ -198,9 +198,8 @@ Schema: )] ``` -Using `ref: '#/components/schemas/UserRole',` in our code, we instruct `OpenAPI` to grab the existing schema `UserRole` -(not the entity, but the schema) that we just described earlier. This way we do not need to repeat code by describing -again the same object and any future modifications will happen in only one place. +Using `ref: '#/components/schemas/UserRole',` in our code, we instruct `OpenAPI` to grab the existing schema `UserRole` (not the entity, but the schema) that we just described earlier. +This way we do not need to repeat code by describing again the same object and any future modifications will happen in only one place. Then, when generating the documentation file, `OpenAPI` will transform it into the specified format (**json**/**yaml**). @@ -221,8 +220,7 @@ UserRoleCollection: type: object ``` -> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of -> your instance of **Dotkernel API**. +> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of your instance of **Dotkernel API**. > > You can add multiple servers (for staging, production etc) by duplicating the existing one. @@ -230,7 +228,8 @@ For more info, see [this page](https://spec.openapis.org/oas/latest.html#schema) ### Common schemas -We provided some schemas that are reusable across the entire project. They are defined in `src/App/src/OpenAPI.php`: +We provided some schemas that are reusable across the entire project. +They are defined in `src/App/src/OpenAPI.php`: - `#/components/schemas/Collection`: provides the default **HAL** structure to all the collections extending it - `#/components/schemas/ErrorMessage`: describes an operation that resulted in an error - may contain multiple messages diff --git a/docs/book/v5/openapi/introduction.md b/docs/book/v5/openapi/introduction.md index 0d91faf2..04939612 100644 --- a/docs/book/v5/openapi/introduction.md +++ b/docs/book/v5/openapi/introduction.md @@ -1,8 +1,5 @@ # OpenAPI documentation -In order to provide an interactive documentation, Dotkernel API implemented -[zircote/swagger-php](https://github.com/zircote/swagger-php). +In order to provide an interactive documentation, Dotkernel API implemented [zircote/swagger-php](https://github.com/zircote/swagger-php). -Using this library, developers are able to automatically generate documentation files that later can be used to provide -a comprehensive overview of the available endpoints, all the details on the requests that it can receive and the -responses these can return. +Using this library, developers are able to automatically generate documentation files that later can be used to provide a comprehensive overview of the available endpoints, all the details on the requests that it can receive and the responses these can return. diff --git a/docs/book/v5/openapi/render-documentation.md b/docs/book/v5/openapi/render-documentation.md index c151d266..602f00be 100644 --- a/docs/book/v5/openapi/render-documentation.md +++ b/docs/book/v5/openapi/render-documentation.md @@ -1,7 +1,7 @@ # Rendering the documentation file -At this step, you only have a static documentation file. You will need an interface that can render it so that you will -be able to interact with your Dotkernel API. +At this step, you only have a static documentation file. +You will need an interface that can render it so that you will be able to interact with your Dotkernel API. In order to do this, we recommend using either of: @@ -10,8 +10,7 @@ In order to do this, we recommend using either of: ## Using Swagger UI -Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `swagger.html`, -the name is up to you) and place the following HTML content in it: +Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `swagger.html`, the name is up to you) and place the following HTML content in it: ```html @@ -35,21 +34,20 @@ the name is up to you) and place the following HTML content in it: ``` -Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file -(openapi.json/openapi.yaml). The line should look similar to this: +Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file (openapi.json/openapi.yaml). +The line should look similar to this: ```js window.ui = SwaggerUIBundle({url: './openapi.yaml', dom_id: '#swagger-ui'}); ``` -Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/swagger.html` to -it. You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each -endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). +Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/swagger.html` to it. +You should see the Redoc interface with your documentation file loaded in it. +From here, you can inspect each endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). ## Using Redoc -Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `redoc.html`, -the name is up to you) and place the following HTML content in it: +Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `redoc.html`, the name is up to you) and place the following HTML content in it: ```html @@ -70,13 +68,13 @@ the name is up to you) and place the following HTML content in it: ``` -Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file -(openapi.json/openapi.yaml). The line should look similar to this: +Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file (openapi.json/openapi.yaml). +The line should look similar to this: ```js Redoc.init('./openapi.yaml', {}, document.getElementById('redoc-container')); ``` Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/redoc.html` to it. -You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each endpoint, -see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). +You should see the Redoc interface with your documentation file loaded in it. +From here, you can inspect each endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). diff --git a/docs/book/v5/openapi/use-documentation.md b/docs/book/v5/openapi/use-documentation.md index fe0330df..def28a98 100644 --- a/docs/book/v5/openapi/use-documentation.md +++ b/docs/book/v5/openapi/use-documentation.md @@ -4,23 +4,26 @@ Since Redoc is readonly, in the following section we will focus only on using Sw ## Protected endpoints -Now that you have a UI for the documentation, you can see all the endpoints. You will see that some of them have a lock -symbol right before the collapse/expand arrow. When you see this symbol next to an endpoint, it means that the endpoint -is protected and can only be accessed when authenticated with an account with proper permissions. +Now that you have a UI for the documentation, you can see all the endpoints. +You will see that some of them have a lock symbol right before the collapse/expand arrow. +When you see this symbol next to an endpoint, it means that the endpoint is protected and can only be accessed when authenticated with an account with proper permissions. ## Authentication -In Swagger UI, you will see an `Authorize` button. Clicking it will open a modal where you will find two sections: +In Swagger UI, you will see an `Authorize` button. +Clicking it will open a modal where you will find two sections: - `AuthToken` - where you will have to enter a valid auth token - `ErrorReportingToken` - where you will have to enter a valid error reporting token -Below, we will walk you through on how to find both tokens. For now, let's close the modal. +Below, we will walk you through on how to find both tokens. +For now, let's close the modal. ### Generating AuthToken -This token is required with most of the Dotkernel API endpoints. There are two entities that generate this type of -token: `(super)admin`s and `user`s. Depending on the endpoint description, you will know which one you need to use. +This token is required with most of the Dotkernel API endpoints. +There are two entities that generate this type of token: `(super)admin`s and `user`s. +Depending on the endpoint description, you will know which one you need to use. Examples: - `/user`: the description says `Admin lists user accounts` - it means that you need an AccessToken with `(super)admin` @@ -28,13 +31,14 @@ Examples: - `/user/my-account`: the description says `User fetches their own account` - it means that you need an AccessToken with `user` privileges -In the UI, find a section called `AccessToken`, toggle the `/security/generate-token` (`Generate access token`) endpoint -and click the `Try it out` button. Under the `Access token generation request` you will find a textarea prepopulated -with a JSON object. You will have to change the value of `username` and `password`. See -[this guide](../tutorials/token-authentication.md#credentials) for the credentials. +In the UI, find a section called `AccessToken`, toggle the `/security/generate-token` (`Generate access token`) endpoint and click the `Try it out` button. +Under the `Access token generation request` you will find a textarea prepopulated with a JSON object. +You will have to change the value of `username` and `password`. +See [this guide](../tutorials/token-authentication.md#credentials) for the credentials. -After you have filled out the credentials, click on the `Execute` button below the textarea. This will send the request -to your instance of Dotkernel API. If everything went well, under the textarea you should see: +After you have filled out the credentials, click on the `Execute` button below the textarea. +This will send the request to your instance of Dotkernel API. +If everything went well, under the textarea you should see: - the `curl` request that was made - the `Request URL` the request was sent to @@ -43,31 +47,29 @@ to your instance of Dotkernel API. If everything went well, under the textarea y > Save the `refresh_token` somewhere, you will need it later -Now copy the value of `access_token` (make sure you copy all the characters, without the surrounding double quotes) and -go back up to the `Authorize` button and click it to open the auth modal. Paste the copied token as the value of the -`AuthToken` and click on the **Authorize** button you see under the input field. The **Authorize** button has now -changed to **Logout**. You can close the modal. +Now copy the value of `access_token` (make sure you copy all the characters, without the surrounding double quotes) and go back up to the `Authorize` button and click it to open the auth modal. +Paste the copied token as the value of the `AuthToken` and click on the **Authorize** button you see under the input field. +The **Authorize** button has now changed to **Logout**. +You can close the modal. -From here, Swagger UI will remember the AuthToken until you close/refresh the browser tab. Also, it will automatically -append the `Authorization` header to each request, allowing you to make authorized API calls. +From here, Swagger UI will remember the AuthToken until you close/refresh the browser tab. +Also, it will automatically append the `Authorization` header to each request, allowing you to make authorized API calls. -If you need to switch to an account with different privileges, you go again to the `Authorize` button, click on it to -open the auth modal, and click **Logout** for the `AuthToken`. Then paste the new token as the value of the `AuthToken`, -click on the **Authorize** button, close the modal and continue using the UI authenticated with the new account. +If you need to switch to an account with different privileges, you go again to the `Authorize` button, click on it to open the auth modal, and click **Logout** for the `AuthToken`. +Then paste the new token as the value of the `AuthToken`, click on the **Authorize** button, close the modal and continue using the UI authenticated with the new account. ### Refreshing AuthToken -By default, auth tokens expire in 1 day. If you make an API call, and you receive an error telling you that your auth -token is expired, you need to either generate a new token (as seen above) or refresh the existing one using the -`refresh_token` received when generating the current token. +By default, auth tokens expire in 1 day. +If you make an API call, and you receive an error telling you that your auth token is expired, you need to either generate a new token (as seen above) or refresh the existing one using the `refresh_token` received when generating the current token. -In order to refresh the auth token, you find the same section called `AccessToken`, toggle the `/security/refresh-token` -(`Refresh access token`) endpoint and click the `Try it out` button. Under the `Access token refresh request` you will -find a textarea prepopulated with a JSON object. You will have to change the value of `refresh_token` to the refresh -token of your current auth token. +In order to refresh the auth token, you find the same section called `AccessToken`, toggle the `/security/refresh-token` (`Refresh access token`) endpoint and click the `Try it out` button. +Under the `Access token refresh request` you will find a textarea prepopulated with a JSON object. +You will have to change the value of `refresh_token` to the refresh token of your current auth token. -Once done, click on the `Execute` button below the textarea. This will send the request to your instance of Dotkernel -API. If everything went well, under the textarea you should see the same details: +Once done, click on the `Execute` button below the textarea. +This will send the request to your instance of Dotkernel API. +If everything went well, under the textarea you should see the same details: - the `curl` request that was made - the `Request URL` the request was sent to @@ -83,23 +85,23 @@ From here, you will follow the same steps: ### Generating ErrorReportingToken -Just like the AuthTokens, ErrorReportingTokens are used to make authorized API calls. The difference is that this token -applies only to one specific endpoint: `/error-report` (`Report an error to the API`). This endpoint is intended to be -used by third-party applications and frontends to report an error back to the API. +Just like the AuthTokens, ErrorReportingTokens are used to make authorized API calls. +The difference is that this token applies only to one specific endpoint: `/error-report` (`Report an error to the API`). +This endpoint is intended to be used by third-party applications and frontends to report an error back to the API. > This endpoint does not require `AuthTokens` In order to generate this token, follow [this guide](../commands/generate-tokens.md#generate-error-reporting-token). -Once you have the error reporting token, go again to the `Authorize` button, paste the new token as the value of the -`ErrorReportingToken`, click on the **Authorize** button and close the modal. Now you're ready to report errors to your -instance of Dotkernel API. +Once you have the error reporting token, go again to the `Authorize` button, paste the new token as the value of the `ErrorReportingToken`, click on the **Authorize** button and close the modal. +Now you're ready to report errors to your instance of Dotkernel API. ## Making API calls > The UI does not use confirmation messages before making an API call so double check any operation before executing it. -Once authorized in the UI, you can click on any endpoint to expand it. There you will find an overview of the endpoint, including: +Once authorized in the UI, you can click on any endpoint to expand it. +There you will find an overview of the endpoint, including: - Request method (`DELETE`, `GET`, `PATCH`, `POST`, `PUT`) - request URL (example: `/resource`) @@ -113,10 +115,10 @@ all the required parameters Clicking the `Try it out` button will activate any parameter input fields and the request body textarea (if any). Clicking `Cancel` will deactivate them. -Make sure you fill out all the necessary data, then click on the `Execute` found button above `Responses`. This will -send the request and return and display the API response. Once finished, you will see the response as the first item -under `Responses`, including the HTTP status code and the response body. +Make sure you fill out all the necessary data, then click on the `Execute` found button above `Responses`. +This will send the request and return and display the API response. +Once finished, you will see the response as the first item under `Responses`, including the HTTP status code and the response body. -You can repeat the request by clicking again on the `Execute` button. This will first clear the previous output and -display the new response in the same place. Additionally, between two executions, you can manually clear any previous -output using the `Clear` button next to the `Execute` button. +You can repeat the request by clicking again on the `Execute` button. +This will first clear the previous output and display the new response in the same place. +Additionally, between two executions, you can manually clear any previous output using the `Clear` button next to the `Execute` button. diff --git a/docs/book/v5/openapi/write-documentation.md b/docs/book/v5/openapi/write-documentation.md index 9247ce54..1a9cb42d 100644 --- a/docs/book/v5/openapi/write-documentation.md +++ b/docs/book/v5/openapi/write-documentation.md @@ -1,12 +1,10 @@ # Writing documentation -> In order to avoid polluting PHP files with maybe thousands of lines of OpenAPI attributes, we opted for storing them -> in separate files, called `OpenAPI.php`, one for each module. +> In order to avoid polluting PHP files with maybe thousands of lines of OpenAPI attributes, we opted for storing them in separate files, called `OpenAPI.php`, one for each module. -We already covered all the endpoints available in Dotkernel API, you can consult the existing documentation in each -module's own `OpenAPI.php` file. After you add more functionalities to your API, you will have to document the new -endpoints. This is easier than it sounds because in most cases you will do the same: add a request by method, describe -the request payload (if any), add request parameters (if any) and describe the possible responses. +We already covered all the endpoints available in Dotkernel API, you can consult the existing documentation in each module's own `OpenAPI.php` file. +After you add more functionalities to your API, you will have to document the new endpoints. +This is easier than it sounds because in most cases you will do the same: add a request by method, describe the request payload (if any), add request parameters (if any) and describe the possible responses. ## Common objects @@ -33,7 +31,8 @@ If you need help, take a look at the existing definitions found in Dotkernel API ### OA\Delete -Defines a `DELETE` HTTP request. It should specify at least the following parameters: +Defines a `DELETE` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -46,7 +45,8 @@ respective response bodies ### OA\Get -Defines a `GET` HTTP request. It should specify at least the following parameters: +Defines a `GET` HTTP request. +It should specify at least the following parameters: - `path`: the route to a single or collection of resources (example: `/resource/{uuid}` for a single resource or `/resource` for a collection of resources) @@ -60,7 +60,8 @@ respective response bodies ### OA\Patch -Defines a `PATCH` HTTP request. It should specify at least the following parameters: +Defines a `PATCH` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -74,7 +75,8 @@ respective response bodies ### OA\Post -Defines a `POST` HTTP request. It should specify at least the following parameters: +Defines a `POST` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -88,7 +90,8 @@ respective response bodies ### OA\Put -Defines a `PUT` HTTP request. It should specify at least the following parameters: +Defines a `PUT` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose diff --git a/docs/book/v5/tutorials/cors.md b/docs/book/v5/tutorials/cors.md index dd5264d1..d2e2557b 100644 --- a/docs/book/v5/tutorials/cors.md +++ b/docs/book/v5/tutorials/cors.md @@ -2,15 +2,13 @@ ## What is CORS? -**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other -origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. +**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. ## Why do we need CORS? When integrating an API, most developers have encountered the following error message: -> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: -> No ‘Access-Control-Allow-Origin’ header is present on the requested resource. +> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. This happens because the API (_RESOURCE_URL_) is not configured to accept requests from the client (_ORIGIN_URL_). @@ -86,7 +84,6 @@ This list explains the above configuration values: Save and close the file. -> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` -> array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. +> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. For more info, see [mezzio/mezzio-cors documentation](https://docs.mezzio.dev/mezzio-cors/v1/middleware/#configuration). diff --git a/docs/book/v5/tutorials/create-book-module.md b/docs/book/v5/tutorials/create-book-module.md index b6d36c90..b827a7e5 100644 --- a/docs/book/v5/tutorials/create-book-module.md +++ b/docs/book/v5/tutorials/create-book-module.md @@ -44,9 +44,11 @@ The below files structure is what we will have at the end of this tutorial and i Firstly we will need the book module, so we will implement and create the basics for a module to be registered and functional. -In `src` folder we will create the `Book` folder and in this we will create the `src` folder. So the final structure will be like this: `src/Book/src`. +In `src` folder we will create the `Book` folder and in this we will create the `src` folder. +So the final structure will be like this: `src/Book/src`. -In `src/Book/src` we will create 2 php files: `RoutesDelegator.php` and `ConfigProvider.php`. This files will be updated later with all needed configuration. +In `src/Book/src` we will create 2 php files: `RoutesDelegator.php` and `ConfigProvider.php`. +This files will be updated later with all needed configuration. * `src/Book/src/RoutesDelegator.php` @@ -135,7 +137,8 @@ class ConfigProvider composer dump-autoload ``` -That's it. The module is now registered and, we can continue creating Handlers, Services, Repositories and whatever is needed for out tutorial. +That's it. +The module is now registered and, we can continue creating Handlers, Services, Repositories and whatever is needed for out tutorial. ## File creation and contents diff --git a/docs/book/v5/tutorials/find-user-by-identity.md b/docs/book/v5/tutorials/find-user-by-identity.md index 681a4eba..1f3dca54 100644 --- a/docs/book/v5/tutorials/find-user-by-identity.md +++ b/docs/book/v5/tutorials/find-user-by-identity.md @@ -1,212 +1,212 @@ -# A practical example: Find user by identity - -## Our goal - -Create a new endpoint that fetches a user record by its identity column. - -We already have an endpoint that retrieves a user based on their UUID, so we can review it and create something similar. - -## What we have - -Let's print out all available endpoints using : - -```shell -php ./bin/cli.php route:list -``` - -This command will list all available endpoints, which looks like this: - -```text -+--------+---------------------------------+--------------------------------+ -| Method | Name | Path | -+--------+---------------------------------+--------------------------------+ -| POST | account.activate.request | /account/activate | -| PATCH | account.activate | /account/activate/{hash} | -| PATCH | account.modify-password | /account/reset-password/{hash} | -............................................................................. -............................................................................. -............................................................................. -| GET | user.my-avatar.view | /user/my-avatar | -| GET | user.role.list | /user/role | -| GET | user.role.view | /user/role/{uuid} | -| PATCH | user.update | /user/{uuid} | -| GET | user.view | /user/{uuid} | -+--------+---------------------------------+--------------------------------+ -``` - -### Note - -> **The above output is just an example.** -> -> More info about listing available endpoints can be found in `../commands/display-available-endpoints.md`. - -The endpoint we're focusing on is the last one, `user.view`, so let's take a closer look at its functionality. - -If we search for the route name `user.view` we will find its definition in the `src/User/src/RoutesDelegator.php` class, where all user related endpoints are found. - -```php -$app->get('/user/' . $uuid, UserHandler::class, 'user.view'); -``` - -Our route points to `get` method from `UserHandler` so let's navigate to that method. - -```php -public function get(ServerRequestInterface $request): ResponseInterface -{ - $user = $this->userService->findOneBy(['uuid' => $request->getAttribute('uuid')]); - - return $this->createResponse($request, $user); -} -``` - -As we can see, the method will query the database for the user based on its uuid taken from the endpoint. - -We now have an understanding of how things work and we can start to implement our own endpoint. - -### Implementation - -We need to create a new handler that will process our request, we can call it `IdentityHandler`. - -Create a new PHP class called `IdentityHandler.php` in `src/User/src/Handler` folder. - -```php -getAttribute('identity'); - if (empty($identity)) { - throw (new BadRequestException())->setMessages([sprintf(Message::INVALID_VALUE, 'identity')]); - } - - $user = $this->userService->findByIdentity($identity); - if (! $user instanceof User) { - throw new NotFoundException(Message::USER_NOT_FOUND); - } - - return $this->createResponse($request, $user); - } -} -``` - -Our handler is very similar to the existing one, with some extra steps: - -* We store the identity from the request in the `$identity` variable for later use. -* If the identity is empty we throw a `BadRequestException` with an appropriate message. -* If we can't find the user in the database we throw an `NotFoundException`. -* If the record is found, we generate and return the response. - -The next step is to register the new handler. -To do this go to `src/User/src/ConfigProvider.php`. -In the `getDependencies()` method under the `factories` key add `IdentityHandler::class => AttributedServiceFactory::class,` - -Next, create the route in `src/User/src/RoutesDelegator.php`: - -```php - $app->get( - '/user/{identity}', - IdentityHandler::class, - 'user.view.identity' - ); -``` - -### Note - -> Make sure to register the endpoint as the last one to not shadow existing endpoints. - -The last step is to set permissions on the newly created route. - -Go to `config/autoload/authorization.global.php` and add our route name (`user.view.identity`) under the `UserRole::ROLE_GUEST` key -This will give access to every user, including guests to view other accounts. (for the sake of simplicity) - -### Writing tests - -Because every new piece of code should be tested we will write some tests for this endpoint also. - -In the `test/Functional` folder create a new php class `IdentityTest.php`: - -```php -get('/user/'); - - $this->assertResponseNotFound($response); - } - - public function testInvalidIdentityReturnsNotFound(): void - { - $response = $this->get('/user/invalid_identity'); - $messages = json_decode($response->getBody()->getContents(), true); - - $this->assertResponseNotFound($response); - $this->assertNotEmpty($messages); - $this->assertIsArray($messages); - $this->assertNotEmpty($messages['error']['messages'][0]); - $this->assertIsString($messages['error']['messages'][0]); - $this->assertSame(Message::USER_NOT_FOUND, $messages['error']['messages'][0]); - } - - public function testValidIdentityReturnsUser(): void - { - $this->createUser([ - 'identity' => 'valid_user', - ]); - - $response = $this->get('/user/valid_user'); - - $this->assertResponseOk($response); - $user = json_decode($response->getBody()->getContents(), true); - - $this->assertSame('valid_user', $user['identity']); - } -} -``` - -Planning and coding a new feature can be challenging at times, but reviewing our existing code or tutorials can serve as a source of inspiration. +# A practical example: Find user by identity + +## Our goal + +Create a new endpoint that fetches a user record by its identity column. + +We already have an endpoint that retrieves a user based on their UUID, so we can review it and create something similar. + +## What we have + +Let's print out all available endpoints using : + +```shell +php ./bin/cli.php route:list +``` + +This command will list all available endpoints, which looks like this: + +```text ++--------+---------------------------------+--------------------------------+ +| Method | Name | Path | ++--------+---------------------------------+--------------------------------+ +| POST | account.activate.request | /account/activate | +| PATCH | account.activate | /account/activate/{hash} | +| PATCH | account.modify-password | /account/reset-password/{hash} | +............................................................................. +............................................................................. +............................................................................. +| GET | user.my-avatar.view | /user/my-avatar | +| GET | user.role.list | /user/role | +| GET | user.role.view | /user/role/{uuid} | +| PATCH | user.update | /user/{uuid} | +| GET | user.view | /user/{uuid} | ++--------+---------------------------------+--------------------------------+ +``` + +### Note + +> **The above output is just an example.** +> +> More info about listing available endpoints can be found in `../commands/display-available-endpoints.md`. + +The endpoint we're focusing on is the last one, `user.view`, so let's take a closer look at its functionality. + +If we search for the route name `user.view` we will find its definition in the `src/User/src/RoutesDelegator.php` class, where all user related endpoints are found. + +```php +$app->get('/user/' . $uuid, UserHandler::class, 'user.view'); +``` + +Our route points to `get` method from `UserHandler` so let's navigate to that method. + +```php +public function get(ServerRequestInterface $request): ResponseInterface +{ + $user = $this->userService->findOneBy(['uuid' => $request->getAttribute('uuid')]); + + return $this->createResponse($request, $user); +} +``` + +As we can see, the method will query the database for the user based on its uuid taken from the endpoint. + +We now have an understanding of how things work and we can start to implement our own endpoint. + +### Implementation + +We need to create a new handler that will process our request, we can call it `IdentityHandler`. + +Create a new PHP class called `IdentityHandler.php` in `src/User/src/Handler` folder. + +```php +getAttribute('identity'); + if (empty($identity)) { + throw (new BadRequestException())->setMessages([sprintf(Message::INVALID_VALUE, 'identity')]); + } + + $user = $this->userService->findByIdentity($identity); + if (! $user instanceof User) { + throw new NotFoundException(Message::USER_NOT_FOUND); + } + + return $this->createResponse($request, $user); + } +} +``` + +Our handler is very similar to the existing one, with some extra steps: + +* We store the identity from the request in the `$identity` variable for later use. +* If the identity is empty we throw a `BadRequestException` with an appropriate message. +* If we can't find the user in the database we throw an `NotFoundException`. +* If the record is found, we generate and return the response. + +The next step is to register the new handler. +To do this go to `src/User/src/ConfigProvider.php`. +In the `getDependencies()` method under the `factories` key add `IdentityHandler::class => AttributedServiceFactory::class,` + +Next, create the route in `src/User/src/RoutesDelegator.php`: + +```php + $app->get( + '/user/{identity}', + IdentityHandler::class, + 'user.view.identity' + ); +``` + +### Note + +> Make sure to register the endpoint as the last one to not shadow existing endpoints. + +The last step is to set permissions on the newly created route. + +Go to `config/autoload/authorization.global.php` and add our route name (`user.view.identity`) under the `UserRole::ROLE_GUEST` key This will give access to every user, including guests to view other accounts. +(for the sake of simplicity) + +### Writing tests + +Because every new piece of code should be tested we will write some tests for this endpoint also. + +In the `test/Functional` folder create a new php class `IdentityTest.php`: + +```php +get('/user/'); + + $this->assertResponseNotFound($response); + } + + public function testInvalidIdentityReturnsNotFound(): void + { + $response = $this->get('/user/invalid_identity'); + $messages = json_decode($response->getBody()->getContents(), true); + + $this->assertResponseNotFound($response); + $this->assertNotEmpty($messages); + $this->assertIsArray($messages); + $this->assertNotEmpty($messages['error']['messages'][0]); + $this->assertIsString($messages['error']['messages'][0]); + $this->assertSame(Message::USER_NOT_FOUND, $messages['error']['messages'][0]); + } + + public function testValidIdentityReturnsUser(): void + { + $this->createUser([ + 'identity' => 'valid_user', + ]); + + $response = $this->get('/user/valid_user'); + + $this->assertResponseOk($response); + $user = json_decode($response->getBody()->getContents(), true); + + $this->assertSame('valid_user', $user['identity']); + } +} +``` + +Planning and coding a new feature can be challenging at times, but reviewing our existing code or tutorials can serve as a source of inspiration. diff --git a/docs/book/v5/tutorials/token-authentication.md b/docs/book/v5/tutorials/token-authentication.md index a13d6300..0a8162f5 100644 --- a/docs/book/v5/tutorials/token-authentication.md +++ b/docs/book/v5/tutorials/token-authentication.md @@ -2,9 +2,8 @@ ## What is token authentication? -Token authentication means making a request to an API endpoint while also sending a special header that contains an -access token. The access token was previously generated by (usually) the same API as the one you are sending requests to -and it consists of an alphanumeric string. +Token authentication means making a request to an API endpoint while also sending a special header that contains an access token. +The access token was previously generated by (usually) the same API as the one you are sending requests to and it consists of an alphanumeric string. ## How does it work? diff --git a/docs/book/v5/upgrading/UPGRADE-5.3.md b/docs/book/v5/upgrading/UPGRADE-5.3.md index ddeef35a..6c3fa7c6 100644 --- a/docs/book/v5/upgrading/UPGRADE-5.3.md +++ b/docs/book/v5/upgrading/UPGRADE-5.3.md @@ -3,8 +3,8 @@ ------------------------- -Dotkernel API 5.3 is a minor release. As such, no significant backward compatibility breaks are expected, -with minor backward compatibility breaks being prefixed in this document with `[BC BREAK]`. +Dotkernel API 5.3 is a minor release. +As such, no significant backward compatibility breaks are expected, with minor backward compatibility breaks being prefixed in this document with `[BC BREAK]`. This document only covers upgrading from version 5.2. ## Table of Contents diff --git a/docs/book/v6/core-features/authentication.md b/docs/book/v6/core-features/authentication.md index 86eced9b..c16f5f01 100644 --- a/docs/book/v6/core-features/authentication.md +++ b/docs/book/v6/core-features/authentication.md @@ -1,41 +1,35 @@ # Authentication -Authentication is the process by which an identity is presented to the application. It ensures that the entity -making the request has the proper credentials to access the API. +Authentication is the process by which an identity is presented to the application. +It ensures that the entity making the request has the proper credentials to access the API. **Dotkernel API** identities are delivered to the application from the client through the `Authorization` request. -If it is present, the application tries to find and assign the identity to the application. If it is not presented, -Dotkernel API assigns a default `guest` identity, represented by an instance of the class -`Mezzio\Authentication\UserInterface`. +If it is present, the application tries to find and assign the identity to the application. +If it is not presented, Dotkernel API assigns a default `guest` identity, represented by an instance of the class `Mezzio\Authentication\UserInterface`. ## Configuration -Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already -configured out of the box. But if you want to dig more, the configuration is stored in -`config/autoload/local.php` under the `authentication` key. +Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already configured out of the box. +But if you want to dig more, the configuration is stored in `config/autoload/local.php` under the `authentication` key. -> You can check the -> [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) -> configuration part for more info. +> You can check the [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) configuration part for more info. ## How it works -Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and -simple, token-based APIs. It allows each user of your application to generate API tokens for their accounts. +Dotkernels API authentication system can be used for SPAs (single-page applications), mobile applications, and simple, token-based APIs. +It allows each user of your application to generate API tokens for their accounts. The authentication happens through the middleware in the `Api\App\Middleware\AuthenticationMiddleware`. ## Database -When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. All the tables -required for authentication are automatically created and populated. +When you install **Dotkernel API** for the first time, you need to run the migrations and seeders. +All the tables required for authentication are automatically created and populated. -In Dotkernel API, authenticated users come from either the `admin` or the `user` table. We choose to keep the admin -table separated from the users to prevent users of the application from accessing sensitive data, which only the -administrators of the application should access. +In Dotkernel API, authenticated users come from either the `admin` or the `user` table. +We choose to keep the admin table separated from the users to prevent users of the application from accessing sensitive data, which only the administrators of the application should access. -The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as -their names (**we recommend you change the default passwords**). +The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as their names (**we recommend you change the default passwords**). As you guessed each client serves to authenticate `admin` or `user`. @@ -43,8 +37,7 @@ Another table that is pre-populated is the `oauth_scopes` table, with the `api` ### Issuing API Tokens -Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows -authentication to an API using the user's credentials (generally a username and password). +Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows authentication to an API using the user's credentials (generally a username and password). The client sends a POST request to the `/security/generate-token` with the following parameters: @@ -80,8 +73,7 @@ The server responds with a JSON as follows: } ``` -Next time when you make a request to the server to an authenticated endpoint, the client should use -the `Authorization` header request. +Next time when you make a request to the server to an authenticated endpoint, the client should use the `Authorization` header request. ```shell GET /users/1 HTTP/1.1 diff --git a/docs/book/v6/core-features/authorization.md b/docs/book/v6/core-features/authorization.md index 7891a24b..77eab9e4 100644 --- a/docs/book/v6/core-features/authorization.md +++ b/docs/book/v6/core-features/authorization.md @@ -1,16 +1,13 @@ # Authorization -Authorization is the process by which a system takes a validated identity and checks if that identity has access to a -given resource. +Authorization is the process by which a system takes a validated identity and checks if that identity has access to a given resource. -**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of -Role-Based Access Control (RBAC). +**Dotkernel API**'s implementation of authorization uses `Mezzio\Authorization\Rbac\LaminasRbac` as a model of Role-Based Access Control (RBAC). ## How it works -In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define -roles for each entity. RBAC comes in to ensure that each entity has the appropriate role and permission to access a -resource. +In Dotkernel API each authenticatable entity (admin/user) comes with their roles table where you can define roles for each entity. +RBAC comes in to ensure that each entity has the appropriate role and permission to access a resource. The authorization happens through the `Api\App\Middleware\AuthorizationMiddleware` middleware. @@ -53,13 +50,11 @@ The configuration file for the role and permission definitions is `config/autolo ], ``` -> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) -> for more information. +> See [mezzio-authorization-rbac](https://docs.mezzio.dev/mezzio-authorization-rbac/v1/basic-usage/) for more information. ## Usage -Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users -roles (`user`, `guest`). +Based on the configuration file above, we have 2 admins roles (`superuser`, `admin`) and 2 users roles (`user`, `guest`). Roles inherit the permissions from their parents: @@ -68,10 +63,9 @@ Roles inherit the permissions from their parents: - `user` has no parent - `guest` has `user` as a parent which means `user` also has `guest` permissions -For each role we defined an array of permissions. A permission in Dotkernel API is basically a route name. +For each role we defined an array of permissions. +A permission in Dotkernel API is basically a route name. -As you can see, the `superuser` does not have its own permissions, because it gains all the permissions -from `admin`, no need to define explicit permissions. +As you can see, the `superuser` does not have its own permissions, because it gains all the permissions from `admin`, no need to define explicit permissions. -The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but -`guest` cannot access user-specific routes. +The `user` role, gains all the permission from `guest` so no need to define that `user` can access `home` route, but `guest` cannot access user-specific routes. diff --git a/docs/book/v6/core-features/content-validation.md b/docs/book/v6/core-features/content-validation.md index 33f7e707..8efc2193 100644 --- a/docs/book/v6/core-features/content-validation.md +++ b/docs/book/v6/core-features/content-validation.md @@ -83,8 +83,7 @@ Content-Type: application/json The server will try to validate the `Content-Type` header against your configured `Content-Type` key from the config file, and if the format is not supported, a status code `415 - Unsupported Media Type` will be returned. For example, if you have a route that needs a file to be uploaded, normally you will configure the `Content-Type` of that route to be `multipart/form-data`. -The above request will fail because the client sends `application/json` as -`Content-Type`. +The above request will fail because the client sends `application/json` as `Content-Type`. > If the request does not contain a "Content-Type" header, that means that the server will try to deserialize the data to the best of its abilities. diff --git a/docs/book/v6/core-features/error-reporting.md b/docs/book/v6/core-features/error-reporting.md index a429a08b..e06cb223 100644 --- a/docs/book/v6/core-features/error-reporting.md +++ b/docs/book/v6/core-features/error-reporting.md @@ -66,7 +66,8 @@ If both return `false`, a `ForbiddenException` is thrown and the error message d - The tokens under `ErrorReportServiceInterface::class` . `tokens` do not expire. - The log file stores the token value too, making it easy to identify which application sent the error message. -If your request passes all the checks, the message is saved in the log file specified in `ErrorReportServiceInterface::class` . `path`. +If your request passes all the checks, the message is saved in the log file specified in `ErrorReportServiceInterface::class` . +`path`. #### Tips and tricks diff --git a/docs/book/v6/extended-features/injectable-input-filters.md b/docs/book/v6/extended-features/injectable-input-filters.md index cf441b4b..bd8f44f7 100644 --- a/docs/book/v6/extended-features/injectable-input-filters.md +++ b/docs/book/v6/extended-features/injectable-input-filters.md @@ -22,7 +22,8 @@ public function handle(ServerRequestInterface $request): ResponseInterface } ``` -While simple, this ties your handler directly to a concrete class. It’s harder to reuse logic across contexts and mock or replace the filter during testing. +While simple, this ties your handler directly to a concrete class. +It’s harder to reuse logic across contexts and mock or replace the filter during testing. Our **current** approach uses constructor injection: diff --git a/docs/book/v6/extended-features/route-grouping.md b/docs/book/v6/extended-features/route-grouping.md index 0cd35b49..bd016209 100644 --- a/docs/book/v6/extended-features/route-grouping.md +++ b/docs/book/v6/extended-features/route-grouping.md @@ -1,7 +1,8 @@ # Route grouping In Dotkernel 6.0 with the help of the new [dot-router](https://docs.dotkernel.org/dot-router/v1/overview/) package, we have managed to implement a nicer way of creating routes. -A lot of the times developers need to create sets of routes that have a similar format. As an example: +A lot of the times developers need to create sets of routes that have a similar format. +As an example: ```php $app->post('/product/create', CreateProductHandler::class, 'product:create'); diff --git a/docs/book/v6/installation/composer.md b/docs/book/v6/installation/composer.md index b5f83b7d..3b92c514 100644 --- a/docs/book/v6/installation/composer.md +++ b/docs/book/v6/installation/composer.md @@ -1,6 +1,7 @@ # Composer Installation of Packages -Composer is required to install Dotkernel `api`. You can install Composer from the [official site](https://getcomposer.org/). +Composer is required to install Dotkernel `api`. +You can install Composer from the [official site](https://getcomposer.org/). > First make sure that you have navigated your command prompt to the folder where you copied the files in the previous step. @@ -47,7 +48,8 @@ Type `0` to select `[0] Do not inject`. The next question is: -`Remember this option for other packages of the same type? (y/N)` +`Remember this option for other packages of the same type? +(y/N)` Type `y` here, and hit `enter` to complete this stage. diff --git a/docs/book/v6/installation/getting-started.md b/docs/book/v6/installation/getting-started.md index 6302249f..884510c5 100644 --- a/docs/book/v6/installation/getting-started.md +++ b/docs/book/v6/installation/getting-started.md @@ -5,8 +5,9 @@ > If you are using Windows as OS on your machine, you can use WSL2 as development environment. > Read more here: [PHP-Mariadb-on-WLS2](https://www.dotkernel.com/php-development/almalinux-9-in-wsl2-install-php-apache-mariadb-composer-phpmyadmin/) -Using your terminal, navigate inside the directory you want to download the project files into. Make sure that the -directory is empty before proceeding to the download process. Once there, run the following command: +Using your terminal, navigate inside the directory you want to download the project files into. +Make sure that the directory is empty before proceeding to the download process. +Once there, run the following command: ```shell git clone https://github.com/dotkernel/api.git . diff --git a/docs/book/v6/installation/test-the-installation.md b/docs/book/v6/installation/test-the-installation.md index d819e21a..fc3a2149 100644 --- a/docs/book/v6/installation/test-the-installation.md +++ b/docs/book/v6/installation/test-the-installation.md @@ -14,8 +14,7 @@ php -S 0.0.0.0:8080 -t public ## Running tests -The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this -command: +The project has 2 types of tests: functional and unit tests, you can run both types at the same type by executing this command: ```shell php vendor/bin/phpunit diff --git a/docs/book/v6/introduction/introduction.md b/docs/book/v6/introduction/introduction.md index e32c69b0..fefba15a 100644 --- a/docs/book/v6/introduction/introduction.md +++ b/docs/book/v6/introduction/introduction.md @@ -43,7 +43,8 @@ From authorization at request route level to API keys for your application, you Registering a new module can be done by including its `ConfigProvider.php` in `config.php`. -Brand new middlewares should go into `pipeline.php`. Here you can edit the order in which they run and find more info about the currently included ones. +Brand new middlewares should go into `pipeline.php`. +Here you can edit the order in which they run and find more info about the currently included ones. You can further customize your api within the `autoload` directory that holds configuration files for each category. diff --git a/docs/book/v6/openapi/generate-documentation.md b/docs/book/v6/openapi/generate-documentation.md index 15d492ee..163f3bdd 100644 --- a/docs/book/v6/openapi/generate-documentation.md +++ b/docs/book/v6/openapi/generate-documentation.md @@ -1,12 +1,10 @@ # Generating the documentation file -> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of -> your instance of **Dotkernel API**. +> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of your instance of **Dotkernel API**. Using your terminal, move to the root directory of your project. -Dotkernel API stores the OpenAPI attributes in the `src` directory, so that's the path we will use for generating the -static documentation file. +Dotkernel API stores the OpenAPI attributes in the `src` directory, so that's the path we will use for generating the static documentation file. ## Methods of generating documentation file diff --git a/docs/book/v6/openapi/getting-help.md b/docs/book/v6/openapi/getting-help.md index be76626d..e53d6b28 100644 --- a/docs/book/v6/openapi/getting-help.md +++ b/docs/book/v6/openapi/getting-help.md @@ -5,8 +5,7 @@ reference of the presented objects - see more examples of OpenAPI object representations in `zircote/swagger-php`'s [GitHub repository](https://zircote.github.io/swagger-php/guide/examples.html) - consult `zircote/swagger-php`'s -[online documentation](http://zircote.github.io/swagger-php/guide/generating-openapi-documents.html) or run the -following command to see their help page: +[online documentation](http://zircote.github.io/swagger-php/guide/generating-openapi-documents.html) or run the following command to see their help page: ```shell ./vendor/bin/openapi --help diff --git a/docs/book/v6/openapi/initialized-components.md b/docs/book/v6/openapi/initialized-components.md index af131e11..84fc9987 100644 --- a/docs/book/v6/openapi/initialized-components.md +++ b/docs/book/v6/openapi/initialized-components.md @@ -198,9 +198,8 @@ Schema: )] ``` -Using `ref: '#/components/schemas/UserRole',` in our code, we instruct `OpenAPI` to grab the existing schema `UserRole` -(not the entity, but the schema) that we just described earlier. This way we do not need to repeat code by describing -again the same object and any future modifications will happen in only one place. +Using `ref: '#/components/schemas/UserRole',` in our code, we instruct `OpenAPI` to grab the existing schema `UserRole` (not the entity, but the schema) that we just described earlier. +This way we do not need to repeat code by describing again the same object and any future modifications will happen in only one place. Then, when generating the documentation file, `OpenAPI` will transform it into the specified format (**json**/**yaml**). @@ -221,8 +220,7 @@ UserRoleCollection: type: object ``` -> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of -> your instance of **Dotkernel API**. +> Make sure that in `src/App/src/OpenAPI.php`, on the line with `#[OA\Server` the value of `url` is set to the of URL of your instance of **Dotkernel API**. > > You can add multiple servers (for staging, production etc) by duplicating the existing one. @@ -230,7 +228,8 @@ For more info, see [this page](https://spec.openapis.org/oas/latest.html#schema) ### Common schemas -We provided some schemas that are reusable across the entire project. They are defined in `src/App/src/OpenAPI.php`: +We provided some schemas that are reusable across the entire project. +They are defined in `src/App/src/OpenAPI.php`: - `#/components/schemas/Collection`: provides the default **HAL** structure to all the collections extending it - `#/components/schemas/ErrorMessage`: describes an operation that resulted in an error - may contain multiple messages diff --git a/docs/book/v6/openapi/introduction.md b/docs/book/v6/openapi/introduction.md index 0d91faf2..04939612 100644 --- a/docs/book/v6/openapi/introduction.md +++ b/docs/book/v6/openapi/introduction.md @@ -1,8 +1,5 @@ # OpenAPI documentation -In order to provide an interactive documentation, Dotkernel API implemented -[zircote/swagger-php](https://github.com/zircote/swagger-php). +In order to provide an interactive documentation, Dotkernel API implemented [zircote/swagger-php](https://github.com/zircote/swagger-php). -Using this library, developers are able to automatically generate documentation files that later can be used to provide -a comprehensive overview of the available endpoints, all the details on the requests that it can receive and the -responses these can return. +Using this library, developers are able to automatically generate documentation files that later can be used to provide a comprehensive overview of the available endpoints, all the details on the requests that it can receive and the responses these can return. diff --git a/docs/book/v6/openapi/render-documentation.md b/docs/book/v6/openapi/render-documentation.md index c151d266..602f00be 100644 --- a/docs/book/v6/openapi/render-documentation.md +++ b/docs/book/v6/openapi/render-documentation.md @@ -1,7 +1,7 @@ # Rendering the documentation file -At this step, you only have a static documentation file. You will need an interface that can render it so that you will -be able to interact with your Dotkernel API. +At this step, you only have a static documentation file. +You will need an interface that can render it so that you will be able to interact with your Dotkernel API. In order to do this, we recommend using either of: @@ -10,8 +10,7 @@ In order to do this, we recommend using either of: ## Using Swagger UI -Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `swagger.html`, -the name is up to you) and place the following HTML content in it: +Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `swagger.html`, the name is up to you) and place the following HTML content in it: ```html @@ -35,21 +34,20 @@ the name is up to you) and place the following HTML content in it: ``` -Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file -(openapi.json/openapi.yaml). The line should look similar to this: +Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file (openapi.json/openapi.yaml). +The line should look similar to this: ```js window.ui = SwaggerUIBundle({url: './openapi.yaml', dom_id: '#swagger-ui'}); ``` -Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/swagger.html` to -it. You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each -endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). +Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/swagger.html` to it. +You should see the Redoc interface with your documentation file loaded in it. +From here, you can inspect each endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). ## Using Redoc -Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `redoc.html`, -the name is up to you) and place the following HTML content in it: +Navigate to the `public` directory of your instance of Dotkernel API and create an HTML (you can call it `redoc.html`, the name is up to you) and place the following HTML content in it: ```html @@ -70,13 +68,13 @@ the name is up to you) and place the following HTML content in it: ``` -Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file -(openapi.json/openapi.yaml). The line should look similar to this: +Make sure that you replace `PATH_TO_YOUR_OPENAPI_FILE` with the relative path to your documentation file (openapi.json/openapi.yaml). +The line should look similar to this: ```js Redoc.init('./openapi.yaml', {}, document.getElementById('redoc-container')); ``` Using your browser, open a new tab and type in the URL of your instance of Dotkernel API and append `/redoc.html` to it. -You should see the Redoc interface with your documentation file loaded in it. From here, you can inspect each endpoint, -see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). +You should see the Redoc interface with your documentation file loaded in it. +From here, you can inspect each endpoint, see it's URL, check if it needs authentication, the request payload (if any) and the possible response(s). diff --git a/docs/book/v6/openapi/use-documentation.md b/docs/book/v6/openapi/use-documentation.md index fe0330df..def28a98 100644 --- a/docs/book/v6/openapi/use-documentation.md +++ b/docs/book/v6/openapi/use-documentation.md @@ -4,23 +4,26 @@ Since Redoc is readonly, in the following section we will focus only on using Sw ## Protected endpoints -Now that you have a UI for the documentation, you can see all the endpoints. You will see that some of them have a lock -symbol right before the collapse/expand arrow. When you see this symbol next to an endpoint, it means that the endpoint -is protected and can only be accessed when authenticated with an account with proper permissions. +Now that you have a UI for the documentation, you can see all the endpoints. +You will see that some of them have a lock symbol right before the collapse/expand arrow. +When you see this symbol next to an endpoint, it means that the endpoint is protected and can only be accessed when authenticated with an account with proper permissions. ## Authentication -In Swagger UI, you will see an `Authorize` button. Clicking it will open a modal where you will find two sections: +In Swagger UI, you will see an `Authorize` button. +Clicking it will open a modal where you will find two sections: - `AuthToken` - where you will have to enter a valid auth token - `ErrorReportingToken` - where you will have to enter a valid error reporting token -Below, we will walk you through on how to find both tokens. For now, let's close the modal. +Below, we will walk you through on how to find both tokens. +For now, let's close the modal. ### Generating AuthToken -This token is required with most of the Dotkernel API endpoints. There are two entities that generate this type of -token: `(super)admin`s and `user`s. Depending on the endpoint description, you will know which one you need to use. +This token is required with most of the Dotkernel API endpoints. +There are two entities that generate this type of token: `(super)admin`s and `user`s. +Depending on the endpoint description, you will know which one you need to use. Examples: - `/user`: the description says `Admin lists user accounts` - it means that you need an AccessToken with `(super)admin` @@ -28,13 +31,14 @@ Examples: - `/user/my-account`: the description says `User fetches their own account` - it means that you need an AccessToken with `user` privileges -In the UI, find a section called `AccessToken`, toggle the `/security/generate-token` (`Generate access token`) endpoint -and click the `Try it out` button. Under the `Access token generation request` you will find a textarea prepopulated -with a JSON object. You will have to change the value of `username` and `password`. See -[this guide](../tutorials/token-authentication.md#credentials) for the credentials. +In the UI, find a section called `AccessToken`, toggle the `/security/generate-token` (`Generate access token`) endpoint and click the `Try it out` button. +Under the `Access token generation request` you will find a textarea prepopulated with a JSON object. +You will have to change the value of `username` and `password`. +See [this guide](../tutorials/token-authentication.md#credentials) for the credentials. -After you have filled out the credentials, click on the `Execute` button below the textarea. This will send the request -to your instance of Dotkernel API. If everything went well, under the textarea you should see: +After you have filled out the credentials, click on the `Execute` button below the textarea. +This will send the request to your instance of Dotkernel API. +If everything went well, under the textarea you should see: - the `curl` request that was made - the `Request URL` the request was sent to @@ -43,31 +47,29 @@ to your instance of Dotkernel API. If everything went well, under the textarea y > Save the `refresh_token` somewhere, you will need it later -Now copy the value of `access_token` (make sure you copy all the characters, without the surrounding double quotes) and -go back up to the `Authorize` button and click it to open the auth modal. Paste the copied token as the value of the -`AuthToken` and click on the **Authorize** button you see under the input field. The **Authorize** button has now -changed to **Logout**. You can close the modal. +Now copy the value of `access_token` (make sure you copy all the characters, without the surrounding double quotes) and go back up to the `Authorize` button and click it to open the auth modal. +Paste the copied token as the value of the `AuthToken` and click on the **Authorize** button you see under the input field. +The **Authorize** button has now changed to **Logout**. +You can close the modal. -From here, Swagger UI will remember the AuthToken until you close/refresh the browser tab. Also, it will automatically -append the `Authorization` header to each request, allowing you to make authorized API calls. +From here, Swagger UI will remember the AuthToken until you close/refresh the browser tab. +Also, it will automatically append the `Authorization` header to each request, allowing you to make authorized API calls. -If you need to switch to an account with different privileges, you go again to the `Authorize` button, click on it to -open the auth modal, and click **Logout** for the `AuthToken`. Then paste the new token as the value of the `AuthToken`, -click on the **Authorize** button, close the modal and continue using the UI authenticated with the new account. +If you need to switch to an account with different privileges, you go again to the `Authorize` button, click on it to open the auth modal, and click **Logout** for the `AuthToken`. +Then paste the new token as the value of the `AuthToken`, click on the **Authorize** button, close the modal and continue using the UI authenticated with the new account. ### Refreshing AuthToken -By default, auth tokens expire in 1 day. If you make an API call, and you receive an error telling you that your auth -token is expired, you need to either generate a new token (as seen above) or refresh the existing one using the -`refresh_token` received when generating the current token. +By default, auth tokens expire in 1 day. +If you make an API call, and you receive an error telling you that your auth token is expired, you need to either generate a new token (as seen above) or refresh the existing one using the `refresh_token` received when generating the current token. -In order to refresh the auth token, you find the same section called `AccessToken`, toggle the `/security/refresh-token` -(`Refresh access token`) endpoint and click the `Try it out` button. Under the `Access token refresh request` you will -find a textarea prepopulated with a JSON object. You will have to change the value of `refresh_token` to the refresh -token of your current auth token. +In order to refresh the auth token, you find the same section called `AccessToken`, toggle the `/security/refresh-token` (`Refresh access token`) endpoint and click the `Try it out` button. +Under the `Access token refresh request` you will find a textarea prepopulated with a JSON object. +You will have to change the value of `refresh_token` to the refresh token of your current auth token. -Once done, click on the `Execute` button below the textarea. This will send the request to your instance of Dotkernel -API. If everything went well, under the textarea you should see the same details: +Once done, click on the `Execute` button below the textarea. +This will send the request to your instance of Dotkernel API. +If everything went well, under the textarea you should see the same details: - the `curl` request that was made - the `Request URL` the request was sent to @@ -83,23 +85,23 @@ From here, you will follow the same steps: ### Generating ErrorReportingToken -Just like the AuthTokens, ErrorReportingTokens are used to make authorized API calls. The difference is that this token -applies only to one specific endpoint: `/error-report` (`Report an error to the API`). This endpoint is intended to be -used by third-party applications and frontends to report an error back to the API. +Just like the AuthTokens, ErrorReportingTokens are used to make authorized API calls. +The difference is that this token applies only to one specific endpoint: `/error-report` (`Report an error to the API`). +This endpoint is intended to be used by third-party applications and frontends to report an error back to the API. > This endpoint does not require `AuthTokens` In order to generate this token, follow [this guide](../commands/generate-tokens.md#generate-error-reporting-token). -Once you have the error reporting token, go again to the `Authorize` button, paste the new token as the value of the -`ErrorReportingToken`, click on the **Authorize** button and close the modal. Now you're ready to report errors to your -instance of Dotkernel API. +Once you have the error reporting token, go again to the `Authorize` button, paste the new token as the value of the `ErrorReportingToken`, click on the **Authorize** button and close the modal. +Now you're ready to report errors to your instance of Dotkernel API. ## Making API calls > The UI does not use confirmation messages before making an API call so double check any operation before executing it. -Once authorized in the UI, you can click on any endpoint to expand it. There you will find an overview of the endpoint, including: +Once authorized in the UI, you can click on any endpoint to expand it. +There you will find an overview of the endpoint, including: - Request method (`DELETE`, `GET`, `PATCH`, `POST`, `PUT`) - request URL (example: `/resource`) @@ -113,10 +115,10 @@ all the required parameters Clicking the `Try it out` button will activate any parameter input fields and the request body textarea (if any). Clicking `Cancel` will deactivate them. -Make sure you fill out all the necessary data, then click on the `Execute` found button above `Responses`. This will -send the request and return and display the API response. Once finished, you will see the response as the first item -under `Responses`, including the HTTP status code and the response body. +Make sure you fill out all the necessary data, then click on the `Execute` found button above `Responses`. +This will send the request and return and display the API response. +Once finished, you will see the response as the first item under `Responses`, including the HTTP status code and the response body. -You can repeat the request by clicking again on the `Execute` button. This will first clear the previous output and -display the new response in the same place. Additionally, between two executions, you can manually clear any previous -output using the `Clear` button next to the `Execute` button. +You can repeat the request by clicking again on the `Execute` button. +This will first clear the previous output and display the new response in the same place. +Additionally, between two executions, you can manually clear any previous output using the `Clear` button next to the `Execute` button. diff --git a/docs/book/v6/openapi/write-documentation.md b/docs/book/v6/openapi/write-documentation.md index 9247ce54..1a9cb42d 100644 --- a/docs/book/v6/openapi/write-documentation.md +++ b/docs/book/v6/openapi/write-documentation.md @@ -1,12 +1,10 @@ # Writing documentation -> In order to avoid polluting PHP files with maybe thousands of lines of OpenAPI attributes, we opted for storing them -> in separate files, called `OpenAPI.php`, one for each module. +> In order to avoid polluting PHP files with maybe thousands of lines of OpenAPI attributes, we opted for storing them in separate files, called `OpenAPI.php`, one for each module. -We already covered all the endpoints available in Dotkernel API, you can consult the existing documentation in each -module's own `OpenAPI.php` file. After you add more functionalities to your API, you will have to document the new -endpoints. This is easier than it sounds because in most cases you will do the same: add a request by method, describe -the request payload (if any), add request parameters (if any) and describe the possible responses. +We already covered all the endpoints available in Dotkernel API, you can consult the existing documentation in each module's own `OpenAPI.php` file. +After you add more functionalities to your API, you will have to document the new endpoints. +This is easier than it sounds because in most cases you will do the same: add a request by method, describe the request payload (if any), add request parameters (if any) and describe the possible responses. ## Common objects @@ -33,7 +31,8 @@ If you need help, take a look at the existing definitions found in Dotkernel API ### OA\Delete -Defines a `DELETE` HTTP request. It should specify at least the following parameters: +Defines a `DELETE` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -46,7 +45,8 @@ respective response bodies ### OA\Get -Defines a `GET` HTTP request. It should specify at least the following parameters: +Defines a `GET` HTTP request. +It should specify at least the following parameters: - `path`: the route to a single or collection of resources (example: `/resource/{uuid}` for a single resource or `/resource` for a collection of resources) @@ -60,7 +60,8 @@ respective response bodies ### OA\Patch -Defines a `PATCH` HTTP request. It should specify at least the following parameters: +Defines a `PATCH` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -74,7 +75,8 @@ respective response bodies ### OA\Post -Defines a `POST` HTTP request. It should specify at least the following parameters: +Defines a `POST` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose @@ -88,7 +90,8 @@ respective response bodies ### OA\Put -Defines a `PUT` HTTP request. It should specify at least the following parameters: +Defines a `PUT` HTTP request. +It should specify at least the following parameters: - `path`: the route to the resource (example: `/resource/{uuid}` - where `uuid` is a path parameter defined below) - `description`: verbose description of the endpoint's purpose diff --git a/docs/book/v6/security/basic-security.md b/docs/book/v6/security/basic-security.md index 965872e1..80ca21da 100644 --- a/docs/book/v6/security/basic-security.md +++ b/docs/book/v6/security/basic-security.md @@ -34,8 +34,7 @@ Update the configuration file of this package (`config/autoload/authorization.gl ## Demo Credentials -Dotkernel API ships with two demo accounts: an admin account (`admin`) and a user account (`test@dotkernel.com`), -with public identities and passwords as described in the [token authentication tutorial](https://docs.dotkernel.org/api-documentation/v6/tutorials/token-authentication/). +Dotkernel API ships with two demo accounts: an admin account (`admin`) and a user account (`test@dotkernel.com`), with public identities and passwords as described in the [token authentication tutorial](https://docs.dotkernel.org/api-documentation/v6/tutorials/token-authentication/). Make sure to **update** or **remove** these demo accounts in your production environment. diff --git a/docs/book/v6/security/oauth2-security.md b/docs/book/v6/security/oauth2-security.md index 0d4c3a63..f4c885a0 100644 --- a/docs/book/v6/security/oauth2-security.md +++ b/docs/book/v6/security/oauth2-security.md @@ -7,8 +7,7 @@ As a security stating point, when developing an application using this project m The project ships with the default OAuth clients `admin` and `frontend` with passwords equal to their names, as described in the [Authentication](https://docs.dotkernel.org/api-documentation/v6/core-features/authentication/) guide. -These clients **must not** remain unchanged in your production environment, as they are a security risk - -ensure you deleted them or updated the passwords. +These clients **must not** remain unchanged in your production environment, as they are a security risk - ensure you deleted them or updated the passwords. ## OAuth Token Lifetime and Refresh Hygiene @@ -23,8 +22,7 @@ Make sure to adjust their values in accordance to your application's needs, with ## Autogeneration of Cryptographic Keys -Dotkernel API makes use of the `./vendor/bin/generate-oauth2-keys` command from `mezzio-authentication-oauth2` to automatically regenerate the -public/private key pair used to verify the transmitted JWTs. +Dotkernel API makes use of the `./vendor/bin/generate-oauth2-keys` command from `mezzio-authentication-oauth2` to automatically regenerate the public/private key pair used to verify the transmitted JWTs. This process is done after each `composer update` (or `composer install` with no lock file), as specified in `composer.json` under the `scripts.post-update-cmd` key. While hidden to the VCS by default, keep in mind not to commit any local keys. diff --git a/docs/book/v6/tutorials/cors.md b/docs/book/v6/tutorials/cors.md index dd5264d1..d2e2557b 100644 --- a/docs/book/v6/tutorials/cors.md +++ b/docs/book/v6/tutorials/cors.md @@ -2,15 +2,13 @@ ## What is CORS? -**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other -origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. +**Cross-Origin Resource Sharing** or _CORS_ is an HTTP-header based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. ## Why do we need CORS? When integrating an API, most developers have encountered the following error message: -> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: -> No ‘Access-Control-Allow-Origin’ header is present on the requested resource. +> Access to fetch at _RESOURCE_URL_ from origin _ORIGIN_URL_ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. This happens because the API (_RESOURCE_URL_) is not configured to accept requests from the client (_ORIGIN_URL_). @@ -86,7 +84,6 @@ This list explains the above configuration values: Save and close the file. -> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` -> array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. +> On the **production** environment, make sure you allow only specific origins by adding them to the `allowed_origins` array and removing the current value of `ConfigurationInterface::ANY_ORIGIN`. For more info, see [mezzio/mezzio-cors documentation](https://docs.mezzio.dev/mezzio-cors/v1/middleware/#configuration). diff --git a/docs/book/v6/tutorials/create-book-module-via-dot-maker.md b/docs/book/v6/tutorials/create-book-module-via-dot-maker.md index d6b37868..cfc80a28 100644 --- a/docs/book/v6/tutorials/create-book-module-via-dot-maker.md +++ b/docs/book/v6/tutorials/create-book-module-via-dot-maker.md @@ -5,8 +5,7 @@ It can be added to your API installation by following the [official documentatio ## Folder and files structure -The below files structure is what we will have at the end of this tutorial and is just an example, -you can have multiple components such as event listeners, wrappers, etc. +The below files structure is what we will have at the end of this tutorial and is just an example, you can have multiple components such as event listeners, wrappers, etc. ```markdown . @@ -425,7 +424,11 @@ To list the books use: curl http://0.0.0.0:8080/book ``` -To fetch a book, `curl` one of the links found in the output of the **list books** command, under `_embedded` . `books` . * . `_links` . `self` . `href`. +To fetch a book, `curl` one of the links found in the output of the **list books** command, under `_embedded` . +`books` . * . +`_links` . +`self` . +`href`. The link should have the following format: diff --git a/docs/book/v6/tutorials/create-book-module.md b/docs/book/v6/tutorials/create-book-module.md index 8bd46704..c5972297 100644 --- a/docs/book/v6/tutorials/create-book-module.md +++ b/docs/book/v6/tutorials/create-book-module.md @@ -768,7 +768,8 @@ class ConfigProvider composer dump-autoload ``` -That's it. The module is now registered. +That's it. +The module is now registered. We need to configure access to the newly created endpoints. Open `config/autoload/authorization.global.php` and append the below route names to the `UserRoleEnum::Guest->value` key: @@ -825,7 +826,11 @@ To list the books use: curl http://0.0.0.0:8080/book ``` -To fetch a book, `curl` one of the links found in the output of the **list books** command, under `_embedded` . `books` . * . `_links` . `self` . `href`. +To fetch a book, `curl` one of the links found in the output of the **list books** command, under `_embedded` . +`books` . * . +`_links` . +`self` . +`href`. The link should have the following format: diff --git a/docs/book/v6/tutorials/find-user-by-identity.md b/docs/book/v6/tutorials/find-user-by-identity.md index 681a4eba..1f3dca54 100644 --- a/docs/book/v6/tutorials/find-user-by-identity.md +++ b/docs/book/v6/tutorials/find-user-by-identity.md @@ -1,212 +1,212 @@ -# A practical example: Find user by identity - -## Our goal - -Create a new endpoint that fetches a user record by its identity column. - -We already have an endpoint that retrieves a user based on their UUID, so we can review it and create something similar. - -## What we have - -Let's print out all available endpoints using : - -```shell -php ./bin/cli.php route:list -``` - -This command will list all available endpoints, which looks like this: - -```text -+--------+---------------------------------+--------------------------------+ -| Method | Name | Path | -+--------+---------------------------------+--------------------------------+ -| POST | account.activate.request | /account/activate | -| PATCH | account.activate | /account/activate/{hash} | -| PATCH | account.modify-password | /account/reset-password/{hash} | -............................................................................. -............................................................................. -............................................................................. -| GET | user.my-avatar.view | /user/my-avatar | -| GET | user.role.list | /user/role | -| GET | user.role.view | /user/role/{uuid} | -| PATCH | user.update | /user/{uuid} | -| GET | user.view | /user/{uuid} | -+--------+---------------------------------+--------------------------------+ -``` - -### Note - -> **The above output is just an example.** -> -> More info about listing available endpoints can be found in `../commands/display-available-endpoints.md`. - -The endpoint we're focusing on is the last one, `user.view`, so let's take a closer look at its functionality. - -If we search for the route name `user.view` we will find its definition in the `src/User/src/RoutesDelegator.php` class, where all user related endpoints are found. - -```php -$app->get('/user/' . $uuid, UserHandler::class, 'user.view'); -``` - -Our route points to `get` method from `UserHandler` so let's navigate to that method. - -```php -public function get(ServerRequestInterface $request): ResponseInterface -{ - $user = $this->userService->findOneBy(['uuid' => $request->getAttribute('uuid')]); - - return $this->createResponse($request, $user); -} -``` - -As we can see, the method will query the database for the user based on its uuid taken from the endpoint. - -We now have an understanding of how things work and we can start to implement our own endpoint. - -### Implementation - -We need to create a new handler that will process our request, we can call it `IdentityHandler`. - -Create a new PHP class called `IdentityHandler.php` in `src/User/src/Handler` folder. - -```php -getAttribute('identity'); - if (empty($identity)) { - throw (new BadRequestException())->setMessages([sprintf(Message::INVALID_VALUE, 'identity')]); - } - - $user = $this->userService->findByIdentity($identity); - if (! $user instanceof User) { - throw new NotFoundException(Message::USER_NOT_FOUND); - } - - return $this->createResponse($request, $user); - } -} -``` - -Our handler is very similar to the existing one, with some extra steps: - -* We store the identity from the request in the `$identity` variable for later use. -* If the identity is empty we throw a `BadRequestException` with an appropriate message. -* If we can't find the user in the database we throw an `NotFoundException`. -* If the record is found, we generate and return the response. - -The next step is to register the new handler. -To do this go to `src/User/src/ConfigProvider.php`. -In the `getDependencies()` method under the `factories` key add `IdentityHandler::class => AttributedServiceFactory::class,` - -Next, create the route in `src/User/src/RoutesDelegator.php`: - -```php - $app->get( - '/user/{identity}', - IdentityHandler::class, - 'user.view.identity' - ); -``` - -### Note - -> Make sure to register the endpoint as the last one to not shadow existing endpoints. - -The last step is to set permissions on the newly created route. - -Go to `config/autoload/authorization.global.php` and add our route name (`user.view.identity`) under the `UserRole::ROLE_GUEST` key -This will give access to every user, including guests to view other accounts. (for the sake of simplicity) - -### Writing tests - -Because every new piece of code should be tested we will write some tests for this endpoint also. - -In the `test/Functional` folder create a new php class `IdentityTest.php`: - -```php -get('/user/'); - - $this->assertResponseNotFound($response); - } - - public function testInvalidIdentityReturnsNotFound(): void - { - $response = $this->get('/user/invalid_identity'); - $messages = json_decode($response->getBody()->getContents(), true); - - $this->assertResponseNotFound($response); - $this->assertNotEmpty($messages); - $this->assertIsArray($messages); - $this->assertNotEmpty($messages['error']['messages'][0]); - $this->assertIsString($messages['error']['messages'][0]); - $this->assertSame(Message::USER_NOT_FOUND, $messages['error']['messages'][0]); - } - - public function testValidIdentityReturnsUser(): void - { - $this->createUser([ - 'identity' => 'valid_user', - ]); - - $response = $this->get('/user/valid_user'); - - $this->assertResponseOk($response); - $user = json_decode($response->getBody()->getContents(), true); - - $this->assertSame('valid_user', $user['identity']); - } -} -``` - -Planning and coding a new feature can be challenging at times, but reviewing our existing code or tutorials can serve as a source of inspiration. +# A practical example: Find user by identity + +## Our goal + +Create a new endpoint that fetches a user record by its identity column. + +We already have an endpoint that retrieves a user based on their UUID, so we can review it and create something similar. + +## What we have + +Let's print out all available endpoints using : + +```shell +php ./bin/cli.php route:list +``` + +This command will list all available endpoints, which looks like this: + +```text ++--------+---------------------------------+--------------------------------+ +| Method | Name | Path | ++--------+---------------------------------+--------------------------------+ +| POST | account.activate.request | /account/activate | +| PATCH | account.activate | /account/activate/{hash} | +| PATCH | account.modify-password | /account/reset-password/{hash} | +............................................................................. +............................................................................. +............................................................................. +| GET | user.my-avatar.view | /user/my-avatar | +| GET | user.role.list | /user/role | +| GET | user.role.view | /user/role/{uuid} | +| PATCH | user.update | /user/{uuid} | +| GET | user.view | /user/{uuid} | ++--------+---------------------------------+--------------------------------+ +``` + +### Note + +> **The above output is just an example.** +> +> More info about listing available endpoints can be found in `../commands/display-available-endpoints.md`. + +The endpoint we're focusing on is the last one, `user.view`, so let's take a closer look at its functionality. + +If we search for the route name `user.view` we will find its definition in the `src/User/src/RoutesDelegator.php` class, where all user related endpoints are found. + +```php +$app->get('/user/' . $uuid, UserHandler::class, 'user.view'); +``` + +Our route points to `get` method from `UserHandler` so let's navigate to that method. + +```php +public function get(ServerRequestInterface $request): ResponseInterface +{ + $user = $this->userService->findOneBy(['uuid' => $request->getAttribute('uuid')]); + + return $this->createResponse($request, $user); +} +``` + +As we can see, the method will query the database for the user based on its uuid taken from the endpoint. + +We now have an understanding of how things work and we can start to implement our own endpoint. + +### Implementation + +We need to create a new handler that will process our request, we can call it `IdentityHandler`. + +Create a new PHP class called `IdentityHandler.php` in `src/User/src/Handler` folder. + +```php +getAttribute('identity'); + if (empty($identity)) { + throw (new BadRequestException())->setMessages([sprintf(Message::INVALID_VALUE, 'identity')]); + } + + $user = $this->userService->findByIdentity($identity); + if (! $user instanceof User) { + throw new NotFoundException(Message::USER_NOT_FOUND); + } + + return $this->createResponse($request, $user); + } +} +``` + +Our handler is very similar to the existing one, with some extra steps: + +* We store the identity from the request in the `$identity` variable for later use. +* If the identity is empty we throw a `BadRequestException` with an appropriate message. +* If we can't find the user in the database we throw an `NotFoundException`. +* If the record is found, we generate and return the response. + +The next step is to register the new handler. +To do this go to `src/User/src/ConfigProvider.php`. +In the `getDependencies()` method under the `factories` key add `IdentityHandler::class => AttributedServiceFactory::class,` + +Next, create the route in `src/User/src/RoutesDelegator.php`: + +```php + $app->get( + '/user/{identity}', + IdentityHandler::class, + 'user.view.identity' + ); +``` + +### Note + +> Make sure to register the endpoint as the last one to not shadow existing endpoints. + +The last step is to set permissions on the newly created route. + +Go to `config/autoload/authorization.global.php` and add our route name (`user.view.identity`) under the `UserRole::ROLE_GUEST` key This will give access to every user, including guests to view other accounts. +(for the sake of simplicity) + +### Writing tests + +Because every new piece of code should be tested we will write some tests for this endpoint also. + +In the `test/Functional` folder create a new php class `IdentityTest.php`: + +```php +get('/user/'); + + $this->assertResponseNotFound($response); + } + + public function testInvalidIdentityReturnsNotFound(): void + { + $response = $this->get('/user/invalid_identity'); + $messages = json_decode($response->getBody()->getContents(), true); + + $this->assertResponseNotFound($response); + $this->assertNotEmpty($messages); + $this->assertIsArray($messages); + $this->assertNotEmpty($messages['error']['messages'][0]); + $this->assertIsString($messages['error']['messages'][0]); + $this->assertSame(Message::USER_NOT_FOUND, $messages['error']['messages'][0]); + } + + public function testValidIdentityReturnsUser(): void + { + $this->createUser([ + 'identity' => 'valid_user', + ]); + + $response = $this->get('/user/valid_user'); + + $this->assertResponseOk($response); + $user = json_decode($response->getBody()->getContents(), true); + + $this->assertSame('valid_user', $user['identity']); + } +} +``` + +Planning and coding a new feature can be challenging at times, but reviewing our existing code or tutorials can serve as a source of inspiration. diff --git a/docs/book/v6/tutorials/token-authentication.md b/docs/book/v6/tutorials/token-authentication.md index c58021f7..61544da0 100644 --- a/docs/book/v6/tutorials/token-authentication.md +++ b/docs/book/v6/tutorials/token-authentication.md @@ -2,9 +2,8 @@ ## What is token authentication? -Token authentication means making a request to an API endpoint while also sending a special header that contains an -access token. The access token was previously generated by (usually) the same API as the one you are sending requests to -and it consists of an alphanumeric string. +Token authentication means making a request to an API endpoint while also sending a special header that contains an access token. +The access token was previously generated by (usually) the same API as the one you are sending requests to and it consists of an alphanumeric string. ## How does it work?