19. About backend documentation. Open API. Swagger. Open API Tests. Json:API vs GraphQL vs REST.

Video version
(Leave your feedback on YouTube)

Links

Project documentation is very expensive. That's why most projects don't have it.

Code is better suited for documentation than any language.

Maintaining documentation is very expensive.

Properly written tests are another very good layer of documentation.

If you do write documentation, no one will read it. Reading documentation is a complex skill.

If you are developing something that people's lives or finances depend on, documentation is mandatory. It's also a matter of legal safety.

"Real" documentation is needed not for the code, but for the business logic. The code already shows "how it works". The documentation should give a hint to the question "why it works this way".

OpenAPI (Swagger) is a specification for describing REST web services. It can be easily converted to other specifications!

PHP8 Attributes make OpenAPI descriptions very compact. Attributes are just regular classes, so they can be freely inherited or created, making the description experience even more compact and tailored to the project's needs.

Spectator allows testing the OpenAPI specification. This is just a perfect solution - developers do the same amount of work needed for testing, and simultaneously get always up-to-date tested documentation.

OpenAPI is a better solution than Postman for everyone locally. The developer does the same set of actions as for themselves locally, but immediately for the whole team (QA, frontend devs, other developers).

Swagger is very convenient for "pure" backend developers. It allows quickly testing completed work and minimizing losses in communication with client developers.

Choose REST or Json:API yourself. You need to know about API specifications.

GraphQL is a specific solution with a lot of problems. Think carefully if you really need it.


If you have any more questions or need further adjustments, feel free to let me know!

Modules/Auth/Transformers/CurrentUserInfoResource.php
#[BaseScheme(
    resource: CurrentUserInfoResource::class,
    properties: [
        new PropertyString(property: 'name'),
        new PropertySlug(),
    ]
)]

Modules/Auth/Transformers/LoginUserResource.php
#[BaseScheme(
    resource: LoginUserResource::class,
    properties: [
        new PropertyString(property: 'token'),
    ]
)]

Modules/Auth/Requests/LoginRequest.php
#[BaseScheme(
    resource: LoginRequest::class,
    properties: [
        new PropertyString(
            property: 'email',
            example: 'example@example.com'
        ),
        new PropertyString(
            property: 'password',
            example: 'Pas$word1'
        ),
    ]
)]

Modules/Auth/Actions/GetCurrentUserInfo.php
#[ApiGet(
    path: '/api/v1/me',
    tags: ['Auth'],
    description: 'Get current user info',
    auth: true
)]
#[ResponseJsonSuccess(CurrentUserInfoResource::class)]

Modules/Auth/Actions/LoginUser.php
#[ApiPost(
    path: '/api/v1/login',
    tags: ['Auth'],
    description: 'Login user'
)]
#[ResponseUnauthorized]
#[ResponseJsonSuccess(LoginUserResource::class)]
#[RequestJson(LoginRequest::class)]

Modules/Auth/Actions/GetCurrentUserInfo.php
#[ApiGet(
    path: '/api/v1/me',
    tags: ['Auth'],
    description: 'Get current user info',
    auth: true
)]
#[ResponseJsonSuccess(CurrentUserInfoResource::class)]