Instalación y Configuración
Guía completa para instalar y configurar el Shori SDK en tu proyecto.
Requisitos del sistema
- ☕ Java
- 🔷 TypeScript / JavaScript
| Componente | Versión mínima |
|---|---|
| Java | 17+ |
| Maven | 3.6+ |
| Spring Boot (opcional) | 2.7+ / 3.x |
| Componente | Versión mínima |
|---|---|
| Node.js | 18+ (recomendado: 22 LTS) |
| npm | 9+ |
| TypeScript (opcional) | 5.0+ |
Instalación
- ☕ Java
- 🔷 TypeScript / JavaScript
Añade el repositorio y la dependencia en tu pom.xml:
<!-- 1. Repositorio del SDK (GitLab Package Registry - público) -->
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/84253138/packages/maven</url>
</repository>
</repositories>
<!-- 2. Dependencia -->
<dependency>
<groupId>com.nttdata.shori</groupId>
<artifactId>shori-api-client</artifactId>
<version>1.0.6</version>
</dependency>
El Package Registry es público. No necesitas configurar tokens ni credenciales para descargar el artefacto.
Instala el paquete con npm o pnpm:
# npm
npm install shori-sdk-ts
# pnpm
pnpm add shori-sdk-ts
# yarn
yarn add shori-sdk-ts
El paquete está publicado en npm público — no necesitas configurar ningún registry adicional.
El paquete incluye las definiciones de tipos TypeScript. No necesitas instalar @types/shori-sdk-ts.
shori-sdk-ts usa únicamente Web APIs estándar (fetch, Blob, TextEncoder) sin dependencias de Node.js en el código compartido. Es compatible con:
- Node.js 18+ / 22 LTS
- Browsers modernos (Chrome, Firefox, Safari, Edge)
- Next.js (SSR y CSR)
- NestJS
- Express
- Cualquier bundler (Vite, Webpack, esbuild)
Configuración básica
- ☕ Java
- 🔷 TypeScript / JavaScript
Parámetros requeridos
| Parámetro | Descripción | Ejemplo |
|---|---|---|
environment | Ambiente de Shori | ShoriEnvironment.PROD |
portalId | UUID del portal en Shori | "0306444E-38B1-..." |
tenantId | UUID del tenant/organización | "80ff134a-cae2-..." |
apiKey | Clave de API para autenticación | "sk-live-xxxxx" |
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("0306444E-38B1-403D-8753-EC9C2BC43215")
.tenantId("80ff134a-cae2-4a4a-92b9-a109bdee1183")
.apiKey("tu-api-key-secreta")
.build();
Parámetros opcionales
| Parámetro | Descripción | Default |
|---|---|---|
timeoutSeconds | Timeout de conexión y respuesta | 30 |
allowInsecureSsl | Aceptar certificados SSL auto-firmados | true |
maxConnections | Conexiones simultáneas por módulo | 5 |
downloadPath | Ruta local para archivos descargados | carpeta temporal del SO |
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.timeoutSeconds(60)
.allowInsecureSsl(true)
.maxConnections(10)
.downloadPath("/opt/app/downloads")
.build();
Parámetros requeridos
| Parámetro | Descripción | Ejemplo |
|---|---|---|
environment | Ambiente de Shori | ShoriEnvironment.PROD |
portalId | UUID del portal en Shori | "0306444E-38B1-..." |
tenantId | UUID del tenant/organización | "80ff134a-cae2-..." |
apiKey | Clave de API para autenticación | "sk-live-xxxxx" |
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const client = new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId("0306444E-38B1-403D-8753-EC9C2BC43215")
.tenantId("80ff134a-cae2-4a4a-92b9-a109bdee1183")
.apiKey("tu-api-key-secreta")
.build();
Parámetros opcionales
| Parámetro | Descripción | Default |
|---|---|---|
timeoutMs | Timeout de cada request HTTP en milisegundos | 30000 |
const client = new ShoriClientBuilder()
.environment(ShoriEnvironment.UAT)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.timeoutMs(60_000) // 60 segundos
.build();
allowInsecureSsl en TypeScriptEl SDK TypeScript usa fetch nativo del runtime. La verificación SSL está gestionada por Node.js o el browser — no es configurable desde el SDK. En entornos con certificados auto-firmados, usa la variable de entorno NODE_TLS_REJECT_UNAUTHORIZED=0 (solo en desarrollo/UAT).
Ambientes disponibles
- ☕ Java
- 🔷 TypeScript / JavaScript
| Ambiente | Constante | Descripción |
|---|---|---|
| Desarrollo | ShoriEnvironment.DEV | Ambiente local de desarrollo |
| Pruebas | ShoriEnvironment.UAT | User Acceptance Testing |
| Producción | ShoriEnvironment.PROD | Ambiente productivo |
// En desarrollo
ShoriClient devClient = ShoriClient.builder()
.environment(ShoriEnvironment.DEV)
.portalId("portal-dev")
.tenantId("tenant-dev")
.apiKey("api-key-dev")
.allowInsecureSsl(true)
.build();
// En producción
ShoriClient prodClient = ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("portal-prod")
.tenantId("tenant-prod")
.apiKey("api-key-prod")
.allowInsecureSsl(false)
.build();
| Ambiente | Constante | Descripción |
|---|---|---|
| Desarrollo | ShoriEnvironment.DEV | Ambiente local de desarrollo |
| Pruebas | ShoriEnvironment.UAT | User Acceptance Testing |
| Producción | ShoriEnvironment.PROD | Ambiente productivo |
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
// En desarrollo
const devClient = new ShoriClientBuilder()
.environment(ShoriEnvironment.DEV)
.portalId("portal-dev")
.tenantId("tenant-dev")
.apiKey("api-key-dev")
.build();
// En producción
const prodClient = new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId("portal-prod")
.tenantId("tenant-prod")
.apiKey("api-key-prod")
.build();
Selecciona el ambiente dinámicamente según la variable de entorno:
const client = new ShoriClientBuilder()
.environment(
ShoriEnvironment[
process.env.SHORI_ENVIRONMENT as keyof typeof ShoriEnvironment
] ?? ShoriEnvironment.UAT,
)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build();
Integración con frameworks
- ☕ Java
- 🔷 TypeScript / JavaScript
Spring Boot
Define el cliente como un @Bean en una clase de configuración:
@Configuration
public class ShoriConfiguration {
@Value("${shori.portal-id}")
private String portalId;
@Value("${shori.tenant-id}")
private String tenantId;
@Value("${shori.api-key}")
private String apiKey;
@Value("${shori.environment:PROD}")
private String environment;
@Value("${shori.timeout-seconds:30}")
private int timeoutSeconds;
@Bean(destroyMethod = "close")
public ShoriClient shoriClient() {
return ShoriClient.builder()
.environment(ShoriEnvironment.valueOf(environment))
.portalId(portalId)
.tenantId(tenantId)
.apiKey(apiKey)
.timeoutSeconds(timeoutSeconds)
.build();
}
}
application.properties:
shori.portal-id=0306444E-38B1-403D-8753-EC9C2BC43215
shori.tenant-id=80ff134a-cae2-4a4a-92b9-a109bdee1183
shori.api-key=${SHORI_API_KEY}
shori.environment=PROD
shori.timeout-seconds=30
application.yml:
shori:
portal-id: "0306444E-38B1-403D-8753-EC9C2BC43215"
tenant-id: "80ff134a-cae2-4a4a-92b9-a109bdee1183"
api-key: "${SHORI_API_KEY}"
environment: PROD
timeout-seconds: 30
Inyección en servicios:
@Service
public class CasoService {
private final ShoriClient shoriClient;
public CasoService(ShoriClient shoriClient) {
this.shoriClient = shoriClient;
}
public String crearSolicitud(Map<String, Object> datos) {
CasoCreateResponse resultado = shoriClient.caso().create(
CasoCreateRequest.builder()
.casoTypeId("tipo-uuid")
.formId("form-uuid")
.submittedData(datos)
.build()
);
return resultado.getCaso();
}
}
NestJS
Registra el cliente como provider en un módulo dedicado:
// shori.module.ts
import { Module } from "@nestjs/common";
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
@Module({
providers: [
{
provide: "SHORI_CLIENT",
useFactory: () =>
new ShoriClientBuilder()
.environment(
ShoriEnvironment[
process.env.SHORI_ENVIRONMENT as keyof typeof ShoriEnvironment
] ?? ShoriEnvironment.PROD,
)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build(),
},
],
exports: ["SHORI_CLIENT"],
})
export class ShoriModule {}
// caso.service.ts
import { Inject, Injectable } from "@nestjs/common";
import type { ShoriClient } from "shori-sdk-ts";
import { CaseFilter } from "shori-sdk-ts";
@Injectable()
export class CasoService {
constructor(@Inject("SHORI_CLIENT") private readonly shori: ShoriClient) {}
async buscarCasos(casoTypeId: string) {
return this.shori
.caso()
.searchAll(
CaseFilter.builder()
.casoTypeId(casoTypeId)
.workingSubStateId("estado-uuid")
.build(),
);
}
}
Express
// app.ts
import express from "express";
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const app = express();
const shori = new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build();
app.get("/api/casos/:id", async (req, res) => {
try {
const caso = await shori.caso().findById(req.params.id);
res.json(caso);
} catch (error) {
res.status(500).json({ error: (error as Error).message });
}
});
Next.js
// lib/shori.ts — instancia singleton para SSR y API routes
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
let _client: ReturnType<typeof ShoriClientBuilder.prototype.build> | null =
null;
export function getShoriClient() {
if (!_client) {
_client = new ShoriClientBuilder()
.environment(
ShoriEnvironment[
process.env.SHORI_ENVIRONMENT as keyof typeof ShoriEnvironment
] ?? ShoriEnvironment.PROD,
)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build();
}
return _client;
}
// app/api/casos/[id]/route.ts — API Route de Next.js
import { NextResponse } from "next/server";
import { getShoriClient } from "@/lib/shori";
export async function GET(_: Request, { params }: { params: { id: string } }) {
const caso = await getShoriClient().caso().findById(params.id);
return NextResponse.json(caso);
}
Variables de entorno en .env.local:
SHORI_ENVIRONMENT=PROD
SHORI_PORTAL_ID=0306444E-38B1-403D-8753-EC9C2BC43215
SHORI_TENANT_ID=80ff134a-cae2-4a4a-92b9-a109bdee1183
SHORI_API_KEY=tu-api-key-secreta
Gestión del ciclo de vida
- ☕ Java
- 🔷 TypeScript / JavaScript
Cerrar el cliente manualmente
// Al finalizar la aplicación
client.close();
En Spring Boot (automático)
Al declarar el bean con destroyMethod = "close", Spring llama automáticamente a close() cuando el contexto se destruye. No es necesario ningún paso adicional.
El cliente TypeScript no requiere cerrado explícito. Usa fetch nativo del runtime — las conexiones HTTP son gestionadas automáticamente por Node.js o el browser.
close() en TypeScriptA diferencia del SDK Java que gestiona un pool de conexiones HTTP con Apache HttpClient, el SDK TypeScript no mantiene conexiones persistentes propias. El garbage collector de JS libera los recursos automáticamente.
Configuración de SSL
- ☕ Java
- 🔷 TypeScript / JavaScript
Por defecto, allowInsecureSsl(true) está habilitado para facilitar el desarrollo. En producción, desactívalo:
ShoriClient client = ShoriClient.builder()
...
.allowInsecureSsl(false) // Verificar certificado SSL en producción
.build();
Nunca uses allowInsecureSsl(true) en producción. Esto desactiva la verificación del certificado del servidor y expone la comunicación a ataques man-in-the-middle.
La verificación SSL está gestionada por el runtime, no por el SDK.
En Node.js con certificado auto-firmado (solo UAT/DEV):
# Variable de entorno — desactiva verificación SSL en todo el proceso Node.js
NODE_TLS_REJECT_UNAUTHORIZED=0 node mi-app.js
O en el código (solo para desarrollo):
// ⚠️ Solo en desarrollo/UAT — nunca en producción
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Nunca uses NODE_TLS_REJECT_UNAUTHORIZED=0 en producción. En producción, usa únicamente certificados SSL válidos.
Integración con JavaFX y RDA/RPA
Esta sección aplica exclusivamente al SDK Java.
Si usas el SDK en una aplicación de escritorio JavaFX o en un sistema de automatización
(RDA/RPA) con múltiples ventanas o procesos, usa el ShoriClientRegistry para
gestionar los clientes de forma centralizada.
¿Qué es ShoriClientRegistry?
Es una clase de utilidad incluida en el SDK que actúa como registro centralizado de
instancias de ShoriClient. Garantiza que cada cliente se inicialice una sola vez
y se reutilice durante toda la vida de la aplicación.
Estructura recomendada para JavaFX
public class RdaHubApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainView.fxml"));
Scene scene = new Scene(loader.load());
primaryStage.setScene(scene);
primaryStage.setTitle("RDA Hub");
primaryStage.show();
}
@Override
public void stop() throws Exception {
// Cierra TODOS los ShoriClients al cerrar la app
ShoriClientRegistry.closeAll();
}
}
public class PortabilityDownloadController {
private static final String CLIENT_NAME = "portabilidad";
@FXML
public void initialize() {
ShoriClientRegistry.register(
CLIENT_NAME,
ShoriClientRegistry.register(CLIENT_NAME, ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("portalId")
.tenantId("tenantId")
.apiKey("apiKey")
.timeoutSeconds(60)
.downloadPath("C:\\Users\\jramiror\\sdk")
.build())
);
}
}
public class PortabilitySearchService extends Service<List<CasoSearchResponse>> {
private static final String CLIENT_NAME = "portabilidad";
@Override
protected Task<List<CasoSearchResponse>> createTask() {
return new Task<>() {
@Override
protected List<CasoSearchResponse> call() {
ShoriClient client = ShoriClientRegistry.get(CLIENT_NAME);
return client.caso().searchAll(
CaseFilter.builder()
.casoTypeId(FilterOperator.EQ, "producto-uuid")
.workingSubStateId(FilterOperator.IN, "estado-uuid")
.pageSize(100)
.build()
);
}
};
}
}
Múltiples automatizaciones (RDA/RPA)
// Cada automatización tiene su propio cliente con sus credenciales
ShoriClientRegistry.register("portabilidad",
ShoriClientRegistry.register(
CLIENT_NAME,
ShoriClientRegistry.register(CLIENT_NAME, ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("portalId")
.tenantId("tenantId")
.apiKey("apiKey")
.timeoutSeconds(60)
.downloadPath("C:\\Users\\jramiror\\sdk")
.build())
););
ShoriClientRegistry.register("activaciones",
ShoriClientRegistry.register(
CLIENT_NAME,
ShoriClientRegistry.register(CLIENT_NAME, ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("portalId")
.tenantId("tenantId")
.apiKey("apiKey")
.timeoutSeconds(60)
.downloadPath("C:\\Users\\jramiror\\sdk")
.build())
););
// En cada Service, obtener el cliente por nombre
ShoriClient client = ShoriClientRegistry.get("portabilidad");
Configuración avanzada (alta concurrencia)
ShoriClientRegistry.register(
"portabilidad",
ShoriClientRegistry.register(
CLIENT_NAME,
ShoriClientRegistry.register(CLIENT_NAME, ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("portalId")
.tenantId("tenantId")
.apiKey("apiKey")
.timeoutSeconds(60)
.downloadPath("C:\\Users\\jramiror\\sdk")
.allowInsecureSsl(true)
.maxConnections(10)
.timeoutSeconds(30)
.build())
);
);
Javadoc y código fuente en el IDE
A partir de la versión 1.0.6, el pipeline publica automáticamente junto al JAR principal los artefactos:
shori-api-client-1.0.6-sources.jar— código fuente del SDKshori-api-client-1.0.6-javadoc.jar— documentación Javadoc compilada
Maven los descarga automáticamente al ejecutar mvn install.
IntelliJ IDEA: Clic derecho sobre la dependencia en el panel Maven → Download Sources & Documentation
VSCode (Extension Pack for Java):
Ctrl+Shift+P → Java: Import Java Projects para refrescar las dependencias
Solución de problemas comunes
- ☕ Java
- 🔷 TypeScript / JavaScript
ValidationException: El ambiente (environment) es requerido
// ❌ Incorrecto — falta el ambiente
ShoriClient.builder()
.portalId("id")
.apiKey("key")
.build();
// ✅ Correcto
ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("id")
.tenantId("tenant-id")
.apiKey("key")
.build();
AuthenticationException: Error al obtener token
- Verifica que el
apiKeysea correcto para el ambiente seleccionado. - Confirma que el
portalIdytenantIdcorresponden al ambiente seleccionado. - Revisa la conectividad de red con los servidores de Shori.
javax.net.ssl.SSLHandshakeException
Si ves este error en UAT o DEV, habilita el modo SSL permisivo:
.allowInsecureSsl(true)
Acerca del timeout y searchAll
timeoutSeconds aplica por cada request HTTP individual, no al proceso total de searchAll.
searchAll realiza múltiples requests en secuencia (uno por página). Si tienes 5.000 casos con pageSize=100, ejecuta 50 requests encadenados. Cada uno tiene su propio timeout independiente.
Solo necesitas aumentar timeoutSeconds si una sola llamada al API tarda en responder:
.timeoutSeconds(60) // útil si el API tarda en responder cada página individualmente
AuthenticationException: Error de autenticación HTTP 401
- Verifica que el
apiKeysea correcto para el ambiente seleccionado. - Confirma que
portalIdytenantIdcorresponden al ambiente. - El SDK renueva el token automáticamente. Si el error persiste, verifica las credenciales.
ApiException: Timeout (30000ms)
Incrementa el timeout al construir el cliente:
const client = new ShoriClientBuilder()
...
.timeoutMs(60_000) // 60 segundos
.build();
fetch cuelga en uploads (Node.js)
Si el upload de archivos se cuelga en Node.js, asegúrate de usar la versión 1.2.3+ del SDK. Las versiones anteriores usaban FormData que causa un bug en undici (el motor de fetch de Node.js). La versión actual serializa el multipart manualmente como ArrayBuffer.
Acerca del timeout y searchAll
timeoutMs aplica por cada request HTTP individual, no al proceso total de searchAll.
searchAll pagina automáticamente haciendo múltiples requests. Cada uno tiene su propio timeout independiente. Incrementa timeoutMs solo si una sola página tarda en responder.