What's the best way to implement prototype patterns in Zapier integrations?

I’m building a custom integration with Zapier and running into some code duplication issues. My polling functions are getting really messy because I keep writing similar code blocks for different data fields.

Right now, I have these long functions that make API calls to fetch additional details for each record. The problem is that I’m basically copying the same pattern over and over for different endpoints. I want to clean this up using JavaScript prototypes so I can reuse the same logic.

Here’s what one of my current functions looks like:

var MyApp = {
    product_data_poll: function(bundle) {
        var apiResults = JSON.parse(bundle.response.content);
        apiResults.items.reverse();
        
        // fetch product details
        var detailRequest = {
            'url': "api.example.com/v1/" + bundle.auth_fields.company_id + 
                "/products/details(id='" + apiResults.items[i].product_id + "')?format=json",
            'headers': {
                "Authorization": "Bearer " + btoa(bundle.auth_fields.api_key + ':' + bundle.auth_fields.secret)
            },
            'method': "GET"
        };
        var detailResponse = z.request(detailRequest);
        
        try {
            var parsedDetails = JSON.parse(detailResponse.content);
            apiResults.items[i].product_title = parsedDetails.Name;
        } catch(err) {
            console.log(err);
            apiResults.items[i].product_title = apiResults.items[i].product_id;
        }
        
        return apiResults;
    }
};

How can I set up a prototype system to avoid repeating this pattern for every different attribute I need to fetch?

One approach that might work better for your specific Zapier use case is using a mixin pattern instead of traditional prototypes. I ran into similar issues with my integration and found that creating a shared enhancement object worked well.

You could create something like DetailEnhancer that contains your common request logic, then mix it into your polling functions. The benefit is you can define field-specific configurations without the overhead of prototype chains. For example, define your API patterns once and pass field mappings as configuration objects.

The main thing I learned is that Zapier’s execution environment can be finicky with complex prototype inheritance, so keeping it simple with functional mixins or composition tends to be more reliable than deep prototype chains. Your current structure suggests you might benefit more from extracting the request logic into a separate utility function that your polling methods can call with different parameters.

I had similar issues when building my Zapier integration last year. The key is creating a base fetcher prototype that handles the common request pattern, then extending it for specific use cases.

Here’s what worked for me:

function BaseFetcher(bundle) {
    this.bundle = bundle;
    this.baseUrl = "api.example.com/v1/" + bundle.auth_fields.company_id;
    this.headers = {
        "Authorization": "Bearer " + btoa(bundle.auth_fields.api_key + ':' + bundle.auth_fields.secret)
    };
}

BaseFetcher.prototype.fetchDetails = function(endpoint, itemId, mapping) {
    var request = {
        'url': this.baseUrl + endpoint + itemId + "')?format=json",
        'headers': this.headers,
        'method': "GET"
    };
    
    try {
        var response = z.request(request);
        var parsed = JSON.parse(response.content);
        return mapping(parsed);
    } catch(err) {
        console.log(err);
        return null;
    }
};

Then you can create specific fetchers that inherit from this base and just define their own mapping functions. This eliminated about 70% of my duplicate code and made debugging much easier.

honestly your code looks like it needs some refactoring beyond just prototypes. i’d suggest making a generic detail enricher function that takes endpoint config as params instead of hardcoding everything. something like enrichItems(items, {endpoint: '/products/details', idField: 'product_id', mapping: {...}}) might be cleaner than prototype inheritance here tbh