Refactor PrestashopClient and PrestashopProxyController for improved error handling and response management
This commit is contained in:
@@ -16,92 +16,70 @@ public class PrestashopProxyController {
|
|||||||
this.prestashopClient = prestashopClient;
|
this.prestashopClient = prestashopClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Utilitaire pour extraire /products, /products/446, etc.
|
||||||
* Extrait le path Presta à partir de la requête entrante.
|
|
||||||
* Exemple :
|
|
||||||
* - requestURI = /api/ps/products/446
|
|
||||||
* - retourne /products/446
|
|
||||||
*/
|
|
||||||
private String extractPath(HttpServletRequest request) {
|
private String extractPath(HttpServletRequest request) {
|
||||||
String fullPath = request.getRequestURI(); // ex: /api/ps/products/446
|
String fullPath = request.getRequestURI(); // ex: /api/ps/products/446
|
||||||
String contextPath = request.getContextPath(); // souvent ""
|
String contextPath = request.getContextPath(); // souvent ""
|
||||||
String relative = fullPath.substring(contextPath.length()); // /api/ps/products/446
|
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("/**")
|
@GetMapping("/**")
|
||||||
public ResponseEntity<String> proxyGet(HttpServletRequest request) {
|
public ResponseEntity<String> proxyGet(HttpServletRequest request) {
|
||||||
String path = extractPath(request);
|
String path = extractPath(request);
|
||||||
String query = request.getQueryString(); // ex: display=full&filter[id_product]=123
|
String query = request.getQueryString(); // on laisse tel quel
|
||||||
|
|
||||||
String body = prestashopClient.get(path, query);
|
String body = prestashopClient.get(path, query);
|
||||||
|
|
||||||
// On sait qu'on force output_format=JSON côté client.get(...)
|
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.ok()
|
.ok()
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.body(body);
|
.body(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- POST ----------
|
/* ---------------- POST ---------------- */
|
||||||
|
|
||||||
@PostMapping("/**")
|
@PostMapping("/**")
|
||||||
public ResponseEntity<String> proxyPost(
|
public ResponseEntity<String> proxyPost(HttpServletRequest request,
|
||||||
HttpServletRequest request,
|
@RequestBody String xmlBody) {
|
||||||
@RequestBody String bodyFromFront
|
|
||||||
) {
|
|
||||||
String path = extractPath(request);
|
String path = extractPath(request);
|
||||||
String query = request.getQueryString();
|
String query = request.getQueryString();
|
||||||
|
|
||||||
String body = prestashopClient.post(path, query, bodyFromFront);
|
String responseBody = prestashopClient.post(path, query, xmlBody);
|
||||||
|
|
||||||
// Si Angular demande output_format=JSON dans la query, on peut renvoyer JSON,
|
|
||||||
// sinon ce sera typiquement du XML. Dans tous les cas on renvoie le raw body.
|
|
||||||
MediaType mediaType = (query != null && query.contains("output_format=JSON"))
|
|
||||||
? MediaType.APPLICATION_JSON
|
|
||||||
: MediaType.APPLICATION_XML;
|
|
||||||
|
|
||||||
|
// Presta peut renvoyer JSON ou XML, mais côté front tu traites en JSON
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.ok()
|
.ok()
|
||||||
.contentType(mediaType)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.body(body);
|
.body(responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- PUT ----------
|
/* ---------------- PUT ---------------- */
|
||||||
|
|
||||||
@PutMapping("/**")
|
@PutMapping("/**")
|
||||||
public ResponseEntity<String> proxyPut(
|
public ResponseEntity<String> proxyPut(HttpServletRequest request,
|
||||||
HttpServletRequest request,
|
@RequestBody String xmlBody) {
|
||||||
@RequestBody String bodyFromFront
|
|
||||||
) {
|
|
||||||
String path = extractPath(request);
|
String path = extractPath(request);
|
||||||
String query = request.getQueryString();
|
String query = request.getQueryString();
|
||||||
|
|
||||||
String body = prestashopClient.put(path, query, bodyFromFront);
|
String responseBody = prestashopClient.put(path, query, xmlBody);
|
||||||
|
|
||||||
MediaType mediaType = (query != null && query.contains("output_format=JSON"))
|
|
||||||
? MediaType.APPLICATION_JSON
|
|
||||||
: MediaType.APPLICATION_XML;
|
|
||||||
|
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.ok()
|
.ok()
|
||||||
.contentType(mediaType)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.body(body);
|
.body(responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- DELETE ----------
|
/* ---------------- DELETE ---------------- */
|
||||||
|
|
||||||
@DeleteMapping("/**")
|
@DeleteMapping("/**")
|
||||||
public ResponseEntity<Void> proxyDelete(HttpServletRequest request) {
|
public ResponseEntity<String> proxyDelete(HttpServletRequest request) {
|
||||||
String path = extractPath(request);
|
String path = extractPath(request);
|
||||||
String query = request.getQueryString();
|
String query = request.getQueryString();
|
||||||
|
|
||||||
prestashopClient.delete(path, query);
|
String responseBody = prestashopClient.delete(path, query);
|
||||||
|
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity
|
||||||
|
.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(responseBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.HttpStatusCodeException;
|
||||||
import org.springframework.web.client.RestClientException;
|
import org.springframework.web.client.RestClientException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
@@ -29,50 +30,49 @@ public class PrestashopClient {
|
|||||||
this.basicAuth = basicAuth;
|
this.basicAuth = basicAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------
|
||||||
* Construit l'URL finale vers PrestaShop en propageant la query d'origine.
|
* Helpers communs
|
||||||
*
|
* ------------------------------------------------------------------ */
|
||||||
* @param path ex: "/products", "/products/446"
|
|
||||||
* @param query queryString brute reçue côté API (peut être null)
|
private HttpHeaders baseHeaders() {
|
||||||
* @param addDefaultFormatAndDisplay si true, ajoute output_format=JSON et display=full
|
HttpHeaders headers = new HttpHeaders();
|
||||||
*/
|
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
|
||||||
private String buildUrl(String path, String query, boolean addDefaultFormatAndDisplay) {
|
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);
|
||||||
|
|
||||||
UriComponentsBuilder builder = UriComponentsBuilder
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
.fromHttpUrl(baseUrl)
|
.fromHttpUrl(baseUrl)
|
||||||
.path("/api")
|
.path("/api")
|
||||||
.path(path);
|
.path(normalizedPath);
|
||||||
|
|
||||||
// On propage TOUT ce que le front a mis (display, filter[...], etc.)
|
|
||||||
if (query != null && !query.isBlank()) {
|
if (query != null && !query.isBlank()) {
|
||||||
builder.query(query);
|
builder.query(query); // on garde tous les filtres venus du front
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addDefaultFormatAndDisplay) {
|
// on force ces deux-là pour corriger les soucis des crochets + id seuls
|
||||||
// Si le front n'a pas mis output_format, on force JSON
|
builder.replaceQueryParam("output_format", "JSON");
|
||||||
if (query == null || !query.contains("output_format=")) {
|
builder.replaceQueryParam("display", "full");
|
||||||
builder.queryParam("output_format", "JSON");
|
|
||||||
}
|
|
||||||
// Si le front n'a pas mis display, on force full
|
|
||||||
if (query == null || !query.contains("display=")) {
|
|
||||||
builder.queryParam("display", "full");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build(true).toUriString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET générique vers PrestaShop.
|
|
||||||
* - Propage la queryString Angular (display, filter[...], etc.)
|
|
||||||
* - Ajoute output_format=JSON & display=full si absents.
|
|
||||||
*/
|
|
||||||
public String get(String path, String query) {
|
|
||||||
String url = buildUrl(path, query, true);
|
|
||||||
|
|
||||||
|
String url = builder.build(true).toUriString();
|
||||||
log.info("[PrestaShop] GET {}", url);
|
log.info("[PrestaShop] GET {}", url);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = baseHeaders();
|
||||||
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
|
|
||||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
||||||
@@ -85,34 +85,50 @@ public class PrestashopClient {
|
|||||||
String.class
|
String.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log.info("[PrestaShop] Réponse GET {} pour {}", response.getStatusCode(), url);
|
||||||
|
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("PrestaShop returned non-2xx status on GET: "
|
throw new RuntimeException("PrestaShop returned non-2xx status: "
|
||||||
+ response.getStatusCode() + " for URL " + url);
|
+ response.getStatusCode() + " for URL " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.getBody();
|
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) {
|
} catch (RestClientException e) {
|
||||||
log.error("[PrestaShop] Erreur GET {}", url, e);
|
log.error("[PrestaShop] Erreur GET {}", url, e);
|
||||||
throw new RuntimeException("Erreur GET PrestaShop", e);
|
throw new RuntimeException("Erreur GET PrestaShop", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------
|
||||||
* POST générique vers PrestaShop.
|
* POST : XML vers Presta
|
||||||
* On propage la query telle quelle (si Angular met output_format=JSON, etc.).
|
* - on transmet la query EXACTE venant du front (price[use_tax], filter, etc.)
|
||||||
* Le body est du XML (templates construits côté Angular).
|
* - PAS de output_format / display forcés ici
|
||||||
*/
|
* ------------------------------------------------------------------ */
|
||||||
public String post(String path, String query, String body) {
|
public String post(String path, String query, String xmlBody) {
|
||||||
String url = buildUrl(path, query, false);
|
String normalizedPath = normalizePath(path);
|
||||||
|
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
|
.fromHttpUrl(baseUrl)
|
||||||
|
.path("/api")
|
||||||
|
.path(normalizedPath);
|
||||||
|
|
||||||
|
if (query != null && !query.isBlank()) {
|
||||||
|
builder.query(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = builder.build(true).toUriString();
|
||||||
log.info("[PrestaShop] POST {}", url);
|
log.info("[PrestaShop] POST {}", url);
|
||||||
|
log.debug("[PrestaShop] POST body=\n{}", xmlBody);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = baseHeaders();
|
||||||
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
|
headers.setContentType(MediaType.APPLICATION_XML); // Presta attend du XML sur POST/PUT
|
||||||
headers.setContentType(MediaType.APPLICATION_XML);
|
|
||||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
|
||||||
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(body, headers);
|
HttpEntity<String> entity = new HttpEntity<>(xmlBody, headers);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ResponseEntity<String> response = restTemplate.exchange(
|
ResponseEntity<String> response = restTemplate.exchange(
|
||||||
@@ -122,34 +138,50 @@ public class PrestashopClient {
|
|||||||
String.class
|
String.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log.info("[PrestaShop] Réponse POST {} pour {}", response.getStatusCode(), url);
|
||||||
|
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("PrestaShop returned non-2xx status on POST: "
|
throw new RuntimeException("PrestaShop returned non-2xx status: "
|
||||||
+ response.getStatusCode() + " for URL " + url
|
+ response.getStatusCode() + " for URL " + url
|
||||||
+ " - response: " + response.getBody());
|
+ " body=" + response.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.getBody();
|
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) {
|
} catch (RestClientException e) {
|
||||||
log.error("[PrestaShop] Erreur POST {}", url, e);
|
log.error("[PrestaShop] Erreur POST {}", url, e);
|
||||||
throw new RuntimeException("Erreur POST PrestaShop", e);
|
throw new RuntimeException("Erreur POST PrestaShop", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------
|
||||||
* PUT générique vers PrestaShop.
|
* PUT : XML vers Presta
|
||||||
* Le body est du XML (templates construits côté Angular).
|
* - pareil que POST : on garde la query telle quelle, pas de display=full ici
|
||||||
*/
|
* ------------------------------------------------------------------ */
|
||||||
public String put(String path, String query, String body) {
|
public String put(String path, String query, String xmlBody) {
|
||||||
String url = buildUrl(path, query, false);
|
String normalizedPath = normalizePath(path);
|
||||||
|
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
|
.fromHttpUrl(baseUrl)
|
||||||
|
.path("/api")
|
||||||
|
.path(normalizedPath);
|
||||||
|
|
||||||
|
if (query != null && !query.isBlank()) {
|
||||||
|
builder.query(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = builder.build(true).toUriString();
|
||||||
log.info("[PrestaShop] PUT {}", url);
|
log.info("[PrestaShop] PUT {}", url);
|
||||||
|
log.debug("[PrestaShop] PUT body=\n{}", xmlBody);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = baseHeaders();
|
||||||
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
|
|
||||||
headers.setContentType(MediaType.APPLICATION_XML);
|
headers.setContentType(MediaType.APPLICATION_XML);
|
||||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
|
||||||
|
|
||||||
HttpEntity<String> entity = new HttpEntity<>(body, headers);
|
HttpEntity<String> entity = new HttpEntity<>(xmlBody, headers);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ResponseEntity<String> response = restTemplate.exchange(
|
ResponseEntity<String> response = restTemplate.exchange(
|
||||||
@@ -159,29 +191,46 @@ public class PrestashopClient {
|
|||||||
String.class
|
String.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log.info("[PrestaShop] Réponse PUT {} pour {}", response.getStatusCode(), url);
|
||||||
|
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("PrestaShop returned non-2xx status on PUT: "
|
throw new RuntimeException("PrestaShop returned non-2xx status: "
|
||||||
+ response.getStatusCode() + " for URL " + url
|
+ response.getStatusCode() + " for URL " + url
|
||||||
+ " - response: " + response.getBody());
|
+ " body=" + response.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.getBody();
|
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) {
|
} catch (RestClientException e) {
|
||||||
log.error("[PrestaShop] Erreur PUT {}", url, e);
|
log.error("[PrestaShop] Erreur PUT {}", url, e);
|
||||||
throw new RuntimeException("Erreur PUT PrestaShop", e);
|
throw new RuntimeException("Erreur PUT PrestaShop", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* ------------------------------------------------------------------
|
||||||
* DELETE générique vers PrestaShop.
|
* DELETE
|
||||||
*/
|
* - idem : on relaie la query telle quelle
|
||||||
public void delete(String path, String query) {
|
* ------------------------------------------------------------------ */
|
||||||
String url = buildUrl(path, query, false);
|
public String delete(String path, String query) {
|
||||||
|
String normalizedPath = normalizePath(path);
|
||||||
|
|
||||||
|
UriComponentsBuilder builder = UriComponentsBuilder
|
||||||
|
.fromHttpUrl(baseUrl)
|
||||||
|
.path("/api")
|
||||||
|
.path(normalizedPath);
|
||||||
|
|
||||||
|
if (query != null && !query.isBlank()) {
|
||||||
|
builder.query(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = builder.build(true).toUriString();
|
||||||
log.info("[PrestaShop] DELETE {}", url);
|
log.info("[PrestaShop] DELETE {}", url);
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = baseHeaders();
|
||||||
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth);
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML));
|
||||||
|
|
||||||
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
@@ -193,11 +242,19 @@ public class PrestashopClient {
|
|||||||
String.class
|
String.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log.info("[PrestaShop] Réponse DELETE {} pour {}", response.getStatusCode(), url);
|
||||||
|
|
||||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
throw new RuntimeException("PrestaShop returned non-2xx status on DELETE: "
|
throw new RuntimeException("PrestaShop returned non-2xx status: "
|
||||||
+ response.getStatusCode() + " for URL " + url
|
+ response.getStatusCode() + " for URL " + url
|
||||||
+ " - response: " + response.getBody());
|
+ " body=" + response.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
} catch (RestClientException e) {
|
||||||
log.error("[PrestaShop] Erreur DELETE {}", url, e);
|
log.error("[PrestaShop] Erreur DELETE {}", url, e);
|
||||||
throw new RuntimeException("Erreur DELETE PrestaShop", e);
|
throw new RuntimeException("Erreur DELETE PrestaShop", e);
|
||||||
|
|||||||
Reference in New Issue
Block a user