Webhook configuration
-
Add Webhook config Object in your
/src/main/resources/application.yml
fileext:
api_key : "<api_key>"
api_secret : "<api_secret>"
base_url : "<base_url>"
access_mode : "online"
cluster: "https://api.fynd.com"
webhook:
api_path: "/ext/product-highlight-webhook"
notification_email: "[email protected]"
subscribed_saleschannel: "all"
event_map:
-
name: "article/update"
handler: priceUpdateHandler
category: "company"
version: 1 -
Create following helper classes for webhook handlers
/com/fynd/example/java/helper/models/WebhookEventResponse.javapackage com.fynd.example.java.helper.models;
import com.fasterxml.jackson.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.util.*;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"company_id",
"payload",
"event"
})
public class WebhookEventResponse {
@JsonProperty("event")
private EventResponse event;
@JsonProperty("payload")
private Object payload;
@JsonProperty("company_id")
private String companyId;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}/com/fynd/example/java/helper/models/ArticleUpdate.javapackage com.fynd.example.java.helper.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ArticleUpdate {
@JsonProperty("id")
private String id;
@JsonProperty("uid")
private String uid;
@JsonProperty("size")
private String size;
@JsonProperty("price")
private Price price;
@JsonProperty("item_id")
private Integer itemId;
}/com/fynd/example/java/helper/models/UpdateArticlePayload.javapackage com.fynd.example.java.helper.models;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UpdateArticlePayload {
@JsonProperty("articles")
private List<ArticleUpdate> articles;
} -
Now Create
PriceUpdateHandler
class inside a/com/fynd/example/java/webhook
package and add following codepackage com.fynd.example.java.webhook;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fynd.example.java.db.PriceDrop;
import com.fynd.example.java.db.ProductHighlight;
import com.fynd.example.java.db.interfaces.PriceDropRepository;
import com.fynd.example.java.db.interfaces.ProductHighlightRepository;
import com.fynd.example.java.helper.models.ArticleUpdate;
import com.fynd.example.java.helper.models.UpdateArticlePayload;
import com.fynd.example.java.helper.models.WebhookEventResponse;
import com.fynd.extension.middleware.EventHandler;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service("priceUpdateHandler")
public class PriceUpdateHandler implements EventHandler {
private static final Logger log = LoggerFactory.getLogger(PriceUpdateHandler.class);
@Autowired
ObjectMapper objectMapper;
@Autowired
ProductHighlightRepository productHighlightRepository;
@Autowired
PriceDropRepository priceDropRepository;
@SneakyThrows
@Override
public void handle(String eventName, Object body, String companyId, String applicationId) {
log.info("Event Received : {} for companyId : {}", eventName, companyId);
WebhookEventResponse webhookEventResponse
= objectMapper.readValue(body.toString(), WebhookEventResponse.class);
UpdateArticlePayload payload
= objectMapper.convertValue(webhookEventResponse.getPayload(), UpdateArticlePayload.class);
if (payload.getArticles().isEmpty()) {
return;
}
for (ArticleUpdate article : payload.getArticles()) {
Optional<ProductHighlight> data
= productHighlightRepository.findOneByCompanyIdAndProductItemCode(companyId, article.getItemId());
if (data.isPresent() && ObjectUtils.isNotEmpty(data.get().getProduct().getPrice()) ) {
ProductHighlight productHighlight = data.get();
Integer previousPrice = productHighlight.getProduct().getPrice().getEffective().getMax();
Integer newPrice = article.getPrice().getEffective().getMax();
if (previousPrice != newPrice) {
if (newPrice < previousPrice) {
PriceDrop priceDrop = new PriceDrop();
priceDrop.setProductSlug(productHighlight.getProductSlug());
priceDropRepository.save(priceDrop);
}
}
productHighlight.getProduct().getPrice().getEffective().setMax(newPrice);
productHighlight.getProduct().getPrice().getEffective().setMin(newPrice);
productHighlightRepository.save(productHighlight);
}
}
}
} -
We'll need to create one POST API for listening to Webhook Event.
-
Update the
/com/fynd/example/java/controller/WebhookController.java
filepackage com.fynd.example.java.controller;
import com.fynd.extension.service.WebhookService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
@RestController
public class WebhookController {
@Autowired
WebhookService webhookService;
@PostMapping(path = "/ext/product-highlight-webhook")
public ResponseEntity<Object> receiveWebhookEvents(HttpServletRequest httpServletRequest) {
try {
webhookService.processWebhook(httpServletRequest);
return new ResponseEntity<>(Collections.singletonMap("success", true), HttpStatus.OK);
} catch (Exception e) {
System.out.println(e);
return new ResponseEntity<>(Collections.singletonMap("success", false), HttpStatus.BAD_REQUEST);
}
}
}
Now Restart the Extension Server and Relaunch the Extension
You can test if Webhook is working or not by updating the price for one of the products for which you have checked enabled price drop from the Extension. Make sure the tunnel and Extension Server keeps running.
Update the price of the product from the Platform Panel
Products > All Products > Search Product by slug > Edit Inventory
Decrease the selling price of the product After waiting for some time visit the PDP of the same product. You should be able to see the Price Drop tag below the price components
At Last, We will need to handle the Uninstall event of the Extension
open /com/fynd/example/java/ExampleJavaApplication.java
file, and add the following code to the uninstall
callback function
package com.fynd.example.java;
import com.fynd.example.java.db.ProductHighlight;
import com.fynd.example.java.db.interfaces.ProductHighlightRepository;
import com.fynd.example.java.db.interfaces.ProxyRepository;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import com.fynd.extension.model.Extension;
import com.fynd.extension.model.ExtensionCallback;
import com.fynd.extension.model.ExtensionProperties;
import com.fynd.extension.session.Session;
import com.fynd.extension.storage.RedisStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import redis.clients.jedis.JedisPool;
import java.util.List;
@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.fynd.**","com.gofynd","com.sdk.**"})
@EnableMongoRepositories(basePackages = {"com.fynd.example.java.db.interfaces"})
@EntityScan({"com.fynd.example.java.db"})
public class ExampleJavaApplication {
private static final String REDIS_KEY = "ext_sample";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
ExtensionProperties extensionProperties;
@Autowired
ProductHighlightRepository productHighlightRepository;
@Autowired
ProxyRepository proxyRepository;
@Autowired
@Qualifier("redis-pool")
JedisPool jedis;
ExtensionCallback callbacks = new ExtensionCallback((request) -> {
Session fdkSession = (Session) request.getAttribute("session");
logger.info("In Auth callback");
return extensionProperties.getBaseUrl() + "/company/" + fdkSession.getCompanyId();
}, (context) -> {
logger.info("In install callback");
return extensionProperties.getBaseUrl();
}, (request) -> {
logger.info("In uninstall callback");
Session fdkSession = (Session) request.getAttribute("session");
String companyId = fdkSession.getCompanyId();
List<ProductHighlight> productHighlightList = productHighlightRepository.findByCompanyIdAndIsActive(companyId);
for (ProductHighlight productHighlight: productHighlightList) {
productHighlight.setIsActive(false);
}
productHighlightRepository.saveAll(productHighlightList);
proxyRepository.deleteByCompanyId(companyId);
return extensionProperties.getBaseUrl();
}, (fdkSession) -> {
logger.info("In auto-install callback");
return extensionProperties.getBaseUrl();
});
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(ExampleJavaApplication.class, args);
}
@Bean
@DependsOn({"redis-pool"})
public com.fynd.extension.model.Extension getExtension() {
Extension extension = new Extension();
return extension.initialize(
extensionProperties,
new RedisStorage(jedis, REDIS_KEY),
callbacks
);
}
}