Refactor PrestashopClient and PrestashopProxyController to improve query handling and enhance code clarity

This commit is contained in:
Vincent Guillet
2025-11-26 14:25:25 +01:00
parent f4696b5f5b
commit f9a9e81713
2 changed files with 104 additions and 121 deletions

View File

@@ -16,21 +16,25 @@ public class PrestashopProxyController {
this.prestashopClient = prestashopClient;
}
// Utilitaire pour extraire /products, /products/446, etc.
private String extractPath(HttpServletRequest request) {
String fullPath = request.getRequestURI(); // ex: /api/ps/products/446
String contextPath = request.getContextPath(); // souvent ""
String relative = fullPath.substring(contextPath.length()); // /api/ps/products/446
return relative.replaceFirst("^/api/ps", ""); // => /products/446
// On enlève le préfixe /api/ps => /products/446
return relative.replaceFirst("^/api/ps", "");
}
/* ---------------- GET ---------------- */
/* ===========================
* GET
* =========================== */
@GetMapping("/**")
public ResponseEntity<String> proxyGet(HttpServletRequest request) {
String path = extractPath(request);
String query = request.getQueryString(); // on laisse tel quel
String rawQuery = request.getQueryString(); // on laisse Angular décider des filtres
String body = prestashopClient.get(path, query);
String body = prestashopClient.get(path, rawQuery);
return ResponseEntity
.ok()
@@ -38,48 +42,60 @@ public class PrestashopProxyController {
.body(body);
}
/* ---------------- POST ---------------- */
/* ===========================
* POST
* =========================== */
@PostMapping("/**")
public ResponseEntity<String> proxyPost(HttpServletRequest request,
@RequestBody String xmlBody) {
public ResponseEntity<String> proxyPost(
HttpServletRequest request,
@RequestBody String rawBody
) {
String path = extractPath(request);
String query = request.getQueryString();
String rawQuery = request.getQueryString();
String responseBody = prestashopClient.post(path, query, xmlBody);
String body = prestashopClient.post(path, rawQuery, rawBody);
// Presta peut renvoyer JSON ou XML, mais côté front tu traites en JSON
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(responseBody);
.body(body);
}
/* ---------------- PUT ---------------- */
/* ===========================
* PUT
* =========================== */
@PutMapping("/**")
public ResponseEntity<String> proxyPut(HttpServletRequest request,
@RequestBody String xmlBody) {
public ResponseEntity<String> proxyPut(
HttpServletRequest request,
@RequestBody String rawBody
) {
String path = extractPath(request);
String query = request.getQueryString();
String rawQuery = request.getQueryString();
String responseBody = prestashopClient.put(path, query, xmlBody);
String body = prestashopClient.put(path, rawQuery, rawBody);
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(responseBody);
.body(body);
}
/* ---------------- DELETE ---------------- */
/* ===========================
* DELETE
* =========================== */
@DeleteMapping("/**")
public ResponseEntity<String> proxyDelete(HttpServletRequest request) {
String path = extractPath(request);
String query = request.getQueryString();
String rawQuery = request.getQueryString();
String responseBody = prestashopClient.delete(path, query);
String body = prestashopClient.delete(path, rawQuery);
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(responseBody);
.body(body);
}
}

View File

@@ -4,14 +4,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
@Service
public class PrestashopClient {
@@ -30,50 +28,37 @@ public class PrestashopClient {
this.basicAuth = basicAuth;
}
/* ------------------------------------------------------------------
* Helpers communs
* ------------------------------------------------------------------ */
private HttpHeaders baseHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
return headers;
}
private String normalizePath(String path) {
if (path == null || path.isBlank()) {
return "/";
}
return path.startsWith("/") ? path : "/" + path;
}
/* ------------------------------------------------------------------
* GET : force JSON + display=full
* - on garde tous les autres paramètres (filter[..], limit, etc.)
* - on écrase/normalise seulement output_format et display
* => équivalent à ce que tu faisais en front avec output_format=JSON&display=full
* ------------------------------------------------------------------ */
public String get(String path, String query) {
String normalizedPath = normalizePath(path);
/* ===========================
* GET (proxy)
* =========================== */
/**
* GET générique vers PrestaShop.
*
* - On part de la query envoyée par le front (filters, price[use_tax], ...).
* - On force/se remplace uniquement output_format=JSON et display=full.
*/
public String get(String path, @Nullable String rawQuery) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(baseUrl)
.path("/api")
.path(normalizedPath);
.path(path);
if (query != null && !query.isBlank()) {
builder.query(query); // on garde tous les filtres venus du front
// On remet la query EXACTEMENT comme envoyée par Angular
if (rawQuery != null && !rawQuery.isBlank()) {
builder.query(rawQuery);
}
// on force ces deux-là pour corriger les soucis des crochets + id seuls
// On force juste ces deux paramètres
builder.replaceQueryParam("output_format", "JSON");
builder.replaceQueryParam("display", "full");
String url = builder.build(true).toUriString();
log.info("[PrestaShop] GET {}", url);
HttpHeaders headers = baseHeaders();
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
HttpEntity<Void> entity = new HttpEntity<>(headers);
@@ -85,7 +70,7 @@ public class PrestashopClient {
String.class
);
log.info("[PrestaShop] Réponse GET {} pour {}", response.getStatusCode(), url);
log.info("[PrestaShop] Réponse HTTP {} pour {}", response.getStatusCode(), url);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("PrestaShop returned non-2xx status: "
@@ -93,42 +78,38 @@ public class PrestashopClient {
}
return response.getBody();
} catch (HttpStatusCodeException e) {
log.error("[PrestaShop] Erreur GET {} status={} body={}",
url, e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RuntimeException("Erreur GET PrestaShop", e);
} catch (RestClientException e) {
log.error("[PrestaShop] Erreur GET {}", url, e);
throw new RuntimeException("Erreur GET PrestaShop", e);
}
}
/* ------------------------------------------------------------------
* POST : XML vers Presta
* - on transmet la query EXACTE venant du front (price[use_tax], filter, etc.)
* - PAS de output_format / display forcés ici
* ------------------------------------------------------------------ */
public String post(String path, String query, String xmlBody) {
String normalizedPath = normalizePath(path);
/* ===========================
* POST
* =========================== */
public String post(String path, @Nullable String rawQuery, String body) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(baseUrl)
.path("/api")
.path(normalizedPath);
.path(path);
if (query != null && !query.isBlank()) {
builder.query(query);
if (rawQuery != null && !rawQuery.isBlank()) {
builder.query(rawQuery);
}
// Pour POST, tu peux choisir de forcer output_format si tu veux la réponse en JSON
builder.replaceQueryParam("output_format", "JSON");
String url = builder.build(true).toUriString();
log.info("[PrestaShop] POST {}", url);
log.debug("[PrestaShop] POST body=\n{}", xmlBody);
HttpHeaders headers = baseHeaders();
headers.setContentType(MediaType.APPLICATION_XML); // Presta attend du XML sur POST/PUT
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
headers.setContentType(MediaType.APPLICATION_XML); // Presta attend du XML
HttpEntity<String> entity = new HttpEntity<>(xmlBody, headers);
HttpEntity<String> entity = new HttpEntity<>(body, headers);
try {
ResponseEntity<String> response = restTemplate.exchange(
@@ -138,50 +119,45 @@ public class PrestashopClient {
String.class
);
log.info("[PrestaShop] Réponse POST {} pour {}", response.getStatusCode(), url);
log.info("[PrestaShop] Réponse HTTP {} pour {}", response.getStatusCode(), url);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("PrestaShop returned non-2xx status: "
+ response.getStatusCode() + " for URL " + url
+ " body=" + response.getBody());
+ response.getStatusCode() + " for URL " + url);
}
return response.getBody();
} catch (HttpStatusCodeException e) {
log.error("[PrestaShop] Erreur POST {} status={} body={}",
url, e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RuntimeException("Erreur POST PrestaShop", e);
} catch (RestClientException e) {
log.error("[PrestaShop] Erreur POST {}", url, e);
throw new RuntimeException("Erreur POST PrestaShop", e);
}
}
/* ------------------------------------------------------------------
* PUT : XML vers Presta
* - pareil que POST : on garde la query telle quelle, pas de display=full ici
* ------------------------------------------------------------------ */
public String put(String path, String query, String xmlBody) {
String normalizedPath = normalizePath(path);
/* ===========================
* PUT
* =========================== */
public String put(String path, @Nullable String rawQuery, String body) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(baseUrl)
.path("/api")
.path(normalizedPath);
.path(path);
if (query != null && !query.isBlank()) {
builder.query(query);
if (rawQuery != null && !rawQuery.isBlank()) {
builder.query(rawQuery);
}
builder.replaceQueryParam("output_format", "JSON");
String url = builder.build(true).toUriString();
log.info("[PrestaShop] PUT {}", url);
log.debug("[PrestaShop] PUT body=\n{}", xmlBody);
HttpHeaders headers = baseHeaders();
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
HttpEntity<String> entity = new HttpEntity<>(xmlBody, headers);
HttpEntity<String> entity = new HttpEntity<>(body, headers);
try {
ResponseEntity<String> response = restTemplate.exchange(
@@ -191,46 +167,42 @@ public class PrestashopClient {
String.class
);
log.info("[PrestaShop] Réponse PUT {} pour {}", response.getStatusCode(), url);
log.info("[PrestaShop] Réponse HTTP {} pour {}", response.getStatusCode(), url);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("PrestaShop returned non-2xx status: "
+ response.getStatusCode() + " for URL " + url
+ " body=" + response.getBody());
+ response.getStatusCode() + " for URL " + url);
}
return response.getBody();
} catch (HttpStatusCodeException e) {
log.error("[PrestaShop] Erreur PUT {} status={} body={}",
url, e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RuntimeException("Erreur PUT PrestaShop", e);
} catch (RestClientException e) {
log.error("[PrestaShop] Erreur PUT {}", url, e);
throw new RuntimeException("Erreur PUT PrestaShop", e);
}
}
/* ------------------------------------------------------------------
/* ===========================
* DELETE
* - idem : on relaie la query telle quelle
* ------------------------------------------------------------------ */
public String delete(String path, String query) {
String normalizedPath = normalizePath(path);
* =========================== */
public String delete(String path, @Nullable String rawQuery) {
UriComponentsBuilder builder = UriComponentsBuilder
.fromHttpUrl(baseUrl)
.path("/api")
.path(normalizedPath);
.path(path);
if (query != null && !query.isBlank()) {
builder.query(query);
if (rawQuery != null && !rawQuery.isBlank()) {
builder.query(rawQuery);
}
builder.replaceQueryParam("output_format", "JSON");
String url = builder.build(true).toUriString();
log.info("[PrestaShop] DELETE {}", url);
HttpHeaders headers = baseHeaders();
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
HttpEntity<Void> entity = new HttpEntity<>(headers);
@@ -242,19 +214,14 @@ public class PrestashopClient {
String.class
);
log.info("[PrestaShop] Réponse DELETE {} pour {}", response.getStatusCode(), url);
log.info("[PrestaShop] Réponse HTTP {} pour {}", response.getStatusCode(), url);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("PrestaShop returned non-2xx status: "
+ response.getStatusCode() + " for URL " + url
+ " body=" + response.getBody());
+ response.getStatusCode() + " for URL " + url);
}
return response.getBody();
} catch (HttpStatusCodeException e) {
log.error("[PrestaShop] Erreur DELETE {} status={} body={}",
url, e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new RuntimeException("Erreur DELETE PrestaShop", e);
} catch (RestClientException e) {
log.error("[PrestaShop] Erreur DELETE {}", url, e);
throw new RuntimeException("Erreur DELETE PrestaShop", e);