iGRPIGRP 3.0Documentation

SDK Java

Cliente Java do Notification Service — dependência Maven, configuração M2M num serviço Spring Boot, envio com template, erros.

O módulo client é o cliente Java do Notification Service. Usa só java.net.http.HttpClient e Jackson: não depende do Spring. A configuração num serviço Spring Boot (propriedades, beans) é feita por ti — ver Configurar num serviço Spring Boot.

É o cliente que o Access Management usa para enviar os emails de convite.


Dependência Maven

<dependency>
  <groupId>cv.igrp.platform.notification</groupId>
  <artifactId>client</artifactId>
  <version>0.2.0-beta.5</version>
</dependency>

O artefacto está no repositório Maven do iGRP (não no registry npm):

<repository>
  <id>igrp-framework-releases</id>
  <url>https://sonatype.nosi.cv/repository/igrp-framework-releases/</url>
</repository>

ApiClient e classes de API

ApiClient guarda a base URL e as credenciais. Cada domínio da API tem uma classe que recebe o ApiClient no construtor:

ClasseEndpointMétodos principais
NotificationsApi/api/v1/notificationssend, list, get, resend
BulkApi/api/v1/notifications/bulkbulk(request), bulkCsv(request, csv, filename)
AttachmentsApi/api/v1/attachmentsupload, download
TemplatesApi/api/v1/templateslist, create, get, update, publish, archive, preview
InboxApi/api/v1/inboxlist, unreadCount, markRead, archive
BatchesApi, RecipientsApi, GroupsApi, RecurrencesApi, DeliveriesApi, StatsApi, SettingsApi, AdminApi, WebhooksApiRestantes recursos da API REST

Autenticação M2M

ApiClient client = new ApiClient();
client.setBaseUrl("https://<gateway>/igrp-notification-service"); // sem /api/v1
client.setClientCredentials(
    "https://<gateway>/igrp-access-management", // authServerBaseUrl
    clientId,
    clientSecret,
    null);                                       // scope: só se o cliente OAuth2 o exigir

O cliente pede o token em POST {authServerBaseUrl}/oauth2/token (client_credentials), guarda-o em cache e renova-o antes de expirar.

SobrecargaToken pedido a
setClientCredentials(authServerBaseUrl, clientId, clientSecret, scope)authServerBaseUrl — a recomendada
setClientCredentials(clientId, clientSecret[, scope])baseUrl do Notification Service — só funciona se ambos estiverem atrás do mesmo host

authServerBaseUrl é o Access Management

O endpoint é {authServerBaseUrl}/oauth2/token: usa a base do Access Management, não o URL do realm do Keycloak.

setAuthToken(token) serve quando já tens um token (por exemplo, o do utilizador para ler a inbox).

applicationCode

O serviço lê a aplicação do claim application_code do token; se o token não o tiver, usa request.setApplicationCode(...) (escritas) ou o argumento applicationCode das sobrecargas de leitura (get(id, applicationCode), list(..., applicationCode)). Sem nenhum dos dois a resposta é 400 APPLICATION_CODE_REQUIRED.


Enviar com template

EMAIL precisa de SMTP configurado

Para enviar por EMAIL, o provider SMTP tem de estar configurado no Notification Service (NOTIFICATION_PROVIDERS_EMAILSMTP_*: servidor, porta, credenciais e remetente). Sem ele, o envio é recusado com 422 CHANNEL_NOT_ENABLED e nenhum email sai — ver Configurar os canais › EMAIL (SMTP). O canal também tem de estar ativo nas Definições da aplicação.

Os modelos são JavaBeans (construtor vazio + setters):

TemplateRefDto template = new TemplateRefDto();
template.setCode("pedido-confirmacao");
template.setLocale("pt-CV");

RecipientDto recipient = new RecipientDto();
recipient.setEmail(email);

SendNotificationRequest request = new SendNotificationRequest();
request.setChannelStrategy(ChannelStrategy.SPECIFIC);
request.setChannels(List.of(Channel.EMAIL));
request.setRecipients(List.of(recipient));
request.setTemplate(template);
request.setVariables(Map.of("nome", nome, "numeroPedido", referencia));
request.setBusinessKey(referencia);
request.setIdempotencyKey("pedido-confirmacao:" + referencia);

NotificationResponse response = new NotificationsApi(client).send(request);
UUID id = response.getId();   // o serviço responde 202: a entrega é assíncrona
ModeloCampos
SendNotificationRequestchannelStrategy (obrigatório), channels, recipients, groups, template ou inline, variables, priority, locale, attachments, category, businessKey, correlationId, idempotencyKey, callbackUrl, scheduledAt, expiresAt, applicationCode
RecipientDtouserId, email, phone, pushToken
GroupRefDtoum de groupId, departmentCode, roleCode, permissionName
TemplateRefDtocode, locale
InlineContentDtosubject, title, body
AttachmentRefDtofilename, contentRef

Enumerados (cv.igrp.platform.notification.client.constants): ChannelStrategy = SPECIFIC, ALL, PREFERRED; Channel = EMAIL, SMS, WHATSAPP, PUSH, IN_APP, OFFLINE; Priority = LOW, NORMAL, HIGH, URGENT.

O locale do template tem de existir

O serviço procura o template publicado com o locale exato e não faz fallback. Sem ele responde 422 TEMPLATE_ERROR com a mensagem No PUBLISHED template…. O Access Management repete o envio uma vez com o locale por omissão do módulo antes de desistir.

Envio em massa

new BulkApi(client).bulk(request) envia o mesmo pedido a muitos destinatários e devolve BulkResponse (batchId, notificationId, totalDeliveries, deliveries). bulkCsv(request, csvBytes, "destinatarios.csv") lê os destinatários de um CSV. O progresso consulta-se em BatchesApi.

Anexos

AttachmentsApi.upload não envia multipart

upload(byte[], filename) manda os bytes como corpo com Content-Type: multipart/form-data, sem partes. O endpoint espera um multipart com a parte file. Faz o upload com um cliente HTTP multipart (por exemplo RestClient com MultipartBodyBuilder), com o mesmo token, e usa o contentRef devolvido em AttachmentRefDto.


Erros

As chamadas lançam ApiException:

MétodoDevolve
getCode()Estado HTTP
getErrorCode()Código do serviço (String), por exemplo TEMPLATE_ERROR
getErrorCodeEnum()O mesmo como IgrpErrorCode (null se desconhecido)
getErrorMessage()Mensagem do serviço

Códigos mais comuns (IgrpErrorCode):

CódigoHTTP
VALIDATION_ERROR, INVALID_REQUEST, APPLICATION_CODE_REQUIRED400
APPLICATION_ACCESS_DENIED, ATTACHMENT_ACCESS_DENIED, MISSING_USER_ID403
TEMPLATE_NOT_FOUND, NOTIFICATION_NOT_FOUND, ATTACHMENT_NOT_FOUND, …404
ATTACHMENT_TOO_LARGE413
TEMPLATE_ERROR, CHANNEL_NOT_ENABLED, CHANNEL_NOT_ALLOWED, CALLBACK_DOMAIN_NOT_ALLOWED, ACCESS_MANAGER_UNAVAILABLE422
QUOTA_EXCEEDED429

Configurar num serviço Spring Boot

O cliente não traz propriedades nem auto-configuração. O padrão usado no Access Management:

@ConfigurationProperties(prefix = "app.notification")
public record NotificationProperties(
        boolean enabled, String baseUrl, String authUrl,
        String clientId, String clientSecret, String scope) {}
@Configuration
@EnableConfigurationProperties(NotificationProperties.class)
public class NotificationClientConfig {

    @Bean
    @ConditionalOnProperty(name = "app.notification.enabled", havingValue = "true")
    ApiClient notificationApiClient(NotificationProperties props) {
        ApiClient client = new ApiClient();
        client.setBaseUrl(props.baseUrl());
        client.setClientCredentials(props.authUrl(), props.clientId(), props.clientSecret(), props.scope());
        return client;
    }

    @Bean
    @ConditionalOnProperty(name = "app.notification.enabled", havingValue = "true")
    NotificationsApi notificationsApi(ApiClient notificationApiClient) {
        return new NotificationsApi(notificationApiClient);
    }
}
app.notification.enabled=${NOTIFICATION_ENABLED:false}
app.notification.base-url=${NOTIFICATION_SERVICE_BASE_URL:}
app.notification.auth-url=${IGRP_ACCESS_MANAGEMENT_API:}
app.notification.client-id=${IGRP_M2M_CLIENT_ID:}
app.notification.client-secret=${IGRP_M2M_CLIENT_SECRET:}
app.notification.scope=

Com enabled=false os beans não são criados: injeta Optional<NotificationsApi> no serviço que envia e trata a ausência (sem envio, ou um envio alternativo). O prefixo app.notification é um exemplo; usa o da tua aplicação.

How is this guide?

Última atualização: