Skip to main content

Webhook configuration

  • Add Webhook config Object in your /src/main/resources/application.yml file

    ext:
    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.java
    package 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.java
    package 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.java
    package 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 code

    package 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 file

    package 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

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

price drop tag on sales channel

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
);
}
}