Recharge Client
1. Descripción general
recharge-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con la API de gestión de suscripciones de Recharge, plataforma de suscripción recurrente integrada con Shopify. El proyecto no expone ningún endpoint REST propio; se publica en el registro de artefactos Maven interno y es consumido por otros microservicios del ecosistema Hawkers que necesiten gestionar clientes, direcciones, suscripciones, métodos de pago, cargos y pedidos de suscripción.
La librería expone dos clientes HTTP independientes con estrategias de autenticación distintas:
RechargeSfccClient— cliente principal, con autenticación inyectada globalmente vía autoconfiguración (cabeceras por defecto). Cubre clientes, direcciones, suscripciones, métodos de pago y cargos.RechargeHaLeClient— cliente secundario con URL fija (https://api.rechargeapps.com), donde el token de acceso se pasa explícitamente en cada llamada. Cubre cargos por pedido de Shopify, clientes por ID de Shopify, descuentos y pedidos.
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | recharge-client |
groupId | com.hawkersco |
version | 1.0.25-SNAPSHOT |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | JAR (librería, no ejecutable) |
| Módulos | Proyecto único (no multi-módulo) |
3. Arquitectura y diseño
Estructura del proyecto:
com.hawkersco.rechargeclient
├── RechargeClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ ├── RechargeSfccClient.java # Interfaz @HttpExchange: customers, addresses, subscriptions, payment_methods, charges
│ └── RechargeHaLeClient.java # Interfaz @HttpExchange: charges, customers, addresses, orders (URL fija, token por llamada)
├── config/
│ ├── RechargeSfccClientConfig.java # @AutoConfiguration del cliente principal (cabeceras por defecto)
│ └── RechargeHaLeAutoConfiguration.java # @AutoConfiguration del cliente secundario (sin condición, URL hardcodeada)
├── entity/
│ ├── DiscountForm.java # Modelo de aplicación de descuento (RechargeHaLeClient)
│ └── OrdersRecharge.java # Modelo de respuesta de pedidos (RechargeHaLeClient)
└── sfccentity/ # DTOs que reflejan el contrato de la API de Recharge (RechargeSfccClient)
├── Customer.java / CustomerRequest.java / CustomerResponse.java / CustomersResponse.java
├── Address.java / AddressRequest.java / AddressResponse.java / AddressesResponse.java
├── Subscription.java / SubscriptionRequest.java / SubscriptionCreateRequest.java / SubscriptionResponse.java / SubscriptionsResponse.java
├── PaymentMethod.java / PaymentMethodRequest.java / PaymentMethodUpdateRequest.java / PaymentMethodResponse.java / PaymentMethodsResponse.java
├── Charge.java / ChargeResponse.java / ChargesResponse.java
└── userarea/ # Patrón de DTO dual: *Request (cara al consumidor) vs *RechargeRequest (cara a la API)
├── ChargeSkipRequest.java / ChargeSkipRechargeRequest.java
├── FrequencyUpdateRequest.java / FrequencyUpdateRechargeRequest.java
├── ProductUpdateRequest.java / ProductUpdateRechargeRequest.java
├── SubscriptionCancelRequest.java / SubscriptionCancelRechargeRequest.java
├── SubscriptionNextChargeDateUpdateRequest.java / SubscriptionNextChargeDateUpdateRechargeRequest.java
├── SubscriptionProductQtyUpdateRequest.java / SubscriptionProductQtyUpdateRechargeRequest.java
├── AddressUpdateRequest.java, ExternalTID.java, UserResponse.java
Flujo — RechargeSfccClient (autenticación global)
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as RechargeSfccClient
participant API as API Recharge
Consumidor->>Client: getCustomers / createSubscription / skipCharge / ...
Client->>API: request + X-Recharge-Version + X-Recharge-Access-Token (cabeceras por defecto)
API-->>Client: ResponseEntity<T>
Client-->>Consumidor: ResponseEntity<T>
RechargeSfccClientConfig se activa condicionalmente con @ConditionalOnProperty(prefix = "recharge.auth.client", name = {"url", "version", "token"}), registrando RechargeSfccClient con un RestClient que fija X-Recharge-Version y X-Recharge-Access-Token como cabeceras por defecto (estáticas, sin renovación de token).
Flujo — RechargeHaLeClient (token por llamada)
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as RechargeHaLeClient
participant API as api.rechargeapps.com
Consumidor->>Client: getChargesById(token, shopifyOrderId) / applyDiscount(token, addressId, form) / ...
Client->>API: request + header X-Recharge-Access-Token
API-->>Client: ResponseEntity<String | OrdersRecharge>
Client-->>Consumidor: ResponseEntity<T>
RechargeHaLeAutoConfiguration no declara ninguna condición @ConditionalOnProperty: registra siempre el bean RechargeHaLeClient con la URL base fija https://api.rechargeapps.com (hardcodeada en el código, no configurable).
El registro de ambas autoconfiguraciones se realiza mediante el fichero estándar de Spring Boot:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Patrón de DTO dual en sfccentity/userarea/: cada operación de área de usuario tiene un DTO de cara al consumidor (*Request, con nombres de campo simplificados, p. ej. ChargeSkipRequest.idSubscription) y un DTO de cara a la API de Recharge (*RechargeRequest, con la forma exacta que exige el contrato remoto, p. ej. ChargeSkipRechargeRequest.subscriptionIDS/purchaseItemID). El consumidor debe mapear manualmente entre ambos antes de invocar al cliente — la librería no realiza esta conversión.
4. Dependencias principales
| Dependencia | Versión | Propósito |
|---|---|---|
spring-boot-starter | (gestionada SB4) | Base de Spring Boot (contexto, autoconfiguración) |
spring-web | (gestionada SB4) | RestClient + @HttpExchange / HttpServiceProxyFactory |
com.google.code.gson:gson | 2.14.0 | Anotaciones @SerializedName en los DTOs de sfccentity/userarea (soporte dual con Jackson) |
com.fasterxml.jackson.core:jackson-annotations | (gestionada SB4) | Anotaciones @JsonProperty en los modelos |
org.projectlombok:lombok | 1.18.46 | Generación de boilerplate en los modelos (getters, setters, constructores) |
spring-boot-starter-test | (gestionada SB4) | Testing (scope test) |
5. API / Endpoints
No aplica a este proyecto. recharge-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de Recharge se detallan en la sección 6.
6. Integraciones externas
API de Recharge — RechargeSfccClient (cliente principal)
| Área | Método cliente | HTTP | Ruta remota |
|---|---|---|---|
| Customers | getCustomers | GET | /customers |
| Customers | getCustomerById | GET | /customers/{id} |
| Customers | getCustomerByEmail | GET | /customers?email= |
| Customers | createCustomer | POST | /customers |
| Addresses | getAddress | GET | /addresses/{id} |
| Addresses | getAddresses | GET | /addresses |
| Addresses | getAddressesByCustomer | GET | /addresses?customer_id= |
| Addresses | createAddress | POST | /addresses |
| Addresses | updateAddress | PUT | /addresses/{id} |
| Subscriptions | getSubscriptions | GET | /subscriptions |
| Subscriptions | getSubscription | GET | /subscriptions/{id} (ver anomalía en sección 13) |
| Subscriptions | getSubscriptionsByCustomer | GET | /subscriptions?customer_id= |
| Subscriptions | getSubscriptionsByCustomerAndAddress | GET | /subscriptions?customer_id=&address_id= |
| Subscriptions | getSubscriptionsByAddress | GET | /subscriptions?address_id= |
| Subscriptions | createSubscription | POST | /subscriptions |
| Subscriptions | updateFrequencySubscription | PUT | /subscriptions/{id} |
| Subscriptions | updateProductSubscription | PUT | /subscriptions/{id} |
| Subscriptions | updateNextChargeDate | POST | /subscriptions/{id}/set_next_charge_date |
| Subscriptions | updateQuantity | PUT | /subscriptions/{id} |
| Subscriptions | cancelSubscription | POST | /subscriptions/{id}/cancel |
| Subscriptions | activateSubscription | POST | /subscriptions/{id}/activate |
| Payment methods | getPaymentMethod | GET | /payment_methods/{id} |
| Payment methods | getPaymentMethodsByCustomer | GET | /payment_methods?customer_id= |
| Payment methods | createPaymentMethod | POST | /payment_methods |
| Charges | getChargesByCustomer | GET | /charges?customer_id=&status= |
| Charges | getChargesByAddress | GET | /charges?address_id=&status= |
| Charges | skipCharge | POST | /charges/{id}/skip |
API de Recharge — RechargeHaLeClient (URL fija https://api.rechargeapps.com)
| Método cliente | HTTP | Ruta remota | Descripción |
|---|---|---|---|
getCharges | GET | /charges | Lista cargos (respuesta cruda String) |
getChargesById | GET | /charges?shopify_order_id= | Consulta cargos por ID de pedido de Shopify |
getCustomers | GET | /customers?shopify_customer_id= | Consulta clientes por ID de cliente de Shopify |
getCustomerAddress | GET | /customers/{id_customer}/addresses | Consulta las direcciones de un cliente |
applyDiscount | POST | /addresses/{id_addresses}/apply_discount | Aplica un descuento a una dirección/suscripción |
getOrder | GET | /orders/{order_id} | Consulta un pedido por ID de Recharge (respuesta cruda String) |
getOrderById | GET | /orders?shopify_order_id= | Consulta un pedido por ID de pedido de Shopify |
removeDiscount | POST | /addresses/{address_id}/remove_discount | Elimina un descuento aplicado a una dirección |
Ejemplo de payload applyDiscount (DiscountForm):
{
"discount_id": 12345,
"discount_code": "PROMO2026"
}
Ejemplo de respuesta getOrderById/getChargesById (OrdersRecharge, resumida):
{
"orders": [
{
"id": 111222333,
"shopify_order_id": "444555666",
"customer_id": 987654,
"status": "success",
"charge_status": "success",
"total_price": "59.90",
"currency": "EUR",
"created_at": "2026-07-01T10:00:00Z"
}
]
}
Protocolo: HTTPS REST (JSON). Autenticación: cabecera X-Recharge-Access-Token — inyectada globalmente vía cabeceras por defecto en RechargeSfccClient, o pasada explícitamente por llamada en RechargeHaLeClient.
7. Configuración
No se incluye ningún application.properties/application.yml en la librería. Las propiedades deben ser inyectadas por la aplicación consumidora.
Propiedades requeridas (prefijo recharge.auth.client, solo para RechargeSfccClient)
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
recharge.auth.client.url | URL base de la API de Recharge (activa la autoconfiguración) | ${RECHARGE_CLIENT_URL} |
recharge.auth.client.version | Valor de la cabecera X-Recharge-Version | ${RECHARGE_API_VERSION} |
recharge.auth.client.token | Valor de la cabecera X-Recharge-Access-Token | ${RECHARGE_ACCESS_TOKEN} |
Importante: Si falta cualquiera de las tres propiedades, el bean
RechargeSfccClientno se registra.RechargeHaLeClient, en cambio, no depende de ninguna propiedad: se registra siempre con la URL fijahttps://api.rechargeapps.com, y el token se pasa por llamada.
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
RECHARGE_CLIENT_URL | recharge.auth.client.url |
RECHARGE_API_VERSION | recharge.auth.client.version |
RECHARGE_ACCESS_TOKEN | recharge.auth.client.token |
8. Persistencia
No aplica a este proyecto. La librería no accede a ninguna base de datos ni mantiene estado en memoria.
9. Procesos programados y mensajería
No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch.
10. Ejecución en local
recharge-client es una librería JAR, no una aplicación ejecutable. No tiene servidor embebido ni endpoint de health.
Requisitos previos
- Java 25
- Maven 3.x
- Acceso al registro de artefactos Maven interno (
europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven) para resolver/publicar dependencias.
Compilar e instalar en repositorio local
# Compilar sin tests
./mvnw clean install -DskipTests
# Compilar con tests
./mvnw clean install
# Ejecutar tests
./mvnw test
Uso como dependencia en un microservicio consumidor
<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>recharge-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>
RechargeSfccClient se activa automáticamente al declarar recharge.auth.client.*; RechargeHaLeClient está siempre disponible sin configuración adicional.
11. Despliegue
El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:
- Checkout — descarga el código del repositorio.
- Publish to Artifact Registry — ejecuta
mvn deploy -DskipTestspara publicar el JAR en Google Artifact Registry.
| Parámetro | Valor |
|---|---|
| JDK | JDK25 (tool Jenkins) |
| Maven | Maven3 (tool Jenkins) |
| Repositorio | europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven (Artifact Registry GCP) |
No existe Dockerfile ni despliegue como servicio independiente; el artefacto es un JAR publicado en el registro Maven.
Job de Jenkins:
https://jenkins-pi.hawkersco.net/job/recharge-client/
12. Manejo de errores y logging
La mayoría de métodos de RechargeSfccClient y RechargeHaLeClient declaran throws RestClientResponseException, propagando al consumidor los errores HTTP devueltos por la API de Recharge. La excepción es skipCharge en RechargeSfccClient, que no declara ningún throws explícito (inconsistencia menor respecto al resto de métodos del mismo cliente). No hay configuración de logback ni de niveles de log específicos en la librería.
13. Notas y consideraciones
-
Posible bug en
getSubscription: El método está anotado@GetExchange("/subscriptions/{id}")(con placeholder de ruta{id}), pero su parámetro está anotado@RequestParam(name = "id")en lugar de@PathVariable("id"). Con esta combinación, el parámetro se trataría como un query param (?id=...) en lugar de sustituir el placeholder{id}de la ruta, lo que probablemente provoque un error en tiempo de ejecución (variable de plantilla de URI sin resolver) al invocar este método. Pendiente de verificar en tiempo de ejecución; de confirmarse, es un defecto a corregir cambiando la anotación a@PathVariable. -
RechargeHaLeAutoConfigurationsin@ConditionalOnPropertyy con URL hardcodeada: A diferencia deRechargeSfccClientConfig(condicionado a tres propiedades) y de la práctica general del resto de clientes del ecosistema,RechargeHaLeAutoConfigurationregistra el beanRechargeHaLeClientsiempre, con la URL de producción de Recharge (https://api.rechargeapps.com) fijada en el código — no hay forma de apuntar este cliente a un entorno de pruebas/sandbox sin modificar la librería. -
Dos clientes para la misma API con estrategias de autenticación incompatibles:
RechargeSfccClientinyecta el token globalmente vía cabeceras por defecto (estático, sin renovación);RechargeHaLeClientexige el token como parámetro explícito en cada llamada. Un consumidor que necesite ambos conjuntos de operaciones debe gestionar dos flujos de autenticación distintos para el mismo proveedor. -
Mezcla de
@PathVariablesobre parámetros de query enRechargeHaLeClient: Métodos comogetChargesById(@GetExchange("/charges?shopify_order_id={shopify_order_id}")) usan@PathVariablepara rellenar un placeholder que en realidad forma parte de la query string, en lugar de@RequestParam. Aunque Spring resuelve correctamente placeholders{}dentro de la query string mediante variables de plantilla de URI (a diferencia del caso degetSubscription), es un patrón menos idiomático que usar@RequestParamdirectamente. -
Patrón de DTO dual en
sfccentity/userarea/: Cada operación tiene un par de clases (*Request/*RechargeRequest) con forma de campos distinta; el consumidor es responsable de mapear del DTO "de cara al usuario" al DTO "de cara a la API" antes de invocar el cliente. Aporta una capa de indirección que puede confundir si no se conoce el patrón de antemano — no hay ningún mapper automático en la librería. -
Respuestas crudas (
String) en varios métodos deRechargeHaLeClient:getCharges,getCustomers,getCustomerAddress,applyDiscount,getOrderyremoveDiscountdevuelvenResponseEntity<String>sin deserializar, mientras quegetChargesByIdygetOrderByIdsí devuelven el tipoOrdersRecharge. La cobertura de modelos tipados es parcial. -
Sin tests implementados: No se ha encontrado directorio
src/test/en el proyecto. -
RechargeClientApplication.java: Clase principal de Spring Boot en el paquete raíz, sin funcionalidad operativa. Artefacto residual de la generación inicial del proyecto con Spring Initializr, mismo patrón observado en otros clientes del ecosistema.