Como criar APIs personalizadas no Magento 2
Tags: php, magento2, tutorial, braziliandevs
Published: 2021-12-03 16:48:29

# Contextualizando

### O que é HTTP?

*Hypertext Transfer Protocol* (**HTTP**, ou Protocolo de Transferência de Hipertexto) é um método que faz a comunicação entre os clientes e servidores através de *request* (requisição) e *response* (resposta). Arquivos de hipertexto são arquivos que podem ser manipulados via HTML, mas o protocolo HTTP não se restringe apenas a arquivos de hipertexto.

Um cliente (navegador do usuário) envia uma requisição para o servidor, que roda a aplicação para processar a resposta. Ao término do processamento o servidor retorna uma resposta para o navegador.

### O que é API REST?

*Application Programming Interface* (**API**, ou Interface de Programação de Aplicações) é o conjunto de instruções e padrões de programação que servem para fornecer dados e informações relevantes de uma determinada aplicação. Uma API possui uma interface de um *endpoint* que fica exposto publicamente para receber requisições e responde-las com mensagens programáticas através de respostas.

Os *endpoints* são aspectos importantes para a interação com as APIs, normalmente os *endpoints* são URIs via requisições HTTPs.

*Representational State Transfer* (**REST**, ou Transferência Representacional de Estado) é um conjunto de restrições utilizadas para que as requisições HTTP atendam as diretrizes definidas na arquitetura. Os serviços que estão em conformidade com o estilo arquitetural **REST**, são denominados **RESTfull**.

- **POST**: método da aplicação para criar dados no servidor;
- **GET**: método da aplicação para buscar dados no servidor;
- **DELETE**: método da aplicação para excluir dados no servidor;
- **PUT**: método da aplicação para atualizar dados no servidor.

### Magento 2 e APIs

O Magento 2 utiliza reflexão para criar classes automaticamente e definir dados que serão enviados para uma instância da classe PHP chamada no método de serviço da API.

Para ter acesso as informações dos parâmetros que o método de serviço espera e o tipo do retorno do método, é utilizado a anotação do PHP (*docblock*).

---

# Código para criar API REST

### webapi.xml

Para a criação de APIs personalizadas é preciso definir alguns elementos no arquivo `webapi.xml`, seguindo a estruturas de pastas `\{Vendor}\{Module}\etc\{area}\webapi.xml.`

```xml
<?xml version="1.0" ?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
    <route method="{METHOD}" url="/V1/{endpoint}/:{paramName}" secure="{true/false}">
        <service class="{Vendor}\{Module}\Api\{ApiName}Interface" method="{methodName}"/>
        <resources>
            <resource ref="{resource_reference}"/>
        </resources>
        <data>
            <parameter name="{parameterName}" force="{true/false}">{value}</parameter>
        </data>
    </route>
</routes>
```

O nó `<routes>` é o elemento que define a localização do arquivo de esquema XML para a API. O nó `<route>` é filho do nó `<routes>` e obrigatório para definir qual o método e o *endpoint* serão utilizados na API.

### Atributos do nó 'route'

| Atributo | Descrição                                                                                              | Obrigatório |
|----------|--------------------------------------------------------------------------------------------------------|-------------|
| method   | Tipo do método HTTP (GET, POST, PUT e DELETE).                                                         | true        |
| url      | A URL para o endpoint exposto da API. Deve iniciar com "/V{integer}/" para indicar o número da versão. | true        |
| secure   | Indica se a rota da API está acessível apenas para protocolo HTTPS.                                    | false       |

O nó `<service>` é filho do nó `<route>` e obrigatório para definir a implementação da API e o método que será chamado.

### Atributos do nó 'service'

| Atributo | Descrição                                                                      | Obrigatório |
|----------|--------------------------------------------------------------------------------|-------------|
| class    | Especifica a localização da interface responsável para a implementação da API. | true        |
| method   | Especifica o nome do método que será executado na interface.                   | true        |

O nó `<resources>` é filho do nó `<route>` e obrigatório para definir a qual seção(ões) do(s) recurso(s) ACL a API tem acesso. Não possui nenhum atributo.

O nó `<resource>` é filho do nó `<resources>` e obrigatório para definir a qual seção do recurso ACL a API tem acesso. Possui apenas o atributo `ref` que pode possuir os seguintes valores:

- `anonymous`: Permite que a API seja pública e podendo ser acessada por visitantes;
- `self`: Para consultar a API é necessário a autenticação com *oauth*, *token*, *oauth2;*
- `{Vendor}_{Module}::{acl_path}`: Referenciar seção a um recurso ACL para fornecer permissões das configurações.

O nó `<data>` é filho do nó `<route>` e opcional para definir os parâmetros da API através de seus nós filhos. Não possui nenhum atributo.

O nó `<parameter>` é filho do nó `<data>` e obrigatório caso o nó `<data>` for especificado. para definir a qual seção do recurso ACL a API tem acesso. Possui apenas o atributo `ref` que pode possuir os seguintes valores:

### Atributos do nó 'parameter'

| Atributo | Descrição                                                                                                                | Obrigatório |
|----------|--------------------------------------------------------------------------------------------------------------------------|-------------|
| name     | Nome do parâmetro.                                                                                                       | true        |
| force    | Este atributo garante que em uma rota específica da API, o valor do parâmetro será forçado a usar o valor passado no nó. | false       |

### Interface

Todos os métodos expostos pela API devem declarar na interface a tag `@param type $paramName`  para indicar o tipo(s) do(s) parâmetro(s) esperado(s) e o nome do parâmetro esperado pela API e a tag `@return` para indicar o tipo do retorno do método na API.

É possível acessar os parâmetros passados na URL através dos métodos que foram vinculados a API, desde que eles estejam com o mesmo nome em ambos os lugares e que na declaração do método o parâmetro esteja declarado certo (com o *docblock* correto). 

É possível acessar o *body* enviado para a API como se fosse um parâmetro do método declarado, desde que eles estejam com o mesmo nome em ambos os lugares e que na declaração do método o parâmetro esteja declarado certo (com o docblock correto).

**Body:**

```json
{
    "{bodyName}": {
        "{attr}": "{value}",
        "{attr}": "{value}",
        ...
    }
}
```

**Interface:**

```php
<?php

namespace {Vendor}\{Module}\Api;

interface {ApiName}Interface
{
    /**
     * @param {type} $paramName
     * @param {type} $bodyName
     * @return {returnType}
     */
    public function {methodName}({type} $paramName, {type} $bodyName): {returnType};
}
```

### Serviço

Após a criação da interface da API é necessário a sobrescrição através do arquivo `di.xml`, para que o arquivo fique devidamente implementado e possa descrever em como os métodos serão executados.

**Preference:**

```xml
<preference for="{Vendor}\{Module}\Api\{ApiName}Interface" type="{Vendor}\{Module}\Service\{ApiName}" />
```

**Service:**

```php
<?php

namespace {Vendor}\{Module}\Service;

use {Vendor}\{Module}\Api\{ApiName}Interface;

class {ApiName} implements {ApiName}Interface
{
    /**
     * @param {type} $paramName
     * @param {type} $bodyName
     * @return {returnType}
     */
    public function {methodName}(type $paramName): {returnType}
    {
        // Code implementation
    }
}
```

---

# Finalizando

Valores entre chaves (`{test}`) devem ser alterados na implementação do código.

## Habilitando as alterações

Apague os arquivos que são gerados na compilação do Magento e execute o comando PHP para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (proxys, interceptors, etc).

```bash
rm -rf var/generation/
rm -rf generated/
php bin/magento setup:di:compile
```

## Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

```
- app/
  - code/
    - {Vendor}/
        - {Module}/
          - Api/
            - {ApiName}Interface.php
          - etc/
            - di.xml
            - module.xml
          - Service/
            - {ApiName}.php
          - registration.php
          - composer.json
```