Ether Framework
Unified API docs for Ether modules
Loading...
Searching...
No Matches
WebhookPayload.java
Go to the documentation of this file.
1package dev.rafex.ether.webhook.model;
2
3/*-
4 * #%L
5 * ether-webhook
6 * %%
7 * Copyright (C) 2025 - 2026 Raúl Eduardo González Argote
8 * %%
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 * #L%
27 */
28
29import java.net.URI;
30import java.nio.charset.StandardCharsets;
31import java.time.Instant;
32import java.util.LinkedHashMap;
33import java.util.List;
34import java.util.Map;
35
36import dev.rafex.ether.http.client.model.HttpMethod;
37import dev.rafex.ether.http.client.model.HttpRequestSpec;
38import dev.rafex.ether.json.JsonUtils;
39
40/**
41 * Payload de un webhook.
42 * Es un record inmutable que contiene todos los datos necesarios
43 * para enviar un webhook a un endpoint externo.
44 *
45 * @param deliveryId ID de entrega único
46 * @param eventType tipo de evento
47 * @param occurredAt momento en que ocurrió el evento
48 * @param contentType tipo de contenido del cuerpo
49 * @param body cuerpo del payload en bytes
50 * @param headers cabeceras HTTP adicionales
51 */
52public record WebhookPayload(String deliveryId, String eventType, Instant occurredAt, String contentType, byte[] body,
53 Map<String, List<String>> headers) {
54
55 public WebhookPayload {
56 body = body == null ? new byte[0] : body.clone();
57 headers = normalizeHeaders(headers);
58 }
59
60 /**
61 * Crea un payload con contenido JSON.
62 *
63 * @param deliveryId ID de entrega
64 * @param eventType tipo de evento
65 * @param value objeto a serializar como JSON
66 * @return el payload creado
67 */
68 public static WebhookPayload ofJson(final String deliveryId, final String eventType, final Object value) {
69 return new WebhookPayload(deliveryId, eventType, Instant.now(), "application/json",
70 JsonUtils.toJsonBytes(value), Map.of());
71 }
72
73 /**
74 * Crea un payload con contenido de texto plano.
75 *
76 * @param deliveryId ID de entrega
77 * @param eventType tipo de evento
78 * @param value contenido de texto
79 * @return el payload creado
80 */
81 public static WebhookPayload ofText(final String deliveryId, final String eventType, final String value) {
82 return new WebhookPayload(deliveryId, eventType, Instant.now(), "text/plain; charset=utf-8",
83 value == null ? new byte[0] : value.getBytes(StandardCharsets.UTF_8), Map.of());
84 }
85
86 /**
87 * Añade una cabecera al payload.
88 *
89 * @param name nombre de la cabecera
90 * @param value valor de la cabecera
91 * @return un nuevo payload con la cabecera añadida
92 */
93 public WebhookPayload withHeader(final String name, final String value) {
94 final var copy = new LinkedHashMap<String, List<String>>();
95 copy.putAll(headers);
96 copy.put(name, List.of(value));
97 return new WebhookPayload(deliveryId, eventType, occurredAt, contentType, body, copy);
98 }
99
100 /**
101 * Convierte el payload a una especificación de petición HTTP.
102 *
103 * @param endpoint URL del endpoint
104 * @return la especificación de petición
105 */
106 public HttpRequestSpec toRequest(final URI endpoint) {
107 final var builder = HttpRequestSpec.builder(HttpMethod.POST, endpoint).body(body).contentType(contentType);
108 for (final var entry : headers.entrySet()) {
109 for (final var value : entry.getValue()) {
110 builder.header(entry.getKey(), value);
111 }
112 }
113 return builder.build();
114 }
115
116 private static Map<String, List<String>> normalizeHeaders(final Map<String, List<String>> raw) {
117 if (raw == null || raw.isEmpty()) {
118 return Map.of();
119 }
120 final var copy = new LinkedHashMap<String, List<String>>();
121 for (final var entry : raw.entrySet()) {
122 copy.put(entry.getKey(), List.copyOf(entry.getValue()));
123 }
124 return Map.copyOf(copy);
125 }
126}
static byte[] toJsonBytes(final Object value)
Standard header names used by Ether webhook delivery.
record WebhookPayload(String deliveryId, String eventType, Instant occurredAt, String contentType, byte[] body, Map< String, List< String > > headers)
Payload de un webhook.