Introducció
Es vol fomentar l’ús directe de les API que existeixen per als diferents serveis en lloc d’utilitzar els connectors del framework de Canigó corresponents per a això. A causa d’això, aquesta guia servirà per generar un client Java per a l’API d’Antivirus existent mitjançant els fitxers d’especificació OpenApi.
Configuració Prèvia
Per utilitzar el plugin, és necessari seguir la guía de configuración general en este enllaç.
Generació del Client
Per implementar l’API d’Antivirus hem de generar els clients necessaris per poder utilitzar-los després als nostres projectes. Aquesta API consta de dos fitxers d’especificació que es poden descarregar des d’aquí.
Un cop els tinguem descarregats, generarem els dos clients corresponents. En el nostre exemple, farem servir Java com a llenguatge:
penapi-generator-cli generate -i 2669_API_REQUEST_TOKEN-1.0.0.json -g java --library webclient -o antivirus-token-webclient --package-name org.openapitools.tokenclient --api-package org.openapitools.tokenclient.api --model-package org.openapitools.tokenclient.model --additional-properties=useSpringBoot=true
openapi-generator-cli generate -i 2669_API_SCAN_FILE-1.0.2.json -g java --library webclient -o antiviruswebclient --additional-properties=useSpringBoot=true
El paràmetre –library fa referència a les llibreries HTTP que utilitzarà el client, en aquest cas, serà un client REST.
El paràmetre -o fa referència a la ruta d’eixida on generarà el client. En aquest exemple, també s’ha indicat que faci ús de Spring Boot.
Per generar clients amb altres opcions, pots consultar la documentació oficial del plugin als següents enllaços:
Importar el Client
Un cop generat el client, Compilem el projecte amb Maven mitjançant mvn clean install i importem la llibreria a la nostra aplicació.
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-java-tokenclient</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-java-client-antiviruswebclient</artifactId>
<version>1.0.0</version>
</dependency>
Ús del Client
Un cop importat el client, només ens quedaria utilitzar la llibreria al nostre projecte. A continuació mostrem un exemple en un projecte Java amb Spring Boot:
Controlador
import cat.gencat.service.antivirusOpenApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Optional;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class antivirusOpenApiController {
@Autowired
private antivirusOpenApiService antivirusopenapiService;
@Operation(summary = "Escaneja un fitxer amb l'antivirus",
description = "Escaneja un fitxer donat la seva ruta amb l'antivirus. \n" +
"\n Retorna el resultat de l'escaneig")
@PostMapping("/antivirusScanFile")
public ResponseEntity<String> scanFile (@RequestParam("filePath") String filePath){
try {
String scanResult = antivirusopenapiService.scanFile(filePath);
return new ResponseEntity<>(scanResult, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Service
import cat.gencat.manager.TokenSpeManager;
import cat.gencat.service.antivirusOpenApiService;
import lombok.RequiredArgsConstructor;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.DefaultApi;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
@Service
@RequiredArgsConstructor
public class antivirusOpenApiServiceImpl implements antivirusOpenApiService {
@Autowired
private TokenSpeManager tokenSpeManager;
@Override
public String scanFile(String filePath) {
//Invocamos a la API de antivirus
ApiClient defaultClient = new ApiClient();
defaultClient.setBasePath("https://preproduccio.ctti.apim.intranet.gencat.cat/ctti/privat-pre/2669/api-scan-file");
String tokenGicar = tokenSpeManager.getGicarToken();
String tokenSPE = tokenSpeManager.getValidSpeToken(tokenGicar);
defaultClient.addDefaultHeader("X-IBM-Client-Id", "your_IBM_client_id");
defaultClient.addDefaultHeader("Authorization-SPE", "Bearer " + tokenSPE);
defaultClient.addDefaultHeader("Authorization", "Bearer " + tokenGicar);
DefaultApi apiInstance = new DefaultApi(defaultClient);
//Se crea un File con el path recibido por parametro
File fileToScan = new File(filePath);
String result = "";
try{
result = apiInstance.scanFilePost(fileToScan).block();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
Token Manager
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.openapitools.tokenclient.api.DefaultApi;
import org.openapitools.tokenclient.ApiClient;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import java.time.Instant;
@Service
public class TokenSpeManager {
// Cached token and its expiry time
private String cachedToken;
private String cachedGicarToken;
private Instant tokenExpiry;
private Instant gicarTokenExpiry;
public String getValidSpeToken(String tokenGicar) {
if (cachedToken != null && Instant.now().isBefore(tokenExpiry)) {
return cachedToken; // ✅ valid token
}
// ✅ Token don't exist or expired → refresh
ApiClient defaultClient = new ApiClient();
defaultClient.addDefaultHeader("X-IBM-Client-Id", "your_IBM_client_id");
defaultClient.addDefaultHeader("Authorization", "Bearer " + tokenGicar);
DefaultApi apiInstance = new DefaultApi(defaultClient);
String result = "";
try{
result = apiInstance.authenticationPost().block();
} catch (Exception e) {
throw new RuntimeException(e);
}
ObjectMapper mapper = new ObjectMapper();
TokenSpeResponse speTokenResponse;
try {
speTokenResponse = mapper.readValue(result, TokenSpeResponse.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
cachedToken = speTokenResponse.getAccessToken();
tokenExpiry = Instant.ofEpochSecond(speTokenResponse.getExpiresAt()).minusSeconds(30);
// 30s less to avoid edge cases
return cachedToken;
}
public String getGicarToken() {
if (cachedGicarToken != null && Instant.now().isBefore(gicarTokenExpiry)) {
return cachedGicarToken; // ✅ valid token
}
// ✅ Token don't exist or expired → refresh
WebClient client = WebClient.builder()
.baseUrl("https://preproduccio.endpointma.autenticaciogicar4.extranet.gencat.cat")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.build();
TokenGicarResponse tokenGicar = client.post()
.uri("/realms/gicarcpd4/protocol/openid-connect/token")
.body(BodyInserters.fromFormData("client_id", "your_gicar_client_id")
.with("grant_type", "client_credentials")
.with("client_secret", "your_gicar_client_secret"))
.retrieve()
.bodyToMono(TokenGicarResponse.class).block();
cachedGicarToken = tokenGicar.getAccessToken();
gicarTokenExpiry = Instant.now().plusSeconds(tokenGicar.getExpiresIn() - 30);
// 30s less to avoid edge cases
return cachedGicarToken;
}
}
Classes auxiliars per a respostes de l’API
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class TokenSpeResponse {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("refresh_token")
private String refreshToken;
@JsonProperty("access_token_expiration_time")
private long expiresAt;
}
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class TokenGicarResponse {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("expires_in")
private long expiresIn;
@JsonProperty("refresh_expires_in")
private long refreshExpiresIn;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("not_before_policy")
private long notBeforePolicy;
@JsonProperty("scope")
private String scope;
}