tpalfy commented on code in PR #6303:
URL: https://github.com/apache/nifi/pull/6303#discussion_r966071399


##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/GetShopify.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.PrimaryNodeOnly;
+import org.apache.nifi.annotation.behavior.Stateful;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.Scope;
+import org.apache.nifi.components.state.StateMap;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.io.OutputStreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.shopify.model.IncrementalLoadingParameter;
+import org.apache.nifi.processors.shopify.model.ResourceDirectory;
+import org.apache.nifi.processors.shopify.model.ResourceType;
+import org.apache.nifi.processors.shopify.model.ShopifyResource;
+import org.apache.nifi.processors.shopify.rest.ShopifyRestService;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+@PrimaryNodeOnly
+@TriggerSerially
+@TriggerWhenEmpty

Review Comment:
   `@TriggerWhenEmpty` shouldn't be necessary as input is forbidden.
   



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/model/ResourceType.java:
##########
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify.model;
+
+import org.apache.nifi.components.AllowableValue;
+import org.apache.nifi.components.DescribedValue;
+
+public enum ResourceType implements DescribedValue {

Review Comment:
   ```suggestion
   public enum ResourceType implements DescribedValue {
   
       CUSTOMERS("Customers", "Query a Customer resource", "Customer Resource", 
"Customer resource to query", ResourceDirectory.CUSTOMER_RESOURCES),
       DISCOUNTS("Discounts", "Query a Discount resource", "Discount Resource", 
"Discount resource to query", ResourceDirectory.DISCOUNT_RESOURCES),
       INVENTORY("Inventory", "Query an Inventory resource", "Inventory 
Resource", "Inventory resource to query", 
ResourceDirectory.INVENTORY_RESOURCES),
       ONLINE_STORE("Online Store", "Query an Online Store resource", "Online 
Store Resource", "Online Store resource to query", 
ResourceDirectory.ONLINE_STORE_RESOURCES),
       ORDERS("Orders", "Query an Order resource", "Order Resource", "Order 
resource to query", ResourceDirectory.ORDER_RESOURCES),
       PRODUCT("Products", "Query a Product resource", "Product Resource", 
"Product resource to query", ResourceDirectory.PRODUCT_RESOURCES),
       SALES_CHANNELS("Sales Channels", "Query a Sales Channel resource", 
"Sales Channel Resource", "Sales Channel resource to query", 
ResourceDirectory.SALES_CHANNEL_RESOURCES),
       STORE_PROPERTIES("Store Properties", "Query a Store Property resource", 
"Store Property Resource", "Store Property resource to query", 
ResourceDirectory.STORE_PROPERTY_RESOURCES);
   
       private final String allowableValueDisplayName;
       private final String allowableValueDescription;
       private final String propertyDisplayName;
       private final String propertyDescription;
       private List<ShopifyResource> resources;
   
       ResourceType(
               final String allowableValueDisplayName,
               final String allowableValueDescription,
               String propertyDisplayName, String propertyDescription, 
List<ShopifyResource> resources
       ) {
           this.allowableValueDisplayName = allowableValueDisplayName;
           this.allowableValueDescription = allowableValueDescription;
           this.propertyDisplayName = propertyDisplayName;
           this.propertyDescription = propertyDescription;
           this.resources = resources;
       }
   
       @Override
       public String getValue() {
           return name();
       }
   
       @Override
       public String getDisplayName() {
           return allowableValueDisplayName;
       }
   
       @Override
       public String getDescription() {
           return allowableValueDescription;
       }
   
       public String getPropertyDescription() {
           return propertyDescription;
       }
   
       public String getPropertyDisplayName() {
           return propertyDisplayName;
       }
   
       public List<ShopifyResource> getResources() {
           return resources;
       }
   
       public ShopifyResource getResource(final String value) {
           return getResources().stream()
                   .filter(s -> s.getValue().equals(value))
                   .findFirst()
                   .get();
       }
   
       public AllowableValue[] getResourcesAsAllowableValues() {
           return 
getResources().stream().map(ShopifyResource::getAllowableValue).toArray(AllowableValue[]::new);
       }
   }
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/model/ResourceDirectory.java:
##########
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify.model;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.nifi.components.AllowableValue;
+
+public class ResourceDirectory {
+
+    private ResourceDirectory() {
+    }
+
+    private static final Map<ResourceType, List<ShopifyResource>> resourceMap;
+
+    static {
+        resourceMap = new EnumMap<>(ResourceType.class);
+        resourceMap.put(ResourceType.CUSTOMERS, getCustomerResources());
+        resourceMap.put(ResourceType.DISCOUNTS, getDiscountResources());
+        resourceMap.put(ResourceType.INVENTORY, getInventoryResources());
+        resourceMap.put(ResourceType.ONLINE_STORE, getOnlineStoreResources());
+        resourceMap.put(ResourceType.ORDERS, getOrderResources());
+        resourceMap.put(ResourceType.PRODUCT, getProductResources());
+        resourceMap.put(ResourceType.SALES_CHANNELS, 
getSalesChannelResources());
+        resourceMap.put(ResourceType.STORE_PROPERTIES, 
getStorePropertyResources());
+    }
+
+    private static List<ShopifyResource> getCustomerResources() {
+        final ShopifyResource customer = ShopifyResource.newInstance(
+                "customers",
+                "Customers",
+                "The Customer resource stores information about a shop's 
customers, such as their contact details," +
+                        " their order history, and whether they've agreed to 
receive email marketing.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource customerSavedSearch = 
ShopifyResource.newInstance(
+                "customer_saved_searches",
+                "Customer Saved Searches",
+                "A customer saved search is a search query that represents a 
group of customers defined by the shop owner.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(customer, 
customerSavedSearch));
+    }
+
+    private static List<ShopifyResource> getDiscountResources() {
+        final ShopifyResource priceRule = ShopifyResource.newInstance(
+                "price_rules",
+                "Price Rules",
+                "The PriceRule resource can be used to get discounts using 
conditions",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.singletonList(priceRule);
+    }
+
+    private static List<ShopifyResource> getInventoryResources() {
+        final ShopifyResource location = ShopifyResource.newInstance(
+                "locations",
+                "Locations",
+                "A location represents a geographical location where your 
stores, pop-up stores, headquarters, and warehouses exist.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.singletonList(location);
+    }
+
+    private static List<ShopifyResource> getOnlineStoreResources() {
+        final ShopifyResource blog = ShopifyResource.newInstance(
+                "blogs",
+                "Blogs",
+                "Shopify shops come with a built-in blogging engine, allowing 
a shop to have one or more blogs.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource comment = ShopifyResource.newInstance(
+                "comments",
+                "Comments",
+                "A comment is a reader's response to an article in a blog.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource page = ShopifyResource.newInstance(
+                "pages",
+                "Pages",
+                "Shopify stores come with a tool for creating basic HTML web 
pages.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource redirect = ShopifyResource.newInstance(
+                "redirects",
+                "Redirects",
+                "A redirect causes a visitor on a specific path on the shop's 
site to be automatically sent to a different location.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource scriptTag = ShopifyResource.newInstance(
+                "script_tags",
+                "Script Tags",
+                "The ScriptTag resource represents remote JavaScript code that 
is loaded into the pages of a shop's storefront or the order status page of 
checkout.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource theme = ShopifyResource.newInstance(
+                "themes",
+                "Themes",
+                "A theme controls the look and feel of a Shopify online 
store.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(blog, comment, page, 
redirect, scriptTag, theme));
+    }
+
+    private static List<ShopifyResource> getOrderResources() {
+        final ShopifyResource abandonedCheckouts = ShopifyResource.newInstance(
+                "checkouts",
+                "Abandoned Checkouts",
+                "A checkout is considered abandoned after the customer has 
added contact information, but before the customer has completed their 
purchase.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource draftOrders = ShopifyResource.newInstance(
+                "draft_orders",
+                "Draft Orders",
+                "Merchants can use draft orders to create orders on behalf of 
their customers.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource orders = ShopifyResource.newInstance(
+                "orders",
+                "Orders",
+                "An order is a customer's request to purchase one or more 
products from a shop.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(abandonedCheckouts, 
draftOrders, orders));
+    }
+
+    private static List<ShopifyResource> getProductResources() {
+        final ShopifyResource collect = ShopifyResource.newInstance(
+                "collects",
+                "Collects",
+                "Collects are meant for managing the relationship between 
products and custom collections.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource customCollection = ShopifyResource.newInstance(
+                "custom_collections",
+                "Custom Collections",
+                "A custom collection is a grouping of products that a merchant 
can create to make their store easier to browse. ",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource product = ShopifyResource.newInstance(
+                "products",
+                "Products",
+                "Get products in a merchant's store ",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource smartCollection = ShopifyResource.newInstance(
+                "smart_collections",
+                "Smart Collections",
+                "A smart collection is a grouping of products defined by rules 
that are set by the merchant.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(collect, 
customCollection, product, smartCollection));
+    }
+
+    private static List<ShopifyResource> getSalesChannelResources() {
+        final ShopifyResource collectionListing = ShopifyResource.newInstance(
+                "collection_listings",
+                "Collection Listings",
+                "A CollectionListing resource represents a product collection 
that a merchant has made available to your sales channel.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource productListing = ShopifyResource.newInstance(
+                "product_listings",
+                "Product Listings",
+                "A ProductListing resource represents a Product which is 
available to your sales channel.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(collectionListing, 
productListing));
+    }
+
+    private static List<ShopifyResource> getStorePropertyResources() {
+        final ShopifyResource country = ShopifyResource.newInstance(
+                "countries",
+                "Countries",
+                "The Country resource represents the tax rates applied to 
orders from the different countries where a shop sells its products.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource currency = ShopifyResource.newInstance(
+                "currencies",
+                "Currencies",
+                "Merchants who use Shopify Payments can allow customers to pay 
in their local currency on the online store.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource policy = ShopifyResource.newInstance(
+                "policies",
+                "Policies",
+                "Policy resource can be used to access the policies that a 
merchant has configured for their shop, such as their refund and privacy 
policies.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource shippingZone = ShopifyResource.newInstance(
+                "shipping_zones",
+                "Shipping Zones",
+                "ShippingZone resource can be used to view shipping zones and 
their countries, provinces, and shipping rates.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource shop = ShopifyResource.newInstance(
+                "shop",
+                "Shop",
+                "The Shop resource is a collection of general business and 
store management settings and information about the store.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(country, currency, 
policy, shippingZone, shop));
+    }
+
+    public static AllowableValue[] getCategories() {
+        return 
resourceMap.keySet().stream().map(ResourceType::getAllowableValue).toArray(AllowableValue[]::new);
+    }
+
+    public static List<ShopifyResource> getResources(final ResourceType key) {
+        return resourceMap.get(key);
+    }
+
+    public static AllowableValue[] getResourcesAsAllowableValues(final 
ResourceType key) {
+        return 
getResources(key).stream().map(ShopifyResource::getAllowableValue).toArray(AllowableValue[]::new);
+    }
+
+    public static ShopifyResource getResourceTypeDto(final ResourceType key, 
final String value) {
+        return getResources(key).stream()
+                .filter(s -> s.getValue().equals(value))
+                .findFirst()
+                .get();
+    }

Review Comment:
   ```suggestion
   public static final List<ShopifyResource> CUSTOMER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "customers",
               "Customers",
               "The Customer resource stores information about a shop's 
customers, such as their contact details," +
                       " their order history, and whether they've agreed to 
receive email marketing.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "customer_saved_searches",
               "Customer Saved Searches",
               "A customer saved search is a search query that represents a 
group of customers defined by the shop owner.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> DISCOUNT_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "price_rules",
               "Price Rules",
               "The PriceRule resource can be used to get discounts using 
conditions",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ));
   
       public static final List<ShopifyResource> INVENTORY_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "locations",
               "Locations",
               "A location represents a geographical location where your 
stores, pop-up stores, headquarters and warehouses exist.",
               IncrementalLoadingParameter.NONE
       ));
   
       public static final List<ShopifyResource> ONLINE_STORE_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "blogs",
               "Blogs",
               "Shopify shops come with a built-in blogging engine, allowing a 
shop to have one or more blogs.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "comments",
               "Comments",
               "A comment is a reader's response to an article in a blog.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "pages",
               "Pages",
               "Shopify stores come with a tool for creating basic HTML web 
pages.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "redirects",
               "Redirects",
               "A redirect causes a visitor on a specific path on the shop's 
site to be automatically sent to a different location.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "script_tags",
               "Script Tags",
               "The ScriptTag resource represents remote JavaScript code that 
is loaded into the pages of a shop's storefront or the order status page of 
checkout.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "themes",
               "Themes",
               "A theme controls the look and feel of a Shopify online store.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> ORDER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "checkouts",
               "Abandoned Checkouts",
               "A checkout is considered abandoned after the customer has added 
contact information, but before the customer has completed their purchase.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "draft_orders",
               "Draft Orders",
               "Merchants can use draft orders to create orders on behalf of 
their customers.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "orders",
               "Orders",
               "An order is a customer's request to purchase one or more 
products from a shop.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> PRODUCT_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collects",
               "Collects",
               "Collects are meant for managing the relationship between 
products and custom collections.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "custom_collections",
               "Custom Collections",
               "A custom collection is a grouping of products that a merchant 
can create to make their store easier to browse. ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "products",
               "Products",
               "Get products in a merchant's store ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "smart_collections",
               "Smart Collections",
               "A smart collection is a grouping of products defined by rules 
that are set by the merchant.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> SALES_CHANNEL_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collection_listings",
               "Collection Listings",
               "A CollectionListing resource represents a product collection 
that a merchant has made available to your sales channel.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "product_listings",
               "Product Listings",
               "A ProductListing resource represents a Product which is 
available to your sales channel.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> STORE_PROPERTY_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "countries",
               "Countries",
               "The Country resource represents the tax rates applied to orders 
from the different countries where a shop sells its products.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "currencies",
               "Currencies",
               "Merchants who use Shopify Payments can allow customers to pay 
in their local currency on the online store.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "policies",
               "Policies",
               "Policy resource can be used to access the policies that a 
merchant has configured for their shop, such as their refund and privacy 
policies.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "shipping_zones",
               "Shipping Zones",
               "ShippingZone resource can be used to view shipping zones and 
their countries, provinces, and shipping rates.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "shop",
               "Shop",
               "The Shop resource is a collection of general business and store 
management settings and information about the store.",
               IncrementalLoadingParameter.NONE
       )));
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/GetShopify.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.PrimaryNodeOnly;
+import org.apache.nifi.annotation.behavior.Stateful;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.Scope;
+import org.apache.nifi.components.state.StateMap;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.io.OutputStreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.shopify.model.IncrementalLoadingParameter;
+import org.apache.nifi.processors.shopify.model.ResourceDirectory;
+import org.apache.nifi.processors.shopify.model.ResourceType;
+import org.apache.nifi.processors.shopify.model.ShopifyResource;
+import org.apache.nifi.processors.shopify.rest.ShopifyRestService;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+@PrimaryNodeOnly
+@TriggerSerially
+@TriggerWhenEmpty
+@InputRequirement(Requirement.INPUT_FORBIDDEN)
+@Tags({"shopify"})
+@Stateful(scopes = Scope.CLUSTER, description =
+        "For a few resources the processors support incremental loading. The 
list of the resources with the supported parameters"
+                +
+                "can be found in additional details. State is stored across 
the cluster so that this Processor can be run on Primary Node only and if a new 
Primary Node is"
+                +
+                " selected, the new node can pick up where the previous node 
left off, without duplicating the data.")
+@CapabilityDescription("Retrieves object from a custom Shopify store. The 
processor yield time must be set to the account's rate limit accordingly.")
+public class GetShopify extends AbstractProcessor {
+
+    public static final PropertyDescriptor WEB_CLIENT_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name("web-client-service-provider")
+            .displayName("NiFi Web Client Service Provider")
+            .description("NiFi Web Client Service Provider to make HTTP calls 
and build URIs")
+            .required(false)
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .build();
+
+    static final PropertyDescriptor API_URL = new PropertyDescriptor.Builder()
+            .name("api-url")
+            .displayName("API URL")
+            .description("The API URL of the Custom Shopify App")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor ACCESS_TOKEN = new 
PropertyDescriptor.Builder()
+            .name("access-token")
+            .displayName("Admin API Access Token")
+            .description("The Admin API Access Token of the Custom Shopify 
App")
+            .required(true)
+            .sensitive(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor API_VERSION = new 
PropertyDescriptor.Builder()
+            .name("api-version")
+            .displayName("API Version")
+            .description("The used REST API version")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .defaultValue("2022-10")
+            .build();
+
+    static final PropertyDescriptor RESOURCE_TYPE = new 
PropertyDescriptor.Builder()
+            .name("resource-type")
+            .displayName("Resource Type")
+            .description("Shopify resource type")
+            .required(true)
+            .allowableValues(ResourceDirectory.getCategories())
+            .build();
+
+    static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name("success")
+            .description("For FlowFiles created as a result of a successful 
query.")
+            .build();
+
+    private static final Map<ResourceType, PropertyDescriptor> propertyMap = 
new EnumMap<>(ResourceType.class);
+    private static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS = 
createPropertyDescriptors();
+
+    private static List<PropertyDescriptor> createPropertyDescriptors() {
+        final List<PropertyDescriptor> resourceDescriptors = 
Arrays.stream(ResourceType.values())
+                .map(resourceType -> {
+                    final PropertyDescriptor resourceDescriptor = new 
PropertyDescriptor.Builder()
+                            .name(resourceType.getValue())
+                            .displayName(resourceType.getDisplayName())
+                            .description(resourceType.getDescription())
+                            .required(true)
+                            .dependsOn(RESOURCE_TYPE, resourceType.getValue())
+                            
.allowableValues(ResourceDirectory.getResourcesAsAllowableValues(resourceType))
+                            
.addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+                            .build();
+                    propertyMap.put(resourceType, resourceDescriptor);
+                    return resourceDescriptor;
+                })
+                .collect(Collectors.toList());
+        final List<PropertyDescriptor> propertyDescriptors = new 
ArrayList<>(Arrays.asList(
+                WEB_CLIENT_PROVIDER,
+                API_URL,
+                ACCESS_TOKEN,
+                API_VERSION,
+                RESOURCE_TYPE
+        ));
+        propertyDescriptors.addAll(resourceDescriptors);
+        return Collections.unmodifiableList(propertyDescriptors);
+    }
+
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+    private static final JsonFactory JSON_FACTORY = OBJECT_MAPPER.getFactory();
+    private static final int TOO_MANY_REQUESTS = 429;
+
+    private volatile ShopifyRestService shopifyRestService;
+    private volatile ShopifyResource shopifyResource;
+    private volatile String resourceName;
+
+    @OnScheduled
+    public void onScheduled(final ProcessContext context) {
+        final WebClientServiceProvider webClientServiceProvider =
+                
context.getProperty(WEB_CLIENT_PROVIDER).asControllerService(WebClientServiceProvider.class);
+        final WebClientService webClientService = 
webClientServiceProvider.getWebClientService();
+        final HttpUriBuilder uriBuilder = 
webClientServiceProvider.getHttpUriBuilder();
+
+        final String apiVersion = context.getProperty(API_VERSION).getValue();
+        final String baseUrl = context.getProperty(API_URL).getValue();
+        final String accessToken = 
context.getProperty(ACCESS_TOKEN).getValue();
+
+        final String category = context.getProperty(RESOURCE_TYPE).getValue();
+        final ResourceType resourceType = ResourceType.valueOf(category);
+        resourceName = 
context.getProperty(propertyMap.get(resourceType)).getValue();
+
+        shopifyResource = ResourceDirectory.getResourceTypeDto(resourceType, 
resourceName);

Review Comment:
   ```suggestion
           shopifyResource = resourceType.getResource(resourceName);
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/GetShopify.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.PrimaryNodeOnly;
+import org.apache.nifi.annotation.behavior.Stateful;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.Scope;
+import org.apache.nifi.components.state.StateMap;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.io.OutputStreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.shopify.model.IncrementalLoadingParameter;
+import org.apache.nifi.processors.shopify.model.ResourceDirectory;
+import org.apache.nifi.processors.shopify.model.ResourceType;
+import org.apache.nifi.processors.shopify.model.ShopifyResource;
+import org.apache.nifi.processors.shopify.rest.ShopifyRestService;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+@PrimaryNodeOnly
+@TriggerSerially
+@TriggerWhenEmpty
+@InputRequirement(Requirement.INPUT_FORBIDDEN)
+@Tags({"shopify"})
+@Stateful(scopes = Scope.CLUSTER, description =
+        "For a few resources the processors support incremental loading. The 
list of the resources with the supported parameters"
+                +
+                "can be found in additional details. State is stored across 
the cluster so that this Processor can be run on Primary Node only and if a new 
Primary Node is"
+                +
+                " selected, the new node can pick up where the previous node 
left off, without duplicating the data.")
+@CapabilityDescription("Retrieves object from a custom Shopify store. The 
processor yield time must be set to the account's rate limit accordingly.")
+public class GetShopify extends AbstractProcessor {
+
+    public static final PropertyDescriptor WEB_CLIENT_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name("web-client-service-provider")
+            .displayName("NiFi Web Client Service Provider")
+            .description("NiFi Web Client Service Provider to make HTTP calls 
and build URIs")
+            .required(false)
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .build();
+
+    static final PropertyDescriptor API_URL = new PropertyDescriptor.Builder()
+            .name("api-url")
+            .displayName("API URL")
+            .description("The API URL of the Custom Shopify App")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor ACCESS_TOKEN = new 
PropertyDescriptor.Builder()
+            .name("access-token")
+            .displayName("Admin API Access Token")
+            .description("The Admin API Access Token of the Custom Shopify 
App")
+            .required(true)
+            .sensitive(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor API_VERSION = new 
PropertyDescriptor.Builder()
+            .name("api-version")
+            .displayName("API Version")
+            .description("The used REST API version")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .defaultValue("2022-10")
+            .build();
+
+    static final PropertyDescriptor RESOURCE_TYPE = new 
PropertyDescriptor.Builder()
+            .name("resource-type")
+            .displayName("Resource Type")
+            .description("Shopify resource type")
+            .required(true)
+            .allowableValues(ResourceDirectory.getCategories())
+            .build();
+
+    static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name("success")
+            .description("For FlowFiles created as a result of a successful 
query.")
+            .build();
+
+    private static final Map<ResourceType, PropertyDescriptor> propertyMap = 
new EnumMap<>(ResourceType.class);
+    private static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS = 
createPropertyDescriptors();
+
+    private static List<PropertyDescriptor> createPropertyDescriptors() {
+        final List<PropertyDescriptor> resourceDescriptors = 
Arrays.stream(ResourceType.values())
+                .map(resourceType -> {
+                    final PropertyDescriptor resourceDescriptor = new 
PropertyDescriptor.Builder()
+                            .name(resourceType.getValue())
+                            .displayName(resourceType.getDisplayName())
+                            .description(resourceType.getDescription())

Review Comment:
   ```suggestion
                               
.displayName(resourceType.getPropertyDisplayName())
                               
.description(resourceType.getPropertyDescription())
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/GetShopify.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.PrimaryNodeOnly;
+import org.apache.nifi.annotation.behavior.Stateful;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.Scope;
+import org.apache.nifi.components.state.StateMap;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.io.OutputStreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.shopify.model.IncrementalLoadingParameter;
+import org.apache.nifi.processors.shopify.model.ResourceDirectory;
+import org.apache.nifi.processors.shopify.model.ResourceType;
+import org.apache.nifi.processors.shopify.model.ShopifyResource;
+import org.apache.nifi.processors.shopify.rest.ShopifyRestService;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+@PrimaryNodeOnly
+@TriggerSerially
+@TriggerWhenEmpty
+@InputRequirement(Requirement.INPUT_FORBIDDEN)
+@Tags({"shopify"})
+@Stateful(scopes = Scope.CLUSTER, description =
+        "For a few resources the processors support incremental loading. The 
list of the resources with the supported parameters"
+                +
+                "can be found in additional details. State is stored across 
the cluster so that this Processor can be run on Primary Node only and if a new 
Primary Node is"
+                +
+                " selected, the new node can pick up where the previous node 
left off, without duplicating the data.")
+@CapabilityDescription("Retrieves object from a custom Shopify store. The 
processor yield time must be set to the account's rate limit accordingly.")
+public class GetShopify extends AbstractProcessor {
+
+    public static final PropertyDescriptor WEB_CLIENT_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name("web-client-service-provider")
+            .displayName("NiFi Web Client Service Provider")
+            .description("NiFi Web Client Service Provider to make HTTP calls 
and build URIs")
+            .required(false)
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .build();
+
+    static final PropertyDescriptor API_URL = new PropertyDescriptor.Builder()
+            .name("api-url")
+            .displayName("API URL")
+            .description("The API URL of the Custom Shopify App")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor ACCESS_TOKEN = new 
PropertyDescriptor.Builder()
+            .name("access-token")
+            .displayName("Admin API Access Token")
+            .description("The Admin API Access Token of the Custom Shopify 
App")
+            .required(true)
+            .sensitive(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor API_VERSION = new 
PropertyDescriptor.Builder()
+            .name("api-version")
+            .displayName("API Version")
+            .description("The used REST API version")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .defaultValue("2022-10")
+            .build();
+
+    static final PropertyDescriptor RESOURCE_TYPE = new 
PropertyDescriptor.Builder()
+            .name("resource-type")
+            .displayName("Resource Type")
+            .description("Shopify resource type")
+            .required(true)
+            .allowableValues(ResourceDirectory.getCategories())
+            .build();
+
+    static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name("success")
+            .description("For FlowFiles created as a result of a successful 
query.")
+            .build();
+
+    private static final Map<ResourceType, PropertyDescriptor> propertyMap = 
new EnumMap<>(ResourceType.class);
+    private static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS = 
createPropertyDescriptors();
+
+    private static List<PropertyDescriptor> createPropertyDescriptors() {
+        final List<PropertyDescriptor> resourceDescriptors = 
Arrays.stream(ResourceType.values())
+                .map(resourceType -> {
+                    final PropertyDescriptor resourceDescriptor = new 
PropertyDescriptor.Builder()
+                            .name(resourceType.getValue())
+                            .displayName(resourceType.getDisplayName())
+                            .description(resourceType.getDescription())
+                            .required(true)
+                            .dependsOn(RESOURCE_TYPE, resourceType.getValue())
+                            
.allowableValues(ResourceDirectory.getResourcesAsAllowableValues(resourceType))

Review Comment:
   ```suggestion
                               
.allowableValues(resourceType.getResourcesAsAllowableValues())
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/GetShopify.java:
##########
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.PrimaryNodeOnly;
+import org.apache.nifi.annotation.behavior.Stateful;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.TriggerWhenEmpty;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.state.Scope;
+import org.apache.nifi.components.state.StateMap;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.io.OutputStreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.shopify.model.IncrementalLoadingParameter;
+import org.apache.nifi.processors.shopify.model.ResourceDirectory;
+import org.apache.nifi.processors.shopify.model.ResourceType;
+import org.apache.nifi.processors.shopify.model.ShopifyResource;
+import org.apache.nifi.processors.shopify.rest.ShopifyRestService;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.HttpResponseStatus;
+import org.apache.nifi.web.client.api.HttpUriBuilder;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
+
+@PrimaryNodeOnly
+@TriggerSerially
+@TriggerWhenEmpty
+@InputRequirement(Requirement.INPUT_FORBIDDEN)
+@Tags({"shopify"})
+@Stateful(scopes = Scope.CLUSTER, description =
+        "For a few resources the processors support incremental loading. The 
list of the resources with the supported parameters"
+                +
+                "can be found in additional details. State is stored across 
the cluster so that this Processor can be run on Primary Node only and if a new 
Primary Node is"
+                +
+                " selected, the new node can pick up where the previous node 
left off, without duplicating the data.")
+@CapabilityDescription("Retrieves object from a custom Shopify store. The 
processor yield time must be set to the account's rate limit accordingly.")
+public class GetShopify extends AbstractProcessor {
+
+    public static final PropertyDescriptor WEB_CLIENT_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name("web-client-service-provider")
+            .displayName("NiFi Web Client Service Provider")
+            .description("NiFi Web Client Service Provider to make HTTP calls 
and build URIs")
+            .required(false)
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .build();
+
+    static final PropertyDescriptor API_URL = new PropertyDescriptor.Builder()
+            .name("api-url")
+            .displayName("API URL")
+            .description("The API URL of the Custom Shopify App")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor ACCESS_TOKEN = new 
PropertyDescriptor.Builder()
+            .name("access-token")
+            .displayName("Admin API Access Token")
+            .description("The Admin API Access Token of the Custom Shopify 
App")
+            .required(true)
+            .sensitive(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .build();
+
+    static final PropertyDescriptor API_VERSION = new 
PropertyDescriptor.Builder()
+            .name("api-version")
+            .displayName("API Version")
+            .description("The used REST API version")
+            .required(true)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .defaultValue("2022-10")
+            .build();
+
+    static final PropertyDescriptor RESOURCE_TYPE = new 
PropertyDescriptor.Builder()
+            .name("resource-type")
+            .displayName("Resource Type")
+            .description("Shopify resource type")
+            .required(true)
+            .allowableValues(ResourceDirectory.getCategories())

Review Comment:
   ```suggestion
               .allowableValues(ResourceType.values())
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/model/ResourceDirectory.java:
##########
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify.model;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.nifi.components.AllowableValue;
+
+public class ResourceDirectory {

Review Comment:
   ```suggestion
   public class ResourceDirectory {
   
       public static final List<ShopifyResource> CUSTOMER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "customers",
               "Customers",
               "The Customer resource stores information about a shop's 
customers, such as their contact details," +
                       " their order history, and whether they've agreed to 
receive email marketing.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "customer_saved_searches",
               "Customer Saved Searches",
               "A customer saved search is a search query that represents a 
group of customers defined by the shop owner.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> DISCOUNT_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "price_rules",
               "Price Rules",
               "The PriceRule resource can be used to get discounts using 
conditions",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ));
   
       public static final List<ShopifyResource> INVENTORY_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "locations",
               "Locations",
               "A location represents a geographical location where your 
stores, pop-up stores, headquarters and warehouses exist.",
               IncrementalLoadingParameter.NONE
       ));
   
       public static final List<ShopifyResource> ONLINE_STORE_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "blogs",
               "Blogs",
               "Shopify shops come with a built-in blogging engine, allowing a 
shop to have one or more blogs.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "comments",
               "Comments",
               "A comment is a reader's response to an article in a blog.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "pages",
               "Pages",
               "Shopify stores come with a tool for creating basic HTML web 
pages.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "redirects",
               "Redirects",
               "A redirect causes a visitor on a specific path on the shop's 
site to be automatically sent to a different location.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "script_tags",
               "Script Tags",
               "The ScriptTag resource represents remote JavaScript code that 
is loaded into the pages of a shop's storefront or the order status page of 
checkout.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "themes",
               "Themes",
               "A theme controls the look and feel of a Shopify online store.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> ORDER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "checkouts",
               "Abandoned Checkouts",
               "A checkout is considered abandoned after the customer has added 
contact information, but before the customer has completed their purchase.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "draft_orders",
               "Draft Orders",
               "Merchants can use draft orders to create orders on behalf of 
their customers.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "orders",
               "Orders",
               "An order is a customer's request to purchase one or more 
products from a shop.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> PRODUCT_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collects",
               "Collects",
               "Collects are meant for managing the relationship between 
products and custom collections.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "custom_collections",
               "Custom Collections",
               "A custom collection is a grouping of products that a merchant 
can create to make their store easier to browse. ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "products",
               "Products",
               "Get products in a merchant's store ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "smart_collections",
               "Smart Collections",
               "A smart collection is a grouping of products defined by rules 
that are set by the merchant.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> SALES_CHANNEL_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collection_listings",
               "Collection Listings",
               "A CollectionListing resource represents a product collection 
that a merchant has made available to your sales channel.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "product_listings",
               "Product Listings",
               "A ProductListing resource represents a Product which is 
available to your sales channel.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> STORE_PROPERTY_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "countries",
               "Countries",
               "The Country resource represents the tax rates applied to orders 
from the different countries where a shop sells its products.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "currencies",
               "Currencies",
               "Merchants who use Shopify Payments can allow customers to pay 
in their local currency on the online store.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "policies",
               "Policies",
               "Policy resource can be used to access the policies that a 
merchant has configured for their shop, such as their refund and privacy 
policies.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "shipping_zones",
               "Shipping Zones",
               "ShippingZone resource can be used to view shipping zones and 
their countries, provinces, and shipping rates.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "shop",
               "Shop",
               "The Shop resource is a collection of general business and store 
management settings and information about the store.",
               IncrementalLoadingParameter.NONE
       )));
   }
   ```



##########
nifi-nar-bundles/nifi-shopify-bundle/nifi-shopify-processors/src/main/java/org/apache/nifi/processors/shopify/model/ResourceDirectory.java:
##########
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.shopify.model;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.nifi.components.AllowableValue;
+
+public class ResourceDirectory {
+
+    private ResourceDirectory() {
+    }
+
+    private static final Map<ResourceType, List<ShopifyResource>> resourceMap;
+
+    static {
+        resourceMap = new EnumMap<>(ResourceType.class);
+        resourceMap.put(ResourceType.CUSTOMERS, getCustomerResources());
+        resourceMap.put(ResourceType.DISCOUNTS, getDiscountResources());
+        resourceMap.put(ResourceType.INVENTORY, getInventoryResources());
+        resourceMap.put(ResourceType.ONLINE_STORE, getOnlineStoreResources());
+        resourceMap.put(ResourceType.ORDERS, getOrderResources());
+        resourceMap.put(ResourceType.PRODUCT, getProductResources());
+        resourceMap.put(ResourceType.SALES_CHANNELS, 
getSalesChannelResources());
+        resourceMap.put(ResourceType.STORE_PROPERTIES, 
getStorePropertyResources());
+    }
+
+    private static List<ShopifyResource> getCustomerResources() {
+        final ShopifyResource customer = ShopifyResource.newInstance(
+                "customers",
+                "Customers",
+                "The Customer resource stores information about a shop's 
customers, such as their contact details," +
+                        " their order history, and whether they've agreed to 
receive email marketing.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource customerSavedSearch = 
ShopifyResource.newInstance(
+                "customer_saved_searches",
+                "Customer Saved Searches",
+                "A customer saved search is a search query that represents a 
group of customers defined by the shop owner.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(customer, 
customerSavedSearch));
+    }
+
+    private static List<ShopifyResource> getDiscountResources() {
+        final ShopifyResource priceRule = ShopifyResource.newInstance(
+                "price_rules",
+                "Price Rules",
+                "The PriceRule resource can be used to get discounts using 
conditions",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.singletonList(priceRule);
+    }
+
+    private static List<ShopifyResource> getInventoryResources() {
+        final ShopifyResource location = ShopifyResource.newInstance(
+                "locations",
+                "Locations",
+                "A location represents a geographical location where your 
stores, pop-up stores, headquarters, and warehouses exist.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.singletonList(location);
+    }
+
+    private static List<ShopifyResource> getOnlineStoreResources() {
+        final ShopifyResource blog = ShopifyResource.newInstance(
+                "blogs",
+                "Blogs",
+                "Shopify shops come with a built-in blogging engine, allowing 
a shop to have one or more blogs.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource comment = ShopifyResource.newInstance(
+                "comments",
+                "Comments",
+                "A comment is a reader's response to an article in a blog.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource page = ShopifyResource.newInstance(
+                "pages",
+                "Pages",
+                "Shopify stores come with a tool for creating basic HTML web 
pages.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource redirect = ShopifyResource.newInstance(
+                "redirects",
+                "Redirects",
+                "A redirect causes a visitor on a specific path on the shop's 
site to be automatically sent to a different location.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource scriptTag = ShopifyResource.newInstance(
+                "script_tags",
+                "Script Tags",
+                "The ScriptTag resource represents remote JavaScript code that 
is loaded into the pages of a shop's storefront or the order status page of 
checkout.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource theme = ShopifyResource.newInstance(
+                "themes",
+                "Themes",
+                "A theme controls the look and feel of a Shopify online 
store.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(blog, comment, page, 
redirect, scriptTag, theme));
+    }
+
+    private static List<ShopifyResource> getOrderResources() {
+        final ShopifyResource abandonedCheckouts = ShopifyResource.newInstance(
+                "checkouts",
+                "Abandoned Checkouts",
+                "A checkout is considered abandoned after the customer has 
added contact information, but before the customer has completed their 
purchase.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource draftOrders = ShopifyResource.newInstance(
+                "draft_orders",
+                "Draft Orders",
+                "Merchants can use draft orders to create orders on behalf of 
their customers.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource orders = ShopifyResource.newInstance(
+                "orders",
+                "Orders",
+                "An order is a customer's request to purchase one or more 
products from a shop.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(abandonedCheckouts, 
draftOrders, orders));
+    }
+
+    private static List<ShopifyResource> getProductResources() {
+        final ShopifyResource collect = ShopifyResource.newInstance(
+                "collects",
+                "Collects",
+                "Collects are meant for managing the relationship between 
products and custom collections.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource customCollection = ShopifyResource.newInstance(
+                "custom_collections",
+                "Custom Collections",
+                "A custom collection is a grouping of products that a merchant 
can create to make their store easier to browse. ",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource product = ShopifyResource.newInstance(
+                "products",
+                "Products",
+                "Get products in a merchant's store ",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource smartCollection = ShopifyResource.newInstance(
+                "smart_collections",
+                "Smart Collections",
+                "A smart collection is a grouping of products defined by rules 
that are set by the merchant.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(collect, 
customCollection, product, smartCollection));
+    }
+
+    private static List<ShopifyResource> getSalesChannelResources() {
+        final ShopifyResource collectionListing = ShopifyResource.newInstance(
+                "collection_listings",
+                "Collection Listings",
+                "A CollectionListing resource represents a product collection 
that a merchant has made available to your sales channel.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource productListing = ShopifyResource.newInstance(
+                "product_listings",
+                "Product Listings",
+                "A ProductListing resource represents a Product which is 
available to your sales channel.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        return Collections.unmodifiableList(Arrays.asList(collectionListing, 
productListing));
+    }
+
+    private static List<ShopifyResource> getStorePropertyResources() {
+        final ShopifyResource country = ShopifyResource.newInstance(
+                "countries",
+                "Countries",
+                "The Country resource represents the tax rates applied to 
orders from the different countries where a shop sells its products.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource currency = ShopifyResource.newInstance(
+                "currencies",
+                "Currencies",
+                "Merchants who use Shopify Payments can allow customers to pay 
in their local currency on the online store.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource policy = ShopifyResource.newInstance(
+                "policies",
+                "Policies",
+                "Policy resource can be used to access the policies that a 
merchant has configured for their shop, such as their refund and privacy 
policies.",
+                IncrementalLoadingParameter.NONE
+        );
+        final ShopifyResource shippingZone = ShopifyResource.newInstance(
+                "shipping_zones",
+                "Shipping Zones",
+                "ShippingZone resource can be used to view shipping zones and 
their countries, provinces, and shipping rates.",
+                IncrementalLoadingParameter.UPDATED_AT_MIN
+        );
+        final ShopifyResource shop = ShopifyResource.newInstance(
+                "shop",
+                "Shop",
+                "The Shop resource is a collection of general business and 
store management settings and information about the store.",
+                IncrementalLoadingParameter.NONE
+        );
+        return Collections.unmodifiableList(Arrays.asList(country, currency, 
policy, shippingZone, shop));
+    }
+
+    public static AllowableValue[] getCategories() {
+        return 
resourceMap.keySet().stream().map(ResourceType::getAllowableValue).toArray(AllowableValue[]::new);
+    }
+
+    public static List<ShopifyResource> getResources(final ResourceType key) {
+        return resourceMap.get(key);
+    }
+
+    public static AllowableValue[] getResourcesAsAllowableValues(final 
ResourceType key) {
+        return 
getResources(key).stream().map(ShopifyResource::getAllowableValue).toArray(AllowableValue[]::new);
+    }
+
+    public static ShopifyResource getResourceTypeDto(final ResourceType key, 
final String value) {
+        return getResources(key).stream()
+                .filter(s -> s.getValue().equals(value))
+                .findFirst()
+                .get();
+    }

Review Comment:
   ```suggestion
   public static final List<ShopifyResource> CUSTOMER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "customers",
               "Customers",
               "The Customer resource stores information about a shop's 
customers, such as their contact details," +
                       " their order history, and whether they've agreed to 
receive email marketing.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "customer_saved_searches",
               "Customer Saved Searches",
               "A customer saved search is a search query that represents a 
group of customers defined by the shop owner.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> DISCOUNT_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "price_rules",
               "Price Rules",
               "The PriceRule resource can be used to get discounts using 
conditions",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ));
   
       public static final List<ShopifyResource> INVENTORY_RESOURCES = 
Collections.singletonList(ShopifyResource.newInstance(
               "locations",
               "Locations",
               "A location represents a geographical location where your 
stores, pop-up stores, headquarters and warehouses exist.",
               IncrementalLoadingParameter.NONE
       ));
   
       public static final List<ShopifyResource> ONLINE_STORE_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "blogs",
               "Blogs",
               "Shopify shops come with a built-in blogging engine, allowing a 
shop to have one or more blogs.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "comments",
               "Comments",
               "A comment is a reader's response to an article in a blog.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "pages",
               "Pages",
               "Shopify stores come with a tool for creating basic HTML web 
pages.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "redirects",
               "Redirects",
               "A redirect causes a visitor on a specific path on the shop's 
site to be automatically sent to a different location.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "script_tags",
               "Script Tags",
               "The ScriptTag resource represents remote JavaScript code that 
is loaded into the pages of a shop's storefront or the order status page of 
checkout.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "themes",
               "Themes",
               "A theme controls the look and feel of a Shopify online store.",
               IncrementalLoadingParameter.NONE
       )));
   
       public static final List<ShopifyResource> ORDER_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "checkouts",
               "Abandoned Checkouts",
               "A checkout is considered abandoned after the customer has added 
contact information, but before the customer has completed their purchase.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "draft_orders",
               "Draft Orders",
               "Merchants can use draft orders to create orders on behalf of 
their customers.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "orders",
               "Orders",
               "An order is a customer's request to purchase one or more 
products from a shop.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> PRODUCT_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collects",
               "Collects",
               "Collects are meant for managing the relationship between 
products and custom collections.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "custom_collections",
               "Custom Collections",
               "A custom collection is a grouping of products that a merchant 
can create to make their store easier to browse. ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "products",
               "Products",
               "Get products in a merchant's store ",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "smart_collections",
               "Smart Collections",
               "A smart collection is a grouping of products defined by rules 
that are set by the merchant.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> SALES_CHANNEL_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "collection_listings",
               "Collection Listings",
               "A CollectionListing resource represents a product collection 
that a merchant has made available to your sales channel.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "product_listings",
               "Product Listings",
               "A ProductListing resource represents a Product which is 
available to your sales channel.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       )));
   
       public static final List<ShopifyResource> STORE_PROPERTY_RESOURCES = 
Collections.unmodifiableList(Arrays.asList(ShopifyResource.newInstance(
               "countries",
               "Countries",
               "The Country resource represents the tax rates applied to orders 
from the different countries where a shop sells its products.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "currencies",
               "Currencies",
               "Merchants who use Shopify Payments can allow customers to pay 
in their local currency on the online store.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "policies",
               "Policies",
               "Policy resource can be used to access the policies that a 
merchant has configured for their shop, such as their refund and privacy 
policies.",
               IncrementalLoadingParameter.NONE
       ), ShopifyResource.newInstance(
               "shipping_zones",
               "Shipping Zones",
               "ShippingZone resource can be used to view shipping zones and 
their countries, provinces, and shipping rates.",
               IncrementalLoadingParameter.UPDATED_AT_MIN
       ), ShopifyResource.newInstance(
               "shop",
               "Shop",
               "The Shop resource is a collection of general business and store 
management settings and information about the store.",
               IncrementalLoadingParameter.NONE
       )));
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to