Shopee Client
1. Descripción general
shopee-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con la API de Shopee Open Platform. 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 tokens de acceso, consultar/buscar productos, actualizar stock, consultar información de tienda/almacén y gestionar conversaciones de mensajería con compradores en Shopee.
A diferencia de otros clientes del ecosistema, ShopeeClient es genérico respecto a la ruta: cada método recibe la ruta del endpoint de Shopee como parámetro (path), y no gestiona ni la firma HMAC ni el token de acceso — ambos deben ser calculados y pasados por el consumidor en cada llamada.
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | shopee-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.shopeeclient
├── ShopeeClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ └── ShopeeClient.java # Interfaz @HttpExchange con 12 operaciones, todas parametrizadas por {path}
├── config/
│ ├── ShopeeClientAutoConfiguration.java # @AutoConfiguration principal (URI encoding especial)
│ └── CacheStore.java # Cache genérica en memoria (Guava), disponible para que el consumidor cachee tokens
├── request/ # ShopeeAccessTokenRequest, ShopeeRefreshTokenRequest, ShopeeGetProductInfoRequest,
│ # ShopeeUpdateStockRequest, ShopeeMessageRequest, ShopeeMarkUnreadRequest
└── response/ # ShopeeRefreshTokenResponse, ShopeeSeachItemResponse, ShopeeSearchAllItemResponse,
# ShopeeGetModelListResponse, ShopeeUpdateStockResponse, ShopeeConversationResponse
Flujo principal
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as ShopeeClient
participant Shopee as API Shopee Open Platform
Consumidor->>Consumidor: calcula sign (HMAC-SHA256) + timestamp + resuelve/cachea access_token
Consumidor->>Client: updateStock(path, accessToken, partnerId, shopId, sign, timestamp, body) / ...
Client->>Shopee: request a {baseUrl}{path}?partner_id=&sign=×tamp=&access_token=...
Shopee-->>Client: ResponseEntity<T>
Client-->>Consumidor: ResponseEntity<T>
La autoconfiguración (ShopeeClientAutoConfiguration) se activa condicionalmente con @ConditionalOnProperty(prefix = "shopee.api", name = "host"), registrando el bean ShopeeClient con un RestClient cuya UriBuilderFactory se configura con EncodingMode.NONE, para que el valor sustituido en {path} (p. ej. /api/v2/auth/token/get) no sufra percent-encoding de las barras /.
El registro de la autoconfiguración se realiza mediante el fichero estándar de Spring Boot:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
CacheStore<T> (backend Guava) está disponible como utilidad para que el consumidor cachee el access_token con TTL, pero no se usa internamente por ningún componente de la librería — la gestión completa del ciclo de vida del token (obtención, refresco, caché) es responsabilidad del consumidor.
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.guava:guava | 33.6.0-jre | Implementación de caché en CacheStore (CacheBuilder); disponible para el consumidor |
com.google.code.gson:gson | (gestionada SB4) | Anotaciones @SerializedName en los modelos (soporte dual con Jackson) |
com.fasterxml.jackson.core:jackson-databind | (gestionada SB4) | Serialización/deserialización Jackson en los modelos |
org.projectlombok:lombok | 1.18.46 | Generación de boilerplate en los modelos (getters, setters, constructores, @Data) |
spring-boot-starter-test | (gestionada SB4) | Testing (scope test) |
5. API / Endpoints
No aplica a este proyecto. shopee-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de Shopee se detallan en la sección 6.
6. Integraciones externas
API de Shopee Open Platform
Todos los métodos comparten el mismo patrón: reciben path (ruta remota concreta de Shopee), partner_id, sign (firma HMAC-SHA256 precalculada) y timestamp como parámetros obligatorios; la mayoría requieren además access_token y shop_id.
| Área | Método | HTTP | Parámetros propios | Descripción |
|---|---|---|---|---|
| Auth / token | generateAccessToken | POST | body: code, partner_id, shop_id | Intercambia un código de autorización por access/refresh token |
| Auth / token | getAccessToken | POST | body: refresh token, partner y shop ID | Refresca el access token con un refresh token |
| Producto | getItemBaseInfo | GET | item_id_list fijo en la URL (ver sección 13) | Consulta información base de ítems |
| Producto | searchItem | GET | item_sku, page_size=1 fijo | Busca un ítem por SKU (máx. 1 resultado) |
| Producto | searchAllItem | GET | offset, page_size=100&item_status=NORMAL fijos | Lista paginada de ítems en estado NORMAL |
| Producto | getProductInfo | POST | body: lista de IDs de ítem y tipos de info deseados | Consulta información detallada de producto |
| Producto | getModelList | GET | item_id | Lista de variantes (modelos) de un ítem, con stock y precio |
| Inventario | updateStock | POST | body: item_id, lista de stock_list por modelo | Actualiza el stock del vendedor para uno o varios modelos |
| Tienda | getShopInfo | GET | — | Consulta información general de la tienda |
| Almacén | getWarehouseDetail | GET | — | Consulta el detalle del almacén |
| Mensajería | getConversationList | GET | direction=older&type=unread fijos | Lista conversaciones no leídas (de más antigua a más reciente) |
| Mensajería | sendMessage | POST | body: destinatario, tipo y contenido del mensaje | Envía un mensaje (texto, sticker, imagen o referencia de pedido) |
| Mensajería | markAsUnread | POST | body: conversation_id | Marca una conversación como no leída (ID en el body) |
| Mensajería | markAsUnreadParams | POST | conversation_id como query param | Marca una conversación como no leída (ID como parámetro de query) |
Ejemplo de payload updateStock (ShopeeUpdateStockRequest):
{
"item_id": 19253756461,
"stock_list": [
{ "model_id": 100001, "seller_stock": [{ "stock": 25 }] }
]
}
Ejemplo de respuesta updateStock (ShopeeUpdateStockResponse):
{
"error": "",
"message": "",
"request_id": "abc123",
"response": {
"success_list": [{ "model_id": 100001, "normal_stock": 25 }],
"failure_list": []
}
}
Ejemplo de respuesta de token (ShopeeRefreshTokenResponse, común a generateAccessToken/getAccessToken):
{
"partner_id": 123456,
"shop_id": 789012,
"access_token": "********",
"refresh_token": "********",
"expire_in": 14400,
"request_id": "abc123",
"error": "",
"message": ""
}
Protocolo: HTTPS REST (JSON, contentType/accept = application/json). Autenticación: firma HMAC-SHA256 (sign) y access_token calculados/gestionados enteramente por el consumidor; el cliente solo los transporta como parámetros.
7. Configuración
No se incluye ningún application.properties/application.yml en la librería. La única propiedad requerida debe ser suministrada por la aplicación consumidora:
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
shopee.api.host | URL base de la API de Shopee (activa la autoconfiguración) | ${SHOPEE_API_HOST} |
Las credenciales (partner_id, partner_key/secreto para firmar, access_token, refresh_token) no se configuran como propiedades Spring: el consumidor las gestiona por completo, incluyendo el cálculo de la firma HMAC-SHA256 en cada llamada.
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
SHOPEE_API_HOST | shopee.api.host |
Importante: Si
shopee.api.hostno está definida, el beanShopeeClientno se registra (condición@ConditionalOnProperty).
8. Persistencia
No aplica a este proyecto. La librería no accede a ninguna base de datos. CacheStore está disponible como utilidad de caché en memoria, pero no la usa internamente ningún componente de esta librería — queda a criterio del consumidor emplearla para cachear tokens.
9. Procesos programados y mensajería
No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch. La "mensajería" cubierta por getConversationList/sendMessage/markAsUnread es la API de chat de Shopee (llamadas HTTP síncronas), no un mecanismo de mensajería propio de la librería.
10. Ejecución en local
shopee-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 (como en CI)
./mvnw -B -DskipTests clean install
# Compilar con tests
./mvnw clean verify
# Ejecutar un test/método concreto
./mvnw -Dtest=MyTestClass test
./mvnw -Dtest=MyTestClass#myMethod test
Uso como dependencia en un microservicio consumidor
<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>shopee-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>
La autoconfiguración se activa automáticamente al declarar shopee.api.host en la aplicación consumidora. El consumidor debe calcular la firma HMAC-SHA256 (partner_key + path + timestamp [+ access_token + shop_id según el endpoint], según el esquema de firma de Shopee Open Platform) e implementar su propia gestión de tokens antes de invocar cualquier método del cliente.
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/shopee-client/
12. Manejo de errores y logging
La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Ningún método de ShopeeClient declara throws explícito; las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor. Varios modelos de respuesta (ShopeeRefreshTokenResponse, ShopeeUpdateStockResponse) incluyen campos error/message propios del contrato de Shopee, que el consumidor debe inspeccionar manualmente para detectar errores de negocio (Shopee puede responder 200 OK con un error no vacío). No hay configuración de logback ni de niveles de log específicos en la librería.
13. Notas y consideraciones
-
getItemBaseInfoconitem_idhardcodeado en la ruta: El método está anotado@GetExchange("{path}?item_id_list=[19253756461]")— el identificador de ítem19253756461está fijado literalmente en la plantilla de la URL, sin ningún parámetro que permita al consumidor especificar el/los ítems a consultar. Esto es casi con certeza un defecto: cualquier llamada agetItemBaseInfo, independientemente de la intención del consumidor, consultará siempre ese ítem fijo (que parece un ID de prueba dejado en el código). Debe corregirse añadiendo un parámetro@RequestParam/@RequestBodypara la lista de IDs antes de usar este método en producción. -
CacheStoredisponible pero sin ningún consumidor interno: A diferencia de otros clientes del ecosistema, aquí la caché de Guava se expone deliberadamente como utilidad de apoyo (documentado enCLAUDE.md: "available for callers to cache access tokens"), no como mecanismo interno de la autoconfiguración — es el único cliente del ecosistema revisado hasta ahora donde esto es el diseño intencional, no un descuido. -
Firma y token completamente delegados al consumidor: A diferencia de la mayoría de clientes del ecosistema (que resuelven el token internamente vía interceptor), aquí el consumidor debe implementar por su cuenta el algoritmo de firma HMAC-SHA256 de Shopee Open Platform y gestionar el ciclo de vida completo del
access_token/refresh_token. La librería es deliberadamente un transporte genérico parametrizado porpath, no un cliente semánticamente cerrado por endpoint. -
markAsUnreadymarkAsUnreadParamspara la misma operación con distinta forma: Ambos métodos marcan una conversación como no leída, pero uno recibe elconversation_iden el body (ShopeeMarkUnreadRequest) y otro como parámetro de query (int conversationId) — sugiere incertidumbre sobre qué forma exige realmente la API de Shopee para este endpoint, con ambas variantes conservadas por si alguna deja de funcionar. -
Valores fijos embebidos en la plantilla de ruta: Además del caso de
getItemBaseInfo,searchItem(page_size=1),searchAllItem(page_size=100&item_status=NORMAL) ygetConversationList(direction=older&type=unread) fijan parámetros de query directamente en la anotación@GetExchange, sin posibilidad de que el consumidor los override. A diferencia del caso degetItemBaseInfo, estos parecen decisiones de diseño deliberadas (paginación/filtro por defecto), no errores, pero limitan la flexibilidad del cliente para casos de uso que necesiten otro tamaño de página o estado de ítem. -
Sin tests implementados: No se ha encontrado directorio
src/test/en el proyecto. -
ShopeeClientApplication.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.