Skip to main content

Meli Client

1. Descripción general

meli-client es una librería cliente reutilizable (JAR) que actúa como fachada sobre la API REST de Mercado Libre. 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 consultar pedidos, ítems, paquetes y envíos del marketplace Mercado Libre.

Gestiona de forma transparente la autenticación OAuth (obtención y refresco de token, con caché) para el flujo general, y ofrece además un cliente específico para Mercado Libre Colombia (MeliCoClient) que recibe el token explícitamente en cada llamada en lugar de mediante interceptor automático.

2. Información técnica

PropiedadValor
artifactIdmeli-client
groupIdcom.hawkersco
version1.0.25-SNAPSHOT
Java25
Spring Boot4.0.6
Tipo de artefactoJAR (librería, no ejecutable)
MódulosProyecto único (no multi-módulo)

3. Arquitectura y diseño

Estructura del proyecto:

com.hawkersco.meliclient
├── MeliClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ ├── MeliClient.java # Interfaz @HttpExchange principal (token vía interceptor)
│ ├── MeliCoClient.java # Interfaz @HttpExchange para Mercado Libre Colombia (token explícito por método)
│ └── MeliTokenClient.java # Interfaz @HttpExchange para obtención/refresco de token OAuth
├── config/
│ ├── MeliClientAutoConfiguration.java # @AutoConfiguration de MeliClient (interceptor + caché de token local)
│ ├── MeliCoClientAutoConfiguration.java # @AutoConfiguration de MeliCoClient (sin interceptor)
│ ├── MeliTokenClientAutoConfiguration.java # @AutoConfiguration de MeliTokenClient
│ ├── CacheStore.java # Caché genérica en memoria (Guava)
│ └── CacheStoreBeans.java # Bean de caché adicional con TTL de 5h (no referenciado por MeliClientAutoConfiguration)
├── model/ # POJOs de request/response (Lombok + Jackson + Gson)
│ ├── MeliTokenResquest.java / MeliTokenResponse.java
│ ├── MeliRefreshTokenResquest.java / MeliRefreshTokenResponse.java
│ ├── MeliOrdersResponse.java, MeliItemResponse.java, MeliPackResponse.java
│ ├── MeliShipmentRequest.java / MeliShipmentResponse.java
│ ├── MeliCoOrderResponse.java # Modelo de respuesta de pedido específico de Mercado Libre Colombia
│ └── MeliNotificationResponse.java # Modelo de notificación webhook de Mercado Libre
└── util/
└── LenientLongTypeAdapter.java # TypeAdapter Gson que tolera valores long con decimales

Flujo principal (MeliClient con token cacheado)

sequenceDiagram
participant Consumidor as Microservicio consumidor
participant MeliClient
participant CacheStore
participant MeliTokenClient
participant API as API Mercado Libre

Consumidor->>MeliClient: getOrders / getItemById / getShipmentsByOrder / ...
MeliClient->>CacheStore: get("token")
alt Token en caché (< 5h)
CacheStore-->>MeliClient: token válido
else Token ausente o expirado
MeliClient->>MeliTokenClient: getToken(grantType, clientId, clientSecret)
MeliTokenClient->>API: POST /oauth/token
API-->>MeliTokenClient: { "access_token": "...", "expires_in": ... }
MeliTokenClient-->>MeliClient: token
MeliClient->>CacheStore: add("token", token)
end
MeliClient->>API: request + header Authorization: Bearer <token>
API-->>MeliClient: respuesta JSON
MeliClient-->>Consumidor: ResponseEntity<T>

MeliClientAutoConfiguration se activa condicionalmente con @ConditionalOnProperty(prefix = "meli.credentials", name = {"url", "granttype", "clientid", "clientsecret"}) y se declara @AutoConfiguration(after = MeliTokenClientAutoConfiguration.class) para garantizar que el bean MeliTokenClient ya exista al construir MeliClient. Crea internamente su propia instancia local de CacheStore<String> (TTL 5 horas) para el token — no reutiliza el bean CacheStore<String> expuesto por CacheStoreBeans.

MeliCoClientAutoConfiguration y MeliTokenClientAutoConfiguration se activan con la condición más laxa @ConditionalOnProperty(prefix = "meli.credentials", name = "url") (solo requieren la URL), y registran sus respectivos RestClient sin ningún interceptor de autenticación: MeliCoClient exige el Authorization como parámetro @RequestHeader explícito en cada método.

Las tres autoconfiguraciones se registran mediante el fichero estándar de Spring Boot:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

4. Dependencias principales

DependenciaVersiónPropó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(gestionada SB4)Anotaciones @SerializedName y TypeAdapter (LenientLongTypeAdapter)
com.fasterxml.jackson.core:jackson-databind(gestionada SB4)Serialización/deserialización Jackson en los modelos
com.google.guava:guava33.4.0-jreImplementación de caché en CacheStore (CacheBuilder)
org.projectlombok:lombok1.18.42 (dependencia; annotationProcessorPath del compilador usa 1.18.46)Generación de boilerplate en los modelos
spring-boot-starter-test(gestionada SB4)Testing (scope test)

5. API / Endpoints

No aplica a este proyecto. meli-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de Mercado Libre se detallan en la sección 6.

6. Integraciones externas

API de Mercado Libre — MeliClient (autenticación automática vía interceptor)

MétodoHTTPRuta remotaDescripción
getOrdersGET/orders/searchBusca pedidos de un vendedor filtrados por estado y fecha de creación
getOrdersWithoutStatusGET/orders/searchBusca pedidos de un vendedor filtrados solo por fecha de creación
getPackByIdGET/packs/{idPack}Consulta un pack (agrupación de pedidos con envío conjunto)
getShipmentsByOrderGET/orders/{idOrder}/shipmentsConsulta el envío asociado a un pedido
getOrderByIdGET/orders/{idOrder}Consulta un pedido por su identificador
getItemByIdGET/items/{idItem}Consulta un ítem (publicación) por su identificador
getShipmentsByResourceGET{resource}Consulta un envío usando la ruta de recurso recibida en una notificación webhook
getLabelByShipmentGET/shipment_labelsDescarga la etiqueta de envío (PDF/ZPL) como recurso binario

API de Mercado Libre — MeliCoClient (Colombia, token explícito)

MétodoHTTPRuta remotaDescripción
getOrdersGET/orders/searchBusca pedidos de un vendedor filtrados por estado y fecha
getOrderByIdGET/orders/{idOrder}Consulta un pedido por su identificador
getItemByIdGET/items/{idItem}Consulta un ítem por su identificador
getShipmentsByOrderGET/orders/{idOrder}/shipmentsConsulta el envío asociado a un pedido
getLabelByShipmentGET/shipment_labelsDescarga la etiqueta de envío
getPackByIdGET/packs/{idPack}Consulta un pack

Todos los métodos de MeliCoClient reciben @RequestHeader("Authorization") String token como primer parámetro (valor completo, p. ej. "Bearer <token>") — es responsabilidad del consumidor obtener y renovar ese token.

API de Mercado Libre — MeliTokenClient (OAuth)

MétodoHTTPRuta remotaDescripción
getToken (client credentials)POST/oauth/tokenObtiene un nuevo access token con grant_type, client_id, client_secret
getToken (refresh)POST/oauth/tokenRenueva el access token usando un refresh_token

Ejemplo de respuesta de token (MeliTokenResponse):

{
"access_token": "********",
"token_type": "bearer",
"expires_in": 21600,
"scope": "offline_access read write",
"user_id": 123456789
}

Ejemplo de payload MeliShipmentRequest (modelo de actualización de envío; no está referenciado por ningún método declarado en MeliClient ni MeliCoClient — ver sección 13):

{
"status": "shipped",
"substatus": "in_hub",
"tracking_number": "ABC123456",
"tracking_url": "https://tracking.meli.example/ABC123456",
"payload": { "service_id": 12345, "comment": "En tránsito", "date": "2026-07-10" }
}

Protocolo: HTTPS REST (JSON). Autenticación: OAuth 2.0 (client credentials / refresh token). MeliClient inyecta el Bearer token automáticamente mediante un interceptor con caché de 5 horas; MeliCoClient requiere que el consumidor gestione y pase el token manualmente en cada llamada.

7. Configuración

El fichero src/main/resources/application.properties existe pero está intencionalmente vacío. Las propiedades deben ser inyectadas por la aplicación consumidora.

Propiedades requeridas (prefijo meli.credentials)

PropiedadDescripciónEjemplo de valor
meli.credentials.urlURL base de la API de Mercado Libre (requerida por las tres autoconfiguraciones)${MELI_URL}
meli.credentials.granttypeGrant type OAuth (requerida solo por MeliClientAutoConfiguration)${MELI_GRANT_TYPE}
meli.credentials.clientidClient ID OAuth (requerida solo por MeliClientAutoConfiguration)${MELI_CLIENT_ID}
meli.credentials.clientsecretClient secret OAuth (requerida solo por MeliClientAutoConfiguration)${MELI_CLIENT_SECRET}

Importante: MeliTokenClient y MeliCoClient solo requieren meli.credentials.url para activarse; MeliClient requiere además granttype, clientid y clientsecret. Es posible tener MeliCoClient/MeliTokenClient activos sin que MeliClient lo esté.

Variables de entorno recomendadas

VariablePropiedad mapeada
MELI_URLmeli.credentials.url
MELI_GRANT_TYPEmeli.credentials.granttype
MELI_CLIENT_IDmeli.credentials.clientid
MELI_CLIENT_SECRETmeli.credentials.clientsecret

8. Persistencia

No aplica a este proyecto. La librería no accede a ninguna base de datos. El único estado que persiste en memoria es la caché del token OAuth (CacheStore, TTL 5 horas, backend Guava).

9. Procesos programados y mensajería

No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch. MeliNotificationResponse modela el payload de una notificación webhook entrante de Mercado Libre, pero no hay ningún listener/controlador en este proyecto que la reciba — el modelo está pensado para ser usado por el consumidor al parsear notificaciones recibidas en su propio endpoint.

10. Ejecución en local

meli-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
mvn -B -DskipTests clean install

# Compilar con tests
mvn clean install

# Usando el wrapper
./mvnw clean install

Uso como dependencia en un microservicio consumidor

<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>meli-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>

La autoconfiguración de cada cliente se activa automáticamente según las propiedades meli.credentials.* declaradas en la aplicación consumidora.

11. Despliegue

El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:

  1. Checkout — descarga el código del repositorio.
  2. Publish to Artifact Registry — ejecuta mvn deploy -DskipTests para publicar el JAR en Google Artifact Registry.

CLAUDE.md documenta un pipeline con etapas Build y Clean vía scripts (jenkins/scripts/mvn.sh / clean.sh), que no se corresponde con el Jenkinsfile actual del repositorio (dos etapas: Checkout y Publish to Artifact Registry, sin scripts externos). Se documenta el Jenkinsfile realmente presente en el repositorio.

ParámetroValor
JDKJDK25 (tool Jenkins)
MavenMaven3 (tool Jenkins)
Repositorioeurope-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/meli-client/

12. Manejo de errores y logging

La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor.

En MeliClientAutoConfiguration.resolveToken, si la respuesta de /oauth/token no es 2xx, no tiene body, o el access_token viene vacío, el método devuelve una cadena vacía ("") en lugar de lanzar una excepción — las llamadas posteriores se autenticarían con Authorization: Bearer (token vacío), fallando con un error HTTP del lado de Mercado Libre en vez de fallar explícitamente en el cliente.

No hay configuración de logback ni de niveles de log específicos en la librería.

13. Notas y consideraciones

  • CacheStoreBeans.token() no utilizado por MeliClientAutoConfiguration: CacheStoreBeans expone un bean CacheStore<String> con TTL de 5 horas destinado (según su Javadoc) a ser "compartido" para el token OAuth, pero MeliClientAutoConfiguration crea su propia instancia local de CacheStore<String> en el método meliClient(...) en lugar de inyectar el bean de CacheStoreBeans. El bean expuesto queda disponible en el contexto Spring pero no es consumido por ningún componente de esta librería — mismo patrón de caché "huérfana" observado en auro-client.

  • Comentario de CacheStoreBeans desactualizado: El Javadoc de CacheStoreBeans.token() menciona "Feign interceptors", pero el proyecto no usa Feign en ningún punto (usa @HttpExchange + RestClient), consistente con la discrepancia general entre partes de la documentación heredada y el código actual.

  • MeliShipmentRequest sin método de cliente asociado: El modelo MeliShipmentRequest (payload para actualizar estado/tracking de un envío) no es referenciado por ningún método de MeliClient ni MeliCoClient — ninguna de las dos interfaces declara un PostExchange/PutExchange de envíos. Pendiente de verificar si esta operación se implementa en otro punto no incluido en este repositorio o si el modelo es un remanente.

  • Fallo silencioso en resolveToken: Igual que en otros clientes del ecosistema (hk-timeslogistics-client), si la autenticación falla, MeliClientAutoConfiguration.resolveToken devuelve "" en lugar de propagar una excepción, dificultando el diagnóstico de errores de autenticación.

  • Dos estrategias de autenticación incompatibles conviviendo en el mismo JAR: MeliClient resuelve el token automáticamente vía interceptor y caché; MeliCoClient delega esa responsabilidad completamente en el consumidor (token como parámetro explícito). Un desarrollador que use ambos clientes debe tener presente que su comportamiento respecto a la autenticación es distinto, pese a exponer operaciones equivalentes (ambos tienen getOrders, getOrderById, getItemById, etc. con firmas casi idénticas salvo el parámetro token).

  • LenientLongTypeAdapter: Utilidad Gson que trunca valores decimales (p. ej. 40166.67) a long al deserializar. Su Javadoc indica que debe registrarse manualmente en un GsonBuilder por el consumidor antes de parsear MeliCoOrderResponse; no se aplica automáticamente en ningún punto de esta librería. Existe presumiblemente porque la API de Mercado Libre Colombia devuelve, en algunos campos numéricos declarados como long en los POJOs, valores con parte decimal.

  • Versión de Lombok inconsistente: El pom.xml fija org.projectlombok:lombok en 1.18.42, mientras que el annotationProcessorPath del compilador usa 1.18.46 — misma inconsistencia observada en logisfashion-client.

  • Duplicación de modelos entre MeliCoOrderResponse y MeliOrdersResponse/MeliShipmentResponse: MeliCoOrderResponse reimplementa una jerarquía de clases (Shipment, Order, Payment, Item, direcciones, etc.) con una estructura muy similar a la de los modelos genéricos (MeliOrdersResponse, MeliShipmentResponse), en lugar de reutilizarlos. Refleja que la respuesta de Mercado Libre Colombia difiere lo suficiente del formato genérico como para justificar un modelo propio, pero incrementa la superficie de mantenimiento.

  • Sin tests implementados: No existe directorio src/test/ en el proyecto, consistente con lo indicado en CLAUDE.md.

  • MeliClientApplication.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.