Skip to main content

Services

Aqui vamos entender como está estruturada a camada de services dentro do Plasma.


A camada de services tem como objetivo agrupar todas as requisições para uma api rest, separando por api e responsabilidades.

No diretório root da aplicação é possível encontrar uma pasta com o nome service, nela terá o que é necessário para implementar seus serviços e assim vincular tudo o que já foi apresentado até aqui para executar uma requisição http.


Organização

Dentro do Plasma a organização de services é dada por agrupamento que acontece da seguinte maneira:

flowchart LR subgraph AGRUPAMENTO direction LR CoreServices --> SERVICES end subgraph SERVICES direction LR AuthService -.extends....-> BaseService PaymentService -.extends....-> BaseService FinancingService -.extends....-> BaseService end style SERVICES fill:#606770,stroke:#fff,stroke-dasharray: 5 5,color:#fff style AGRUPAMENTO fill:#606770,stroke:#606770,color:#fff

Veja que CoreServices é um agrupador de outros services e que extendem BaseService, essa organização é feita para poder garantir que cada requisição se mantenha em seu devido lugar, garantindo a responsabilidade de cada grupo.

service print

Seguindo o diagrama, como pode ser visto na organização da pasta service, temos:

  • CoreService: Classe agrupadora de todos os serviços que compõe a API Core.
  • BaseService: Classe base para criação de novos services.
  • core(diretório): Diretório que acumula todos os services da API Core.
  • AuthService: Service com todas as requisições relacionadas a autenticação da API Core.
  • PaymentService: Service com todas as requisições relacionadas a pagamento da API Core.
  • FinancingService: Service com todas as requisições relacionadas a financiamento da API Core.

Base Service

Antes de mais nada precisamos enteder o que a classe BaseService faz, que no caso não é nada a mais nem a menos que guardar qual é a instância de $Fetch que pretendemos usar.

services/BaseService.ts
import { $Fetch } from 'ohmyfetch';export default class BaseService {  private _api: $Fetch;  constructor(api: $Fetch) {    this._api = api;  }  get api(): $Fetch {    return this._api;  }}

Veja que é apenas uma classe com um construtor e um atributo que deve ser passado no momento que estiver instanciando. Dessa forma sempre que preciso na classe que extender BaseService, poderá herdar o atributo _api.


Implementando um Service

Para implementar um service é muito simples, basta criar uma classe que extenda a classe BaseService, como segue o modelo abaixo:

services/core/AuthService.ts
import { User } from '~~/types/User';import BaseService from '../BaseService';export default class AuthService extends BaseService {  public me(): Promise<User> {    return new Promise(async (resolve, reject) => {      try {        const { data } = await super.api('/usuarios/me', {          method: 'GET'        });        resolve(data);      } catch (e) {        reject(e);      }    });  }}

Uma vez que extende-se BaseService é possível acessar a instancia $Fetch como pode ser visto na linha 8.

Por padrão todas os métodos devem retornar uma Promise e a implementação ser circundada por um try/catch para garantir a captura de algum erro na requisição e ser tratado se necessário ou apenas repassado como catch na Promise implementada. Segue o padrão a ser seguido:

public meuMetodo(): Promise<MeuTipo|void> {  return new Promise(async (resolve, reject) => {    try {      // implementação da requisição      // ...      resolve();    } catch (e) {      reject(e);    }  });}

Implementando uma Classe Agrupadora

Considerando que temos todos os services necessários já implementados, precisamos agrupá-los em uma única classe para facilitar o acesso a partir de um componente ou qualquer outra classe.

CoreService.ts
import { $Fetch } from 'ohmyfetch';import AuthService from './core/AuthService';import PaymentService from './core/PaymentService';import FinancingService from './core/FinancingService';export default class CoreServices {  auth: AuthService;  payment: PaymentService;  financing: FinancingService;  constructor(api: $Fetch) {    this.auth = new AuthService(api);    this.payment = new PaymentService(api);    this.financing = new FinancingService(api);  }}

Veja que esta classe tem um construtor que recebe como parâmetro uma instância $Fetch, isso porque para fazer as requests necessárias é preciso passar para os services qual API deve ser consultada.


Fazendo uma requisição

Agora que temos tudo configurado, vamos então ver como fazer uma requisição.

Considere a sessão script de um componente como apresentado a seguir:

<script setup lang="ts">import { usePlasmaLoading } from '~~/composables/plasma';import CoreServices from '~~/services/CoreServices';const coreService = new CoreServices(useApi().coreApi);const requestHandler = async () => {  usePlasmaLoading().show();  const response = await coreService.auth.me();  usePlasmaLoading().hide();};</script>

Veja com atenção as seguintes linhas:

  • Linha 5: É feita uma nova instância de CoreServices e sabendo que toda classe agrupadora tem em seu construtor um $Fetch para receber como parâmetro, então obtemos essa instância a partir do composable useApi.
  • Linha 9: Uma vez que temos a instância podemos apenas chamar qualquer que seja o service dentro da classe agrupadora e em seguida o método, no caso, método me() do service auth