EPlat

EPlat (E-commerce Platform)
A single interface for interacting with E-commerce platform APIs.

Goals:

  • Make it easy to use and request API resources from different platforms.
  • Offer a universal alias interface for interacting with common natured attributes. e.g. Shopify's product.body_html and BigCommerce's product.description.
  • Have a simple, easy-to-understand project structure.
  • The e_plat alias interface mimics Shopify's API schema names and types.

EPlat Platypus


Installation

Install the gem and add to the application's Gemfile by executing:

$ gem "e_plat"

To your gemfile and then run

$ bundle


Config

You can configure which platform APIs are used by updating the EPlat config:

#initializers/e_plat.rb
EPlat.config.shopify_api_version = "2024-07"
EPlat.config.bigcommerce_api_version = "v3"

# EPlat.api_display_name.shopify #=> "2024-07" # presents as the platform would display in URL paths
# EPlat.config.shopify_api_version #=> "2024_07" # coerced interally for creating constants
# EPlat.config.print_graphql_requests #=> false # prints out Shopify graphql queries/mutations to the console


Testing

To run the test for the default versions of all supported platforms:

  bundle exec rails test

To run with specific api versions, you can set globals inline

  EPLAT_SHOPIFY_API_VERSION=2024_07 EPLAT_BIGCOMMERCE_API_VERSION=v3 rails test

To print out Shopify GraphQL queries/mutations

EPLAT_PRINT_GRAPHQL_REQUESTS=true rails test


Releasing a new version

https://dev.to/doctolib/release-a-new-gem-version-je0



Usage

  1. To make requests, first initialize a session like so:

    EPlat::Session.new(
    platform: :shopify, 
    store_url: "test-store.myshopify.com", 
    api_token:  "123",
    # store_hash: "optional BigCommerce store hash"
    )
    
  2. You can then make requests to the platform via a singleton call on the Resource class:

    EPlat::Product.find(id: 123)
    
  3. Which will return a platform resource instance that inherits from:

    EPlat::Product
    

EPlat is designed to let you mostly use it's universal interface, but then easily interact with non supported platform attributes when needed.

  tag = EPlat::ScriptTag.new(
    display_scope: :online_store,
    event: :onload,
    src: "https://preproduct.io/mini-script.js"
  )
  tag.name = "mini script" if EPlat::Current.e_plat_session.bigcommerce?
  tag.save 

  # ...when session is a Shopify store
  # POST https://preproduct-test.myshopify.com/admin/api/2024-07/script_tags.json 
  # body: '{"script_tag":{"display_scope":"online_store","event":"onload","src":"https://preproduct.io/mini-script.js"}}'
  # 
  # ...when session is a BigCommerce store
  # POST https://api.bigcommerce.com/stores/d0kmq3bory/v3/content/scripts
  # body: {"location":"head","auto_uninstall":true,"kind":"src","load_method":"async","name":"mini script","enabled":true,"visibility":"storefront","event":"onload","src":"https://preproduct.io/mini-script.js"}


Under The Hood

  1. Request/Resources follow this format: EPlat::ResourceName. Requests are called on the class, which then return an instance.
  2. EPlat resources will return their platform's native attributes, alongside a universal alias interface for viewing/editing via the EPlat schema.
    • EPlat aliases can always be safely called, but aren't always successfully mapped to underlying platform attributes.
    • Whilst the EPlat alias interface and methods often mean you can treat resources the same regardless of platform, you can also ignore this interface and interact with the platform native attributes like regular active resource/record object.
    • The EPlat alias interface is just a set of dynamically created getter/setter/predicate methods with types that control the native attributes of the resource. You can check if an attribute has been mapped by calling `resource.mapped? "attribute_name"`


EPlat Alias Interface

Shop ### EPlat::Shop | Alias | Type | Shopify | BigCommerce| Etc | | ------------------------------------ | --------- | ------- | -----------| ------------| | id | integer | * | nil | nil | | name | string | * | name | nil | | email | string | * | admin_email| nil | | domain | string | * | domain | nil | | province | string | * | nil | nil | | country | string | * | country | nil | | address1 | string | * | nil | nil | | zip | string | * | nil | nil | | city | string | * | nil | nil | | source | string | * | nil | nil | | phone | string | * | nil | nil | | latitude | float | * | nil | nil | | longitude | float | * | nil | nil | | primary_locale | string | * | nil | nil | | address2 | string | * | nil | nil | | created_at | datetime | * | nil | nil | | updated_at | datetime | * | nil | nil | | country_code | string | * | country_code | nil | | country_name | string | * | nil | nil | | currency | string | * | currency | nil | | customer_email | string | * | nil | nil | | timezone | string | * | nil | nil | | iana_timezone | string | * | nil | nil | | shop_owner | string | * | nil | nil | | money_format | string | * | nil | nil | | money_with_currency_format | string | * | nil | nil | | weight_unit | string | * | weight_units| nil | | province_code | string | * | nil | nil | | taxes_included | boolean | * | nil | nil | | auto_configure_tax_inclusivity | boolean | * | nil | nil | | tax_shipping | boolean | * | nil | nil | | county_taxes | boolean | * | nil | nil | | plan_display_name | string | * | nil | nil | | plan_name | string | * | plan_name | nil | | has_discounts | boolean | * | nil | nil | | has_gift_cards | boolean | * | nil | nil | | myshopify_domain | string | * | control_panel_base_url | nil | | google_apps_domain | string | * | nil | nil | | google_apps_login_enabled | boolean | * | nil | nil | | money_in_emails_format | string | * | nil | nil | | money_with_currency_in_emails_format | string | * | nil | nil | | eligible_for_payments | boolean | * | nil | nil | | requires_extra_payments_agreement | boolean | * | nil | nil | | password_enabled | boolean | * | nil | nil | | has_storefront | boolean | * | nil | nil | | eligible_for_card_reader_giveaway | boolean | * | nil | nil | | finances | boolean | * | nil | nil | | primary_location_id | integer | * | nil | nil | | cookie_consent_level | string | * | nil | nil | | visitor_tracking_consent_preference | string | * | nil | nil | | checkout_api_supported | boolean | * | nil | nil | | multi_location_enabled | boolean | * | nil | nil | | setup_required | boolean | * | nil | nil | | pre_launch_enabled | boolean | * | nil | nil | | enabled_presentment_currencies | array | * | nil | nil | | transactional_sms_disabled | boolean | * | nil | nil | | marketing_sms_consent_enabled_at_checkout | boolean | * | nil | nil | ```ruby # Bigcommerce translation. myshopify_domain is a permanent shop.myshopify_domain #"store-#{ store_hash }.mybigcommerce.com" shop.domain # custom_domain.com ```
Product ### EPlat::Product | Alias | Type | Shopify | BigCommerce | Etc | | ------------------------ | -------- | ------- | -------------| ------------| | body_html | string | * | description | nil | | created_at | datetime | * | date_created | nil | | handle | string | * | name | nil | | id | integer | * | id | nil | | images | array | * | * | nil | | options | array | * | * | nil | | product_type | string | * | type | nil | | published_at | datetime | * | nil | nil | | status | string | * | availability | nil | | tags | string | * | nil | nil | | template_suffix | string | * | nil | nil | | title | string | * | name | nil | | updated_at | datetime | * | date_modified| nil | | variants | array | * | * | nil | | vendor | string | * | nil | nil | ### EPlat::Product::Variant | Alias | Type | Shopify | BigCommerce | Etc | |-----------------------|----------|---------|--------------------------------------|-----| | id | integer | * | id | nil | | title | string | * | option_values&.map(&:label)&.join(' ') | nil | | price | string | * | price | nil | | sku | string | * | sku | nil | | position | integer | * | nil | nil | | inventory_policy | string | * | nil | nil | | compare_at_price | string | * | nil | nil | | inventory_management | boolean | inventoryItem[tracked] | nil | nil | | created_at | datetime | * | nil | nil | | updated_at | datetime | * | nil | nil | | taxable | boolean | * | nil | nil | | barcode | string | * | nil | nil | | grams | integer | getter only: converted node.inventoryItem[measurement][weight][value] | nil | nil | | weight | float | getter only: node.inventoryItem[measurement][weight][value] | weight | | weight_unit | string | getter only: node.inventoryItem[measurement][weight][unit] | nil | | inventory_item_id | integer | getter only: node.inventoryItem[id]| nil | nil | | inventory_quantity | integer | getter only: node.inventoryQuantity | inventory_level | nil | | tax_code | string | * | nil | nil | | requires_shipping | boolean | InventoryItem[requiresShipping] | nil | nil | helper methods:
`image_src` => `String | nil`, platforms supported: Shopify, Bigcommerce *Bigcommerce variant.title= setter is not supported ### EPlat::Product::Option | Alias | Type | Shopify | BigCommerce | Etc | | ---------- | -------- | ------- | ---------------------------- | --- | | id | integer | * | id | nil | | name | string | * | display_name | nil | | position | integer | * | sort_order | nil | | values | array | * | option_values[i][label] | nil | ### EPlat::Product::Image | Alias | Type | Shopify | BigCommerce | Etc | | -------------------- | -------- | ------- | ----------- | ------------| | id | integer | * | id | nil | | position | integer | * | nil | nil | | alt | string | * | nil | nil | | width | integer | * | nil | nil | | height | integer | * | nil | nil | | src | string | * | url_standard | nil | ### EPlat::Product::Variant::OptionValue (not supported for Shopify API v2024_01) | Alias | Type | Shopify | BigCommerce | Etc | | -------------------- | -------- | ------------------------------------------ | ------------------ | --- | | id | integer | [selected_options][option_value][id] | id | nil | | name | string | [selected_options][name] | option_display_name| nil | | value | string | [selected_options][value] | label | nil |
Order ### EPlat::Order | attribute_name | type | Shopify | BigCommerce | Etc | |--------------------------------------|----------|---------|-------------|-------------| | id | integer | * | id | nil | | app_id | integer | * | nil | nil | | billing_address_address1 | string | * | nil | nil | | billing_address_address2 | string | * | nil | nil | | billing_address_city | string | * | nil | nil | | billing_address_company | string | * | nil | nil | | billing_address_country | string | * | nil | nil | | billing_address_first_name | string | * | nil | nil | | billing_address_last_name | string | * | nil | nil | | billing_address_phone | string | * | nil | nil | | billing_address_province | string | * | nil | nil | | billing_address_zip | string | * | nil | nil | | billing_address_name | string | * | nil | nil | | billing_address_province_code | string | * | nil | nil | | billing_address_country_code | string | * | nil | nil | | billing_address_latitude | string | * | nil | nil | | billing_address_longitude | string | * | nil | nil | | browser_ip | string | * | nil | nil | | buyer_accepts_marketing | boolean | * | nil | nil | | cancel_reason | string | * | nil | nil | | cancelled_at | datetime | * | nil | nil | | cart_token | string | * | nil | nil | | checkout_token | string | * | nil | nil | | client_details | hash | * | nil | nil | | closed_at | datetime | * | nil | nil | | created_at | datetime | * | date_created | nil | | currency | string | * | currency_code | nil | | current_total_discounts | string | * | discount_amount | nil | | current_total_discounts_set | hash | * | nil | nil | | current_total_duties_set | hash | * | nil | nil | | current_total_price | string | * | nil | nil | | current_total_price_set | hash | * | nil | nil | | current_subtotal_price | string | * | nil | nil | | current_subtotal_price_set | hash | * | nil | nil | | current_total_tax | string | * | nil | nil | | current_total_tax_set | hash | * | nil | nil | | customer_locale | string | * | customer_locale | nil | | device_id | integer | * | nil | nil | | discount_codes | array | * | nil | nil | | email | string | * | billing_address[email]| nil | | estimated_taxes | boolean | * | nil | nil | | financial_status | string | * | status_id | nil | | fulfillment_status | string | * | nil | nil | | gateway | string | * | nil | nil | | landing_site | string | * | nil | nil | | landing_site_ref | string | * | nil | nil | | location_id | integer | * | nil | nil | | merchant_of_record_app_id | integer | * | nil | nil | | name | string | * | nil | nil | | note | string | * | staff_notes | nil | | note_attributes | array | * | nil | nil | | number | integer | * | nil | nil | | order_number | integer | * | id | nil | | order_status_url | string | * | nil | nil | | original_total_duties_set | hash | * | nil | nil | | payment_gateway_names | array | * | nil | nil | | phone | string | * | nil | nil | | presentment_currency | string | * | nil | nil | | processed_at | string | * | nil | nil | | processing_method | string | * | nil | nil | | reference | string | * | nil | nil | | referring_site | string | * | nil | nil | | source_identifier | string | * | nil | nil | | source_name | string | * | nil | nil | | source_url | string | * | nil | nil | | subtotal_price | string | * | subtotal_ex_tax | nil | | subtotal_price_set | hash | * | nil | nil | | tags | string | * | nil | nil | | tax_lines | array | * | nil | nil | | taxes_included | boolean | * | nil | nil | | test | boolean | * | nil | nil | | token | string | * | nil | nil | | total_discounts | string | * | nil | nil | | total_discounts_set | hash | * | nil | nil | | total_line_items_price | string | * | nil | nil | | total_line_items_price_set | hash | * | nil | nil | | total_outstanding | string | * | nil | nil | | total_price | string | * | total_inc_tax | nil | | total_price_set | hash | * | nil | nil | | total_shipping_price_set | hash | * | nil | nil | | total_tax | string | * | total_tax | nil | | total_tax_set | hash | * | nil | nil | | total_tip_received | string | * | nil | nil | | total_weight | integer | * | nil | nil | | updated_at | datetime | * | date_modified | nil | | billing_address | hash | * | billing_address | nil | | customer | hash | * | nil | nil | | discount_applications | array | * | nil | nil | | fulfillments | array | * | nil | nil | | line_items | array | * | nil | nil | | payment_details | hash | * | nil | nil | | payment_terms | hash | * | nil | nil | | refunds | array | * | nil | nil | | shipping_address | hash | * | nil | nil | | shipping_lines | array | * | nil | nil | ### EPlat::Order::ShippingAddress | Alias | Type | Shopify | BigCommerce | Etc | |---------------|---------|---------|-------------|-------------| | address1 | string | * | street_1 | nil | | address2 | string | * | street_2 | nil | | city | string | * | city | nil | | company | string | * | company | nil | | country | string | * | country | nil | | first_name | string | * | first_name | nil | | last_name | string | * | last_name | nil | | phone | string | * | phone | nil | | province | string | * | state | nil | | zip | string | * | zip | nil | | country_code | string | * | country_iso2| nil | | province_code | string | * | nil | nil | | latitude | float | * | nil | nil | | longitude | float | * | nil | nil | ### EPlat::Order::BillingAddress | Alias | Type | Shopify | BigCommerce | Etc | |---------------|---------|---------|-------------|-------------| | address1 | string | * | street_1 | nil | | address2 | string | * | street_2 | nil | | city | string | * | city | nil | | company | string | * | company | nil | | country | string | * | country | nil | | first_name | string | * | first_name | nil | | last_name | string | * | last_name | nil | | phone | string | * | phone | nil | | province | string | * | state | nil | | zip | string | * | zip | nil | | country_code | string | * | country_iso2| nil | | province_code | string | * | nil | nil | | latitude | float | * | nil | nil | | longitude | float | * | nil | nil | ### EPlat::Order::LineItem | Attribute | Type | Shopify | BigCommerce | Etc | |-------------------------------|---------|---------|-------------|------| | id | integer | * | order[consignments][0][shipping][0][line_items][#i][id] | nil | | admin_graphql_api_id | string | * | nil | nil | | fulfillable_quantity | integer | * | nil | nil | | fulfillment_service | string | * | nil | nil | | fulfillment_status | string | * | nil | nil | | gift_card | boolean | * | nil | nil | | grams | integer | * | nil | nil | | name | string | * | order[consignments][0][shipping][0][line_items][#i][name] | nil | | price | string | * | order[consignments][0][shipping][0][line_items][#i][price] | nil | | price_set | hash | * | nil | nil | | product_exists | boolean | * | nil | nil | | product_id | integer | * | order[consignments][0][shipping][0][line_items][#i][product_id] | nil | | properties | array | * | nil | nil | | quantity | integer | * | order[consignments][0][shipping][0][line_items][#i][quantity] | nil | | requires_shipping | boolean | * | nil | nil | | sku | string | * | order[consignments][0][shipping][0][line_items][#i][sku] | nil | | taxable | boolean | * | nil | nil | | title | string | * | nil | nil | | total_discount | string | * | nil | nil | | total_discount_set | hash | * | nil | nil | | variant_id | integer | * | order[consignments][0][shipping][0][line_items][#i][variant_id] | nil | | variant_inventory_management | string | * | nil | nil | | variant_title | string | * | nil | nil | | vendor | string | * | nil | nil | | tax_lines | array | * | nil | nil | | duties | array | * | nil | nil | | discount_allocations | array | * | nil | nil | *line_item uses a virtual collection for BigCommerce, this allows us to present with the correct nesting position, whilst updating the native much deeper nested set below
Metafield ### EPlat::Metafield | Alias | Type | Shopify | BigCommerce | Etc | |-----------------|----------|----------------|----------------|-----| | created_at | datetime | * | date_created | nil | | description | string | * | description | nil | | id | integer | * | id | nil | | key | string | * | key | nil | | namespace | string | * | namespace | nil | | owner_id | integer | * | resource_id | nil | | owner_resource | string | * | resource_type | nil | | updated_at | datetime | * | date_modified | nil | | value | string | * | value | nil | | type | string | * | nil | nil | *Note: Bigcommerce always assumes a type of String and a native attribute permission_set of "read_and_sf_access"
ScriptTag ### EPlat::ScriptTag | Alias | Type | Shopify | BigCommerce | Etc | |---------------|----------------|---------------|--------------------|-------------------| | id | integer/string | id | uuid | | | src | string | src | src | | | created_at | datetime | created_at | date_created | | | updated_at | datetime | updated_at | date_modified | | | display_scope | string | display_scope | visibility | | | event | string | event | nil | | | cache | boolean | cache | nil | | *display_scope available options: `online_store`, `order_status`, `all` **Bigcommerce has some native attribute defaults set, which can be overwritten if needed: `location: "head"`, `auto_uninstall: true`, `kind: "src"`, `load_method: "async"`, `name: "app-script"`, `enabled: true`
Webhook ### EPlat::Webhook | Alias | Type | Shopify | BigCommerce | Etc | |-------------------------------|--------------|------------------------------|----------------------|-----| | address | string | address | destination | | | api_version | string | api_version | nil | | | created_at | datetime/Int | created_at | created_at | | | fields | array | fields | nil | | | format | string | format | nil | | | id | integer | id | id | | | metafield_namespaces | array | metafield_namespaces | nil | | | private_metafield_namespaces | array | private_metafield_namespaces | nil | | | topic | string | topic | scope | | | updated_at | datetime/Int | updated_at | updated_at | | *EPlat doesn't make any attemps to alias the varias topic/scope values between platforms. **Notice that BigCommerce uses updated_at and created_at for this resource. Unfortunately it's in a Time Integer format. Haven't yet got dynamic conversion so just tread carefully.




API Coverage

Base / Config | Method | ShopifyAPI Gem equivalent | Shopify - tested | BigCom - tested | -------------------------------------------- | ------------------------- | ----------------- | ------------------ | | EPlat::Session.new() | ::Session.new | * | * | | EPlat::Session.new() | ::Base.activate_session | * | * | | EPlat::Session.new() | ::Session.setup() | * | * | | EPlat.config.values[:shopify_api_version] | ::Baseapi_version | * | | | EPlat.config.values[:bigcommerce_api_version] | ::Baseapi_version | | * |
Shop | Method | Shopify - tested | BigCom - tested | Etc | | ----------------------------- | ----------------- | ----------------- | ------ | | ::Shop.current | * | * | | | shop.attribute | * | * | |
Product | Method | Shopify - tested | BigCom - tested | Etc | | ----------------------------- | ----------------- | ----------------- | ------ | | ::Product.last | * | * | | | ::Product.all | * | * | | | ::Product.attribute | * | * | | | ::Product.find(id) | * | * | | | ::Product.where(attr: '') | * | * | | | ::Product.find_by(attr: '') | * | * | | | ::Product.create(attr:) | * | * | | | ::Product.save | * | * | | | .save saves nested resources | only variants | | | | ::Product.delete(id) | * | * | | | ::Product.count | * | * | | | product.dup | * | * | | | product.variants | * | * | | | product.load_all_variants | * | * | | | product.find_variant(id) | * | * | | | product.images | * | * | | | products.next_page? | * | * | | | products.previous_page? | * | * | | | products.fetch_next_page | * | * | | | products.fetch_previous_page | * | * | | | products.previous_page_info | * | * | | | products.next_page_info | * | * | | ```ruby # The 2024 increased Shopify variants limit @product.load_all_variants #returns all variants. In Shopify's case it will keep on requesting in batches until it has the full amount (capped at 10x requests of 200 currently i.e. 2,000 variants) ### Pagination # ...How you might handle pagination. # Add pagination cursors to your link's params. This is available on any EPlat::Collection instance <%= link_to "previous products", "/", forward_page_info: products.previous_page_info %> <%= link_to "Next products", "/", backward_page_info: products.next_page_info %> # Then on the server, let EPlat handle the correct platform specific arguments to request with. EPlat::Product.find(:all, params: { EPlat::Current.e_plat_session.pagination_param(:forward) => params['forward_page_info'] }) EPlat::Product.find(:all, params: { EPlat::Current.e_plat_session.pagination_param(:backward) => params['backward_page_info'] }) ``` ### Product::Variant | Method | Shopify - tested | BigCom - tested | Etc | | ----------------------------- | ----------------- | ----------------- | ------ | | product.variants | * | * | | | product.find_variant | * | * | | | variants.attribute | * | * | | | variant.attributes.delete | * | * | | | variant.save | * | * | | * Nested resources currently need to be saved on their own instance. product.variants.first.save, as opposed to product.save * Also bear in mind that for platforms like BigCommerce, product and variant IDs are only unique within that store's context * so if storing these IDs locally, remember to query via the shop i.e. shop.listings.where(platform_product_id: 123)
Order | Method | Shopify - tested | BigCom - tested | Etc | | ----------------------------- | ----------------- | ----------------- | ------ | | ::Order.last | * | * | | | ::Order.all | * | * | | | ::Order.attribute | * | * | | | ::Order.find(id) | * | * | | | ::Order.where(title: '') | * | * | | | ::Order.find_by(title: '') | * | * | | | ::Order.create(attr: '', ) | * | * | | | ::Order.new(attr: '', ) | * | * | | | ::Order.save | * | * | | | ::Order.count | * | * | | | order.cancel | * | * | | | orders.next_page? | * | nil | | | orders.previous_page? | * | nil | | | orders.fetch_next_page | * | nil | | | orders.fetch_previous_page | * | nil | | *included nested resources: can update non-resource nested hashes like shipping_address, but not proper resources like customer
Metafield | Method | Shopify - tested | BigCom - tested | Etc | | ----------------------------- | ----------------- | ----------------- | ------ | | product.metafields | * | * | | | order.metafields | * | * | | | product.find_metafield(id) | * | * | | | order.find_metafield(id) | * | * | | | order.find_metafield(id) | * | * | | | product.add_metafield(EPlat::Metafield.new {}) |* | * | | | order.add_metafield(EPlat::Metafield.new {}) |* | * | | | .attribute | * | * | | | .save | * | * | | | .destroy | * | * | | | ::Metafield.create(attr: '') | * | * | | | ::Metafield.new(attr: '') | * | * | |
ScriptTag | Method | Shopify - tested | BigCom - tested | Etc | | -------------------------------- | ----------------- | ----------------- | ------ | | ::ScriptTag.new({}) | * | * | | | ::ScriptTag.create({}) | * | * | | | ::ScriptTag.last | * | * | | | ::ScriptTag.all | * | * | | | ::ScriptTag.find | * | * | | | .attribute | * | * | | | .save | * | * | | | .destroy | * | * | | *note that Bigcommerce uses UUID instead of ID for script tags. This should mostly be handled by EPlat, apart from when passing the value to .find
Webhook | Method | Shopify - tested | BigCom - tested | Etc | | -------------------------------- | ----------------- | ----------------- | ------ | | ::Webhook.new({}) | * | * | | | ::Webhook.create({}) | * | * | | | ::Webhook.last | * | * | | | ::Webhook.all | * | * | | | ::Webhook.find | * | * | | | .attribute | * | * | | | .save | * | * | | | .destroy | * | * | |
Shopify only These areas of the API will just support Shopify. ### RecurringApplicationCharge | Method | Shopify - tested | | -------------------------------------- | ----------------- | | ::RecurringApplicationCharge.current | * | | ::RecurringApplicationCharge.new({}) | * | | ::RecurringApplicationCharge.create({})| * | | ::RecurringApplicationCharge.last | * | | ::RecurringApplicationCharge.all | * | | ::RecurringApplicationCharge.find | * | | .attribute | * | | .save | * | | .cancel | * | | .destroy | * | | .usage_charges | * | *The .current charge is the active charge for the app with the session's store. Only one charge can be active at any time.
### RecurringApplicationCharge::UsageCharge | Method | Shopify - tested | | --------------------------------------------------------------------- | ----------------- | | ::UsageCharge.last(params: r.id) | * | | ::UsageCharge.all(params: r.id) | * | | ::UsageCharge.find(id, params: r.id) | * | | ::UsageCharge.new(r.id, ...) | * | | ::UsageCharge.create(r.id, ...) | * | | .save | * | | .attribute | * | *Note no :update or :delete options supported. ** the recurring_application_charge_id has to be passed to any requests called on the class.
Outside of the scope of EPlat
  • ShopifyAPI::Asset is depricated. (check_for_store_two_pont_o in main app code.)
  • ShopifyAPI::AccessScope doesn't have other platform API equivilents. (although should be kept track of locally)
  • GraphQL. EPlat just handles REST (for now, although we plan to change the internals for Shopify product to use Graphql under the hood)


[!NOTE] For all resources, we also have a EPlat::ShopifyWebhook::resource class. These use the old REST API mappings that the webhooks still use. At PreProduct we interact with cached webhook hashes using these classes, e.g. EPlat::ShopifyWebhook::Product.new({...}). Meaning we can safely call getter methods and access the usual EPlat schema.



Request Syntax

### activate session
EPlat::Session.new(
    platform: :shopify, 
    store_url: "hi.myshopify.com", 
    api_token: 11223344
)

### create new record
product = EPlat::Product.new(title: 't-shirt')
product.save
# or... 
EPlat::Product.create(title: 't-shirt')
new_product = product.dup #duplicates entry without saving

### delete record
EPlat::Product.delete(params[:id])
# or... 
EPlat::Product.find(my_id).destroy

### save record
product = EPlat::Product.new(title: 't-shirt')
product.save # true or false
product.errors # active record like errors if .save returned false
product.formatted_id #returns the resource ID in the platform's format. i.e. Shopify Product would be "gid://shopify/Product/xxx", Shopify Order would be 123, BC order: 123

product.full_response # <Net::HTTPOK>
product.headers # { "date"=>"Fri, 17 Nov 2023 14:25:53 GMT", ...}
JSON.parse(product.full_response.body) # "{...}"


### get records
EPlat::Product.find(101) # GET EPlat::Product.first(args)) (or EPlat::Product.last(args))
EPlat::Product.all 
EPlat::Product.last 
EPlat::Product.where(title: "tshirt") # GET ?title=tshirt
EPlat::Product.find_by(title: "tshirt") # GET ?title=tshirt &.first
EPlat::Product.find(:all, params: {title: "tshirt"}) # ?title=tshirt

EPlat::Product.find(99, from: :leader) # GET /platforms_resource_path/leader.json
EPlat::Product.find(99, from: "/product/1/specific_url.json") #GET /product/1/specific_url.json

### count records
EPlat::Product.count # 2

# Nested resources - pass in the parent resource's ID to the params hash
EPlat::Product::Variant.find(variant_id, params: {product: product.id}) # /admin/api/2024-07/products/{{ product.id }}/variants/{{ variant_id }}.json 
EPlat::Product::Variant.collection_path(product: 5) # /admin/api/2024-07/products/5/variants.json




Attribute info


# Attributes
product.attributes  #return all native platform attributes
product.mapped_attributes.entries #return all mapped e_plat attributes for a resource

# Attribute keys
product.native_keys #An array of the native attribute keys
product.mapped_attributes. #An array of the e_plat attribute keys

# look up mapping
product.mapping.aliases # a hash of the mapped aliases. {native_attribute => e_plat_attribute, ...}
product.mapped? "body_html" #check if a platforms resource is mapped to a specific EPlat alias

# In the context of a Bigcommerce product that has aliases:
product.changed_attributes # {}
product.title = "oi"
product.changed_attributes # {"name"=>"oi", "title"=>"oi"}  
#title is the e_plat key which won't be included in requests to the server. The native key 'name' has automatically been updated and will be sent in requests.

product.as_json # hash of any updated attributes
product.as_full_json # hash of all attributes, regardless of if they've been updated or not
product.to_json # JSON string of any updated_attributes
product.to_full_json # JSON string of all attributes. regardless of if they've been updated or not
product.as_eplat_json # hash of all resource's EPlat attributes, values as EPlat getters produce
product.to_eplat_json # JSON of all resource's EPlat attributes, values as EPlat getters produce