diff --git a/docs/book/v5/core-features/content-validation.md b/docs/book/v5/core-features/content-validation.md index ec01f34..5107052 100644 --- a/docs/book/v5/core-features/content-validation.md +++ b/docs/book/v5/core-features/content-validation.md @@ -1,5 +1,7 @@ # Content Negotiation +> Introduced in Dotkernel API 5.0.0 + **Content Negotiation** is performed by an application in order : - To match the requested representation as specified by the client via the Accept header with a representation the diff --git a/docs/book/v5/core-features/dependency-injection.md b/docs/book/v5/core-features/dependency-injection.md index 0ef7a19..4744dab 100644 --- a/docs/book/v5/core-features/dependency-injection.md +++ b/docs/book/v5/core-features/dependency-injection.md @@ -1,22 +1,20 @@ # Dependency Injection -Dependency injection is a design pattern used in software development to implement inversion of control. In simpler -terms, it's the act of providing dependencies for an object during instantiation. +Dependency injection is a design pattern used in software development to implement inversion of control. +In simpler terms, it's the act of providing dependencies for an object during instantiation. -In PHP, dependency injection can be implemented in various ways, including through constructor injection, setter -injection and property injection. +In PHP, dependency injection can be implemented in various ways, including through constructor injection, setter injection and property injection. -Dotkernel API, through its [dot-dependency-injection](https://github.com/dotkernel/dot-dependency-injection) package -focuses only on constructor injection. +> Introduced in Dotkernel API 5.0.0 + +Dotkernel API, through its [dot-dependency-injection](https://github.com/dotkernel/dot-dependency-injection) package focuses only on constructor injection. ## Usage -**Dotkernel API** comes out of the box with the -[dot-dependency-injection](https://github.com/dotkernel/dot-dependency-injection) package, which provides all we need for -injecting dependencies into any object you want. +**Dotkernel API** comes out of the box with the [dot-dependency-injection](https://github.com/dotkernel/dot-dependency-injection) package, which provides all we need for injecting dependencies into any object you want. -`dot-dependency-injection` determines the dependencies by looking at the `#[Inject]` attribute, added to the constructor -of a class. Dependencies are specified as separate parameters of the `#[Inject]` attribute. +`dot-dependency-injection` determines the dependencies by looking at the `#[Inject]` attribute, added to the constructor of a class. +Dependencies are specified as separate parameters of the `#[Inject]` attribute. For our example we will inject `UserService` and `config` dependencies into a `UseHandler`. @@ -37,11 +35,9 @@ class UserHandler implements RequestHandlerInterface } ``` -> If your class needs the value of a specific configuration key, you can specify the path using dot notation: -> `config.example` +> If your class needs the value of a specific configuration key, you can specify the path using dot notation `config.example`. -The next step is to register the class in the `ConfigProvider` under `factories` using -`Dot\DependencyInjection\Factory\AttributedServiceFactory::class` +The next step is to register the class in the `ConfigProvider` under `factories` using `Dot\DependencyInjection\Factory\AttributedServiceFactory::class` ```php public function getDependencies(): array @@ -54,8 +50,8 @@ public function getDependencies(): array } ``` -That's it. When your object is instantiated from the container, it will automatically have its -dependencies resolved. +That's it. +When your object is instantiated from the container, it will automatically have its dependencies resolved. -> Dependencies injection is available to any object within Dotkernel API. For example, you can inject dependencies in a -> service, a handler and so on, simply by registering it in the `ConfigProvider`. +> Dependencies injection is available to any object within Dotkernel API. +> For example, you can inject dependencies in a service, a handler and so on, simply by registering it in the `ConfigProvider`. diff --git a/docs/book/v5/core-features/exceptions.md b/docs/book/v5/core-features/exceptions.md index 764287f..43d605d 100644 --- a/docs/book/v5/core-features/exceptions.md +++ b/docs/book/v5/core-features/exceptions.md @@ -2,61 +2,50 @@ ## 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? +## How we use 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: +When it comes to handling exceptions, **Dotkernel API** relies on the usage of easy-to-understand, problem-specific exceptions. +Below we will list the available custom exceptions. ### `BadRequestException` thrown when -* client tries to create/update resource, but the data from the request is invalid/incomplete (example: client tries to - create an account, but does not send the required `identity` field) +* The Client tries to **create/update resource**, but the **request data is invalid/incomplete** (example: client tries to create an account, but does not send the required `identity` field) ### `ConflictException` thrown when -* resource cannot be created because a different resource with the same identifier already exists (example: cannot - change existing user's identity because another user with the same identity already exists) -* resource cannot change its state because it is already in the specified state (example: user cannot be activated - because it is already active) +* The **resource cannot be created** because a different resource with the same identifier **already exists** (example: cannot change existing user's identity because another user with the same identity already exists) +* The **resource cannot change its state** because it is **already in the specified state** (example: user cannot be activated because it is already active) ### `ExpiredException` thrown when -* resource cannot be accessed because it expired (example: account activation link) -* resource cannot be accessed because it has been consumed (example: one-time password) +* The **resource cannot be accessed** + * because it has **expired** (example: account activation link) + * because it has been **consumed** (example: one-time password) ### `ForbiddenException` thrown when -* resource cannot be accessed by the authenticated client (example: client authenticated as regular user sends - a `GET /admin` request) +* The **resource cannot be accessed** by the authenticated client's **role** (example: client authenticated as regular user sends a `GET /admin` request) ### `MethodNotAllowedException` thrown when -* client tries to interact with a resource via an invalid HTTP request method (example: client sends a `PATCH /avatar` - request) +* The client tries to interact with a resource via an **invalid HTTP request method** (example: client sends a `PATCH /avatar` request) ### `NotFoundException` thrown when -* client tries to interact with a resource that does not exist on the server (example: client sends - a `GET /resource-does-not-exist` request) +* The client tries to interact with a **resource that does not exist** on the server (example: client sends a `GET /resource-does-not-exist` request) ### `UnauthorizedException` thrown when -* resource cannot be accessed because the client is not authenticated (example: unauthenticated client sends - a `GET /admin` request) +* The **resource cannot be accessed** because the **client is not authenticated** (example: unauthenticated client sends a `GET /admin` request) -## How it works? +## 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 processed the request. -Else, it will build and send a response based on the exception thrown: +Otherwise, it will build and send a response based on the exception thrown: * `BadRequestException` will return a `400 Bad Request` response * `UnauthorizedException` will return a `401 Unauthorized` response @@ -67,11 +56,13 @@ Else, it will build and send a response based on the exception thrown: * `ExpiredException` will return a `410 Gone` response * `MailException`, `RuntimeException` and the generic `Exception` will return a `500 Internal Server Error` response -## How to extend? +## How to extend + +In this example we will -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. +* Create a custom exception called `CustomException` +* Place it next to the already existing custom exceptions (you can use your preferred location) +* Return a custom HTTP status code when `CustomException` is encountered. ### Step 1: Create exception file @@ -106,8 +97,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 { @@ -133,5 +123,5 @@ Save and close the file. ### Step 5: Test for success -Again, access your API's home page URL, which should return the same content. +Access your API's home page URL, which should return the same content. Notice that this time it returns `418 I'm a teapot` HTTP status code. diff --git a/docs/book/v5/introduction/file-structure.md b/docs/book/v5/introduction/file-structure.md index 566347a..5e295f3 100644 --- a/docs/book/v5/introduction/file-structure.md +++ b/docs/book/v5/introduction/file-structure.md @@ -24,38 +24,95 @@ When using Dotkernel API the following structure is installed by default: * `.github` - containes workflow files * `.laminas-ci` - contains laminas-ci workflow files +### `bin` directory + +This directory contents are + +* `clear-config-cache.php` which removes the config cache file (`data/cache/config-cache.php` - available only when development mode is enabled). +* `cli.php` used to build console applications based on [laminas-cli](https://github.com/laminas/laminas-cli) +* `doctrine` used by the doctrine fixtures to populate the database tables + +### `config` directory + +This directory contains all application-related config files: + +* `cli-config.php`: command line interface configuration used by migrations, fixtures, crons +* `config.php`: registers ConfigProviders for installing packages +* `container.php`: main service container that provides access to all registered services +* `development.config.php.dist`: activates debug mode; gets symlinked as `development.config.php` when enabling development mode +* `migrations.php`: configuration for database migration, like migration file location and table to save the migration log +* `pipeline.php`: contains a list of middlewares, in the order of their execution +* `twig-cs-fixer.php`: configuration file for Twig code style checker/fixer + +#### `config/autoload` directory + +This directory contains all service-related local and global config files: + +* `authorization.global.php`: configures access per route for user roles +* `cli.global.php`: configures cli +* `content-negotiation.global.php`: configures request and response formats +* `cors.local.php.dist`: configures Cross-Origin Resource Sharing, like call origin, headers, cookies +* `dependencies.global.php`: config file to set global dependencies that should be accessible by all modules +* `development.local.php.dist`: gets symlinked as `development.local.php` when enabling development mode - activates error handlers +* `doctrine.global.php`: configuration used by Object–relational mapping +* `error-handling.global.php`: configures and activates error logs +* `local.php.dist`: local config file where you can overwrite application name and URL +* `local.test.php.dist`: local configuration for functional tests +* `mail.local.php.dist`: mail configuration; e.g. sendmail vs smtp, message configuration, mail logging +* `mezzio.global.php`: Mezzio core config file +* `mezzio-tooling-factories.global.php`: add or remove factory definitions +* `response-header.global.php`: defines headers per route +* `templates.global.php`: dotkernel/dot-twigrenderer config file + +### `data` directory + +This directory is a storage for project data files and service caches. +It contains these folders: + +* `cache`: cache for e.g. Twig files +* `doctrine`: database migrations and fixtures +* `oauth`: encryption, private and public keys needed for authentication +* `data/lock` - lock files generated by [`dotkernel/dot-cli`](https://docs.dotkernel.org/dot-cli/v3/lock-files/) + +> AVOID storing sensitive data on VCS. + +### `log` directory + +This directory stores daily log files. +When you access the application from the browser, (if not already created) a new log file gets created in the format specified in the `config/autoload/error-handling.global.php` config file under the `stream` array key. + +### `public` directory + +This directory contains all publicly available assets and serves as the entry point of the application: + +* `uploads`: a folder that normally contains files uploaded via the application +* `.htaccess`: server configuration file used by Apache web server; it enables the URL rewrite functionality +* `index.php`: the application's main entry point +* `robots.txt.dist`: a sample robots.txt file that allows/denies bot access to certain areas of your application; activate it by duplicating the file as `robots.txt` and comment out the lines that don't match your environment + ## `src` directory -This directory contains all source code related to the Module. It should contain following directories, if they’re not empty: +This folder contains a separate folder for each Module. +Each Module folder, in turn, should contain following directories, unless they are empty: * Handler - Action classes (similar to Controllers but can only perform one action) -* Entity - For database entities +* Entity - Used by database entities * Service - Service classes * Collection - Database entities collections * Repository - Entity repository folder -> The above example is just some of the directories a project may include, but these should give you an idea of how the structure should look like. +> The above example is just some of the directories a project may include, but they should give you an idea about the recommended structure. Other classes in the `src` directory may include `InputFilter`, `EventListener`, `Helper`, `Command`, `Factory` etc. -The `src` directory should also contain 2 files: +The `src` directory normally also contains these files: -* `ConfigProvider.php` - Provides configuration data -* `RoutesDelegator.php` - Module main routes entry file +* `ConfigProvider.php` - Configuration data for the module +* `OpenAPI.php` - Detailed descriptions for each endpoint in the OpenAPI format +* `RoutesDelegator.php` - Module specific route registrations Module main routes entry file ## `templates` directory 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 - -## `data` directory - -This directory contains project-related data (such as cache, file uploads) - -We recommend using the following directory structure: - -* `data/cache` - location where caches are stored -* `data/oauth` - encryption, private and public keys needed for authentication. -* `data/doctrine` - fixtures and migrations -* `data/lock` - lock files generated by `dotkernel/dot-cli` [See more](https://docs.dotkernel.org/dot-cli/v3/lock-files/) diff --git a/docs/book/v5/introduction/psr.md b/docs/book/v5/introduction/psr.md new file mode 100644 index 0000000..5e6e049 --- /dev/null +++ b/docs/book/v5/introduction/psr.md @@ -0,0 +1,38 @@ +# PSRs + +Some of the PSRs on this list are at the core of Dotkernel API, but several others are installed with the 3rd party packages used in the application. +Below is the full list of PSRs present in Dotkernel API and their purpose. + +* PSR-3: [Logger Interface](https://www.php-fig.org/psr/psr-3/) + * Interface for logging libraries + * Interfaces implemented in [php-fig/log](https://github.com/php-fig/log) +* PSR-4: [Autoloader](https://www.php-fig.org/psr/psr-4/) + * Autoloading classes from file paths + * Interfaces implemented in [laminas/laminas-loader](https://github.com/laminas/laminas-loader) +* PSR-6: [Caching Interface](https://www.php-fig.org/psr/psr-6/) + * Interface for caching systems to improve the performance of any project + * Interfaces implemented in [php-fig/cache](https://github.com/php-fig/cache) +* PSR-7: [HTTP message interfaces](https://www.php-fig.org/psr/psr-7/) + * Interfaces for representing HTTP messages and URIs for use with HTTP messages + * Interfaces implemented in [php-fig/http-message](https://github.com/php-fig/http-message) +* PSR-11: [Container interface](https://www.php-fig.org/psr/psr-11/) + * Interface for dependency injection containers + * Interfaces implemented in [php-fig/container](https://github.com/php-fig/container) +* PSR-13: [Link definition interfaces](https://www.php-fig.org/psr/psr-13/) + * Way of representing a hypermedia link independently of the serialization format + * Interfaces implemented in [php-fig/link](https://github.com/php-fig/link) +* PSR-14: [Event Dispatcher](https://www.php-fig.org/psr/psr-14/) + * Mechanism for event-based extension and collaboration + * Interfaces implemented in [php-fig/event-dispatcher](https://github.com/php-fig/event-dispatcher) +* PSR-15: [HTTP Server Request Handlers](https://www.php-fig.org/psr/psr-15/) + * Interfaces for HTTP server request handlers and HTTP server middleware components that use HTTP messages + * Interfaces implemented in [php-fig/http-server-handler](https://github.com/php-fig/http-server-handler) and [php-fig/http-server-middleware](https://github.com/php-fig/http-server-middleware) +* PSR-17: [HTTP Factories](https://www.php-fig.org/psr/psr-17/) + * Standard for factories that create PSR-7 compliant HTTP objects + * Interfaces implemented in [php-fig/http-factory](https://github.com/php-fig/http-factory) +* PSR-18: [HTTP Client](https://www.php-fig.org/psr/psr-18/) + * Interface for sending HTTP requests and receiving HTTP responses + * Interfaces implemented in [php-fig/http-client](https://github.com/php-fig/http-client) +* PSR-20: [Clock](https://www.php-fig.org/psr/psr-20/) + * Interface for reading the system clock + * Interfaces implemented in [php-fig/clock](https://github.com/php-fig/clock) diff --git a/docs/book/v5/tutorials/api-evolution.md b/docs/book/v5/tutorials/api-evolution.md index 02b425b..2fd0c00 100644 --- a/docs/book/v5/tutorials/api-evolution.md +++ b/docs/book/v5/tutorials/api-evolution.md @@ -1,7 +1,6 @@ # API Evolution pattern -API evolution: Updating an API while keeping it compatible for existing consumers by adding new features, fixing bugs, -planning and removing outdated features. +API evolution: Updating an API while keeping it compatible for existing consumers by adding new features, fixing bugs, planning and removing outdated features. ## How it works @@ -13,10 +12,10 @@ We use response headers to inform the consumers about the future changes by usin **Both headers are independent, you can use them separately.** -> Make sure you have the `DeprecationMiddleware:class` piped in your `pipeline` list. In our case it's -> `config/pipeline.php`. +> Make sure you have the `DeprecationMiddleware:class` piped in your `pipeline` list. +> In our case it's `config/pipeline.php`. -### Marking an entire endpoint as deprecated +## Marking an entire endpoint as deprecated When you want to mark an entire resource as deprecated you have to use the `ResourceDeprecation` attribute. @@ -34,8 +33,7 @@ class HomeHandler implements RequestHandlerInterface ... ``` -In the example above, the ``ResourceDeprecation`` attribute is attached to the class, marking the entire `/` (home) -endpoint as deprecated starting from `2038-01-01`. +In the example above, the `ResourceDeprecation` attribute is attached to the class, marking the entire `/` (home) endpoint as deprecated starting from `2038-01-01`. Running the following curl will print out the response headers where we can see the **Sunset** and **Link** headers. @@ -56,10 +54,9 @@ Link: https://docs.dotkernel.org/api-documentation/v5/core-features/versioning;r Vary: Origin ``` -### Marking a method as deprecated +## Marking a method as deprecated -Most of the time you want to deprecate only an endpoint, so you will need to use the `MethodDeprecation` attribute which -has the same parameters, but it attaches to a handler method. +Most of the time you want to deprecate only an endpoint, so you will need to use the `MethodDeprecation` attribute which has the same parameters, but it attaches to a handler method. ```php ... @@ -90,6 +87,8 @@ If you followed along you can run the below curl: curl --head -X GET http://0.0.0.0:8080 -H "Content-Type: application/json" ``` +The response lists the **Sunset** and **Link** headers. + ```shell HTTP/1.1 200 OK Host: 0.0.0.0:8080 @@ -103,7 +102,7 @@ Link: https://docs.dotkernel.org/api-documentation/v5/core-features/versioning;r Vary: Origin ``` -### NOTES +## NOTES > If `Link` or `Sunset` do not have a value they will not appear in the response headers. @@ -113,5 +112,4 @@ Vary: Origin > Deprecations can only be attached to handler classes that implement `RequestHandlerInterface`. -> The `rel` and `type` arguments are optional, they default to `sunset` and `text/html` if no value was provided and -> are `Link` related parts. +> The `rel` and `type` arguments are optional, they default to `sunset` and `text/html` if no value was provided and are `Link` related parts. diff --git a/docs/book/v5/core-features/cors.md b/docs/book/v5/tutorials/cors.md similarity index 100% rename from docs/book/v5/core-features/cors.md rename to docs/book/v5/tutorials/cors.md diff --git a/docs/book/v5/upgrading.md b/docs/book/v5/upgrading.md index ffc6ddd..c22d29b 100644 --- a/docs/book/v5/upgrading.md +++ b/docs/book/v5/upgrading.md @@ -1,18 +1,15 @@ # Upgrades Dotkernel API does not provide an automatic upgrade path. - Instead, the recommended procedure is to manually implement each modification listed in [releases](https://github.com/dotkernel/api/releases). -Additionally, releases info can also be accessed as an [RSS](https://github.com/dotkernel/api/releases.atom) feed. +Additionally, release info can also be accessed as an [RSS](https://github.com/dotkernel/api/releases.atom) feed. ## Upgrade procedure Once you clone Dotkernel API, you will find a [CHANGELOG.md](https://github.com/dotkernel/api/blob/5.0/CHANGELOG.md) file in the root of the project. +This file contains a list of already implemented features in reverse chronological order. +You can use this file to track the version of your copy of Dotkernel API. -This contains a list of already implemented features in reversed chronological order. -You can use this file to track the version your copy of Dotkernel API is at. - -When there is a new release, you need to run through it and implement in your project the modifications from each pull request. - -Finally, copy the release info and paste it at the beginning of your project's CHANGELOG.md file. -This way you will be able to track your API's version info and keep your project up-to-date. +For each new release you need implement the modifications from its pull requests in your project. +It is recommended to copy the release info into your project's CHANGELOG.md file. +This allows you to track your API's version and keep your project up-to-date with future releases. diff --git a/mkdocs.yml b/mkdocs.yml index d952ee8..59e033a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,6 +14,7 @@ nav: - "Server Requirements": v5/introduction/server-requirements.md - "File Structure": v5/introduction/file-structure.md - "Packages": v5/introduction/packages.md + - "PSRs": v5/introduction/psr.md - Installation: - "Getting Started": v5/installation/getting-started.md - "Composer": v5/installation/composer.md @@ -31,7 +32,6 @@ nav: - "Authorization": v5/core-features/authorization.md - "Content Validation": v5/core-features/content-validation.md - "Exceptions": v5/core-features/exceptions.md - - "CORS": v5/core-features/cors.md - "Dependency Injection": v5/core-features/dependency-injection.md - "Error reporting": v5/core-features/error-reporting.md - Commands: @@ -40,6 +40,7 @@ nav: - "Display available endpoints": v5/commands/display-available-endpoints.md - "Generate tokens": v5/commands/generate-tokens.md - Tutorials: + - "Setting up CORS": v5/tutorials/cors.md - "Creating a book module": v5/tutorials/create-book-module.md - "Token authentication": v5/tutorials/token-authentication.md - "API Evolution": v5/tutorials/api-evolution.md