spree_api 5.3.4 → 5.4.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +71 -33
- data/Rakefile +25 -0
- data/app/controllers/concerns/spree/api/v3/api_key_authentication.rb +51 -0
- data/app/controllers/concerns/spree/api/v3/error_handler.rb +255 -0
- data/app/controllers/concerns/spree/api/v3/http_caching.rb +90 -0
- data/app/controllers/concerns/spree/api/v3/jwt_authentication.rb +95 -0
- data/app/controllers/concerns/spree/api/v3/locale_and_currency.rb +73 -0
- data/app/controllers/concerns/spree/api/v3/order_concern.rb +51 -0
- data/app/controllers/concerns/spree/api/v3/resource_serializer.rb +41 -0
- data/app/controllers/spree/api/v3/base_controller.rb +42 -0
- data/app/controllers/spree/api/v3/resource_controller.rb +210 -0
- data/app/controllers/spree/api/v3/store/auth_controller.rb +140 -0
- data/app/controllers/spree/api/v3/store/base_controller.rb +12 -0
- data/app/controllers/spree/api/v3/store/cart_controller.rb +82 -0
- data/app/controllers/spree/api/v3/store/countries_controller.rb +31 -0
- data/app/controllers/spree/api/v3/store/currencies_controller.rb +18 -0
- data/app/controllers/spree/api/v3/store/customer/account_controller.rb +38 -0
- data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +85 -0
- data/app/controllers/spree/api/v3/store/customer/credit_cards_controller.rb +31 -0
- data/app/controllers/spree/api/v3/store/customer/gift_cards_controller.rb +36 -0
- data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +35 -0
- data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +83 -0
- data/app/controllers/spree/api/v3/store/digitals_controller.rb +37 -0
- data/app/controllers/spree/api/v3/store/locales_controller.rb +24 -0
- data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +68 -0
- data/app/controllers/spree/api/v3/store/orders/line_items_controller.rb +87 -0
- data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +43 -0
- data/app/controllers/spree/api/v3/store/orders/payment_sessions_controller.rb +96 -0
- data/app/controllers/spree/api/v3/store/orders/payments_controller.rb +45 -0
- data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +53 -0
- data/app/controllers/spree/api/v3/store/orders/store_credits_controller.rb +42 -0
- data/app/controllers/spree/api/v3/store/orders_controller.rb +125 -0
- data/app/controllers/spree/api/v3/store/products/filters_controller.rb +38 -0
- data/app/controllers/spree/api/v3/store/products_controller.rb +74 -0
- data/app/controllers/spree/api/v3/store/resource_controller.rb +12 -0
- data/app/controllers/spree/api/v3/store/stores_controller.rb +26 -0
- data/app/controllers/spree/api/v3/store/taxonomies_controller.rb +19 -0
- data/app/controllers/spree/api/v3/store/taxons/products_controller.rb +37 -0
- data/app/controllers/spree/api/v3/store/taxons_controller.rb +34 -0
- data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +33 -0
- data/app/controllers/spree/api/v3/store/wishlists_controller.rb +41 -0
- data/app/serializers/spree/api/v3/address_serializer.rb +22 -0
- data/app/serializers/spree/api/v3/admin/customer_serializer.rb +43 -0
- data/app/serializers/spree/api/v3/admin/metafield_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +39 -0
- data/app/serializers/spree/api/v3/admin/price_serializer.rb +21 -0
- data/app/serializers/spree/api/v3/admin/product_serializer.rb +47 -0
- data/app/serializers/spree/api/v3/admin/taxon_serializer.rb +20 -0
- data/app/serializers/spree/api/v3/admin/taxonomy_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/admin/variant_serializer.rb +44 -0
- data/app/serializers/spree/api/v3/asset_serializer.rb +20 -0
- data/app/serializers/spree/api/v3/base_serializer.rb +98 -0
- data/app/serializers/spree/api/v3/country_serializer.rb +35 -0
- data/app/serializers/spree/api/v3/credit_card_serializer.rb +12 -0
- data/app/serializers/spree/api/v3/currency_serializer.rb +14 -0
- data/app/serializers/spree/api/v3/customer_return_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/customer_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/digital_link_serializer.rb +30 -0
- data/app/serializers/spree/api/v3/digital_serializer.rb +17 -0
- data/app/serializers/spree/api/v3/export_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/gift_card_serializer.rb +78 -0
- data/app/serializers/spree/api/v3/image_serializer.rb +43 -0
- data/app/serializers/spree/api/v3/import_row_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/import_serializer.rb +32 -0
- data/app/serializers/spree/api/v3/invitation_serializer.rb +47 -0
- data/app/serializers/spree/api/v3/line_item_serializer.rb +48 -0
- data/app/serializers/spree/api/v3/locale_serializer.rb +14 -0
- data/app/serializers/spree/{v2/storefront → api/v3}/metafield_serializer.rb +5 -3
- data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +27 -0
- data/app/serializers/spree/api/v3/option_type_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/option_value_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/order_promotion_serializer.rb +16 -0
- data/app/serializers/spree/api/v3/order_serializer.rb +39 -0
- data/app/serializers/spree/api/v3/payment_method_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/payment_serializer.rb +54 -0
- data/app/serializers/spree/api/v3/payment_session_serializer.rb +32 -0
- data/app/serializers/spree/api/v3/payment_setup_session_serializer.rb +33 -0
- data/app/serializers/spree/api/v3/payment_source_serializer.rb +18 -0
- data/app/serializers/spree/api/v3/post_category_serializer.rb +13 -0
- data/app/serializers/spree/api/v3/post_serializer.rb +25 -0
- data/app/serializers/spree/api/v3/price_serializer.rb +34 -0
- data/app/serializers/spree/api/v3/product_serializer.rb +108 -0
- data/app/serializers/spree/api/v3/promotion_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/refund_serializer.rb +31 -0
- data/app/serializers/spree/api/v3/reimbursement_serializer.rb +28 -0
- data/app/serializers/spree/api/v3/report_serializer.rb +29 -0
- data/app/serializers/spree/api/v3/return_authorization_serializer.rb +31 -0
- data/app/serializers/spree/api/v3/return_item_serializer.rb +53 -0
- data/app/serializers/spree/api/v3/shipment_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/shipping_method_serializer.rb +11 -0
- data/app/serializers/spree/api/v3/shipping_rate_serializer.rb +26 -0
- data/app/serializers/spree/api/v3/state_serializer.rb +14 -0
- data/app/serializers/spree/api/v3/stock_item_serializer.rb +23 -0
- data/app/serializers/spree/api/v3/stock_location_serializer.rb +18 -0
- data/app/serializers/spree/api/v3/stock_movement_serializer.rb +24 -0
- data/app/serializers/spree/api/v3/stock_transfer_serializer.rb +25 -0
- data/app/serializers/spree/api/v3/store_credit_serializer.rb +37 -0
- data/app/serializers/spree/api/v3/store_serializer.rb +38 -0
- data/app/serializers/spree/api/v3/taxon_serializer.rb +78 -0
- data/app/serializers/spree/api/v3/taxonomy_serializer.rb +33 -0
- data/app/serializers/spree/api/v3/variant_serializer.rb +86 -0
- data/app/serializers/spree/api/v3/wished_item_serializer.rb +22 -0
- data/app/serializers/spree/api/v3/wishlist_serializer.rb +25 -0
- data/app/services/spree/api/v3/filters_aggregator.rb +156 -0
- data/app/services/spree/api/v3/orders/update.rb +103 -0
- data/config/initializers/alba.rb +5 -0
- data/config/initializers/pagy.rb +10 -0
- data/config/initializers/typelizer.rb +25 -0
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +63 -196
- data/lib/spree/api/dependencies.rb +68 -0
- data/lib/spree/api/engine.rb +0 -5
- data/lib/spree/api/openapi/schema_helper.rb +177 -0
- data/lib/spree/api/testing_support/factories.rb +1 -3
- data/lib/spree/api/testing_support/v3/base.rb +118 -0
- data/lib/spree/api.rb +7 -4
- metadata +131 -264
- data/LICENSE.md +0 -57
- data/app/controllers/concerns/spree/api/v2/caching.rb +0 -40
- data/app/controllers/concerns/spree/api/v2/coupon_codes_helper.rb +0 -29
- data/app/controllers/concerns/spree/api/v2/number_resource.rb +0 -11
- data/app/controllers/concerns/spree/api/v2/platform/nested_set_reposition_concern.rb +0 -37
- data/app/controllers/concerns/spree/api/v2/platform/promotion_calculator_params.rb +0 -17
- data/app/controllers/concerns/spree/api/v2/platform/promotion_rule_params.rb +0 -16
- data/app/controllers/concerns/spree/api/v2/product_list_includes.rb +0 -21
- data/app/controllers/concerns/spree/api/v2/storefront/metadata_controller_concern.rb +0 -18
- data/app/controllers/concerns/spree/api/v2/storefront/order_concern.rb +0 -49
- data/app/controllers/spree/api/v2/base_controller.rb +0 -233
- data/app/controllers/spree/api/v2/data_feeds/google_controller.rb +0 -24
- data/app/controllers/spree/api/v2/platform/addresses_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/adjustments_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/classifications_controller.rb +0 -26
- data/app/controllers/spree/api/v2/platform/countries_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/data_feeds_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/digital_links_controller.rb +0 -29
- data/app/controllers/spree/api/v2/platform/digitals_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/gift_cards_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/line_items_controller.rb +0 -63
- data/app/controllers/spree/api/v2/platform/option_types_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/option_values_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/orders_controller.rb +0 -167
- data/app/controllers/spree/api/v2/platform/payment_methods_controller.rb +0 -31
- data/app/controllers/spree/api/v2/platform/payments_controller.rb +0 -21
- data/app/controllers/spree/api/v2/platform/products_controller.rb +0 -41
- data/app/controllers/spree/api/v2/platform/promotion_actions_controller.rb +0 -34
- data/app/controllers/spree/api/v2/platform/promotion_categories_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/promotion_rules_controller.rb +0 -29
- data/app/controllers/spree/api/v2/platform/promotions_controller.rb +0 -35
- data/app/controllers/spree/api/v2/platform/resource_controller.rb +0 -154
- data/app/controllers/spree/api/v2/platform/roles_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/shipments_controller.rb +0 -147
- data/app/controllers/spree/api/v2/platform/shipping_categories_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/shipping_methods_controller.rb +0 -28
- data/app/controllers/spree/api/v2/platform/states_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/stock_items_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/stock_locations_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/store_credit_categories_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/store_credit_types_controller.rb +0 -19
- data/app/controllers/spree/api/v2/platform/store_credits_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/tax_categories_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/tax_rates_controller.rb +0 -27
- data/app/controllers/spree/api/v2/platform/taxonomies_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/taxons_controller.rb +0 -59
- data/app/controllers/spree/api/v2/platform/users_controller.rb +0 -37
- data/app/controllers/spree/api/v2/platform/variants_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/wished_items_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/wishlists_controller.rb +0 -23
- data/app/controllers/spree/api/v2/platform/zones_controller.rb +0 -23
- data/app/controllers/spree/api/v2/resource_controller.rb +0 -79
- data/app/controllers/spree/api/v2/storefront/account/addresses_controller.rb +0 -77
- data/app/controllers/spree/api/v2/storefront/account/credit_cards_controller.rb +0 -52
- data/app/controllers/spree/api/v2/storefront/account/orders_controller.rb +0 -50
- data/app/controllers/spree/api/v2/storefront/account_controller.rb +0 -52
- data/app/controllers/spree/api/v2/storefront/cart_controller.rb +0 -246
- data/app/controllers/spree/api/v2/storefront/checkout_controller.rb +0 -183
- data/app/controllers/spree/api/v2/storefront/countries_controller.rb +0 -57
- data/app/controllers/spree/api/v2/storefront/digitals_controller.rb +0 -58
- data/app/controllers/spree/api/v2/storefront/order_status_controller.rb +0 -34
- data/app/controllers/spree/api/v2/storefront/policies_controller.rb +0 -31
- data/app/controllers/spree/api/v2/storefront/post_categories_controller.rb +0 -35
- data/app/controllers/spree/api/v2/storefront/posts_controller.rb +0 -51
- data/app/controllers/spree/api/v2/storefront/products_controller.rb +0 -66
- data/app/controllers/spree/api/v2/storefront/stores_controller.rb +0 -27
- data/app/controllers/spree/api/v2/storefront/taxons_controller.rb +0 -51
- data/app/controllers/spree/api/v2/storefront/variants_controller.rb +0 -41
- data/app/controllers/spree/api/v2/storefront/wishlists_controller.rb +0 -214
- data/app/helpers/spree/api/v2/collection_options_helpers.rb +0 -46
- data/app/helpers/spree/api/v2/display_money_helper.rb +0 -63
- data/app/helpers/spree/api/v2/store_media_serializer_images_concern.rb +0 -30
- data/app/models/concerns/spree/user_api_authentication.rb +0 -19
- data/app/models/concerns/spree/user_api_methods.rb +0 -7
- data/app/models/spree/oauth_access_grant.rb +0 -7
- data/app/models/spree/oauth_access_token.rb +0 -7
- data/app/models/spree/oauth_application.rb +0 -22
- data/app/paginators/spree/api/paginate.rb +0 -68
- data/app/presenters/spree/api/products/filters_presenter.rb +0 -39
- data/app/serializers/concerns/spree/api/v2/image_transformation_concern.rb +0 -15
- data/app/serializers/concerns/spree/api/v2/public_metafields_concern.rb +0 -15
- data/app/serializers/concerns/spree/api/v2/resource_serializer_concern.rb +0 -42
- data/app/serializers/concerns/spree/api/v2/taxon_image_transformation_concern.rb +0 -15
- data/app/serializers/spree/api/v2/base_serializer.rb +0 -43
- data/app/serializers/spree/api/v2/platform/address_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/adjustment_serializer.rb +0 -20
- data/app/serializers/spree/api/v2/platform/admin_user_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/asset_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/base_serializer.rb +0 -10
- data/app/serializers/spree/api/v2/platform/calculator_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/classification_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/country_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/credit_card_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/customer_return_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/data_feed_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/digital_link_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/digital_serializer.rb +0 -29
- data/app/serializers/spree/api/v2/platform/gift_card_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/image_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/inventory_unit_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/line_item_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/log_entry_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/metafield_serializer.rb +0 -21
- data/app/serializers/spree/api/v2/platform/option_type_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/option_value_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/order_promotion_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/order_serializer.rb +0 -31
- data/app/serializers/spree/api/v2/platform/payment_capture_event_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/payment_method_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/payment_serializer.rb +0 -22
- data/app/serializers/spree/api/v2/platform/payment_source_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/price_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/product_property_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/product_serializer.rb +0 -90
- data/app/serializers/spree/api/v2/platform/promotion_action_line_item_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/promotion_action_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/promotion_category_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/promotion_rule_serializer.rb +0 -21
- data/app/serializers/spree/api/v2/platform/promotion_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/property_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/prototype_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/refund_reason_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/refund_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/reimbursement_credit_serializer.rb +0 -10
- data/app/serializers/spree/api/v2/platform/reimbursement_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/reimbursement_type_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/return_authorization_reason_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/return_authorization_serializer.rb +0 -17
- data/app/serializers/spree/api/v2/platform/return_item_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/role_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/shipment_serializer.rb +0 -22
- data/app/serializers/spree/api/v2/platform/shipping_category_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/shipping_method_serializer.rb +0 -16
- data/app/serializers/spree/api/v2/platform/shipping_rate_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/state_change_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/state_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/stock_item_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/stock_location_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/stock_movement_serializer.rb +0 -11
- data/app/serializers/spree/api/v2/platform/stock_transfer_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/store_credit_category_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/store_credit_event_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/store_credit_serializer.rb +0 -18
- data/app/serializers/spree/api/v2/platform/store_credit_type_serializer.rb +0 -12
- data/app/serializers/spree/api/v2/platform/store_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/tax_category_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/tax_rate_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/taxon_image_serializer.rb +0 -15
- data/app/serializers/spree/api/v2/platform/taxon_serializer.rb +0 -47
- data/app/serializers/spree/api/v2/platform/taxonomy_serializer.rb +0 -14
- data/app/serializers/spree/api/v2/platform/user_serializer.rb +0 -37
- data/app/serializers/spree/api/v2/platform/variant_serializer.rb +0 -66
- data/app/serializers/spree/api/v2/platform/wished_item_serializer.rb +0 -29
- data/app/serializers/spree/api/v2/platform/wishlist_serializer.rb +0 -19
- data/app/serializers/spree/api/v2/platform/zone_member_serializer.rb +0 -13
- data/app/serializers/spree/api/v2/platform/zone_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/address_serializer.rb +0 -22
- data/app/serializers/spree/v2/storefront/base_serializer.rb +0 -10
- data/app/serializers/spree/v2/storefront/cart_serializer.rb +0 -67
- data/app/serializers/spree/v2/storefront/country_serializer.rb +0 -24
- data/app/serializers/spree/v2/storefront/credit_card_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/digital_link_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/estimated_shipping_rate_serializer.rb +0 -35
- data/app/serializers/spree/v2/storefront/gift_card_serializer.rb +0 -16
- data/app/serializers/spree/v2/storefront/image_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/line_item_serializer.rb +0 -23
- data/app/serializers/spree/v2/storefront/option_type_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/option_value_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/order_promotion_serializer.rb +0 -14
- data/app/serializers/spree/v2/storefront/order_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/payment_method_serializer.rb +0 -17
- data/app/serializers/spree/v2/storefront/payment_serializer.rb +0 -20
- data/app/serializers/spree/v2/storefront/payment_source_serializer.rb +0 -12
- data/app/serializers/spree/v2/storefront/policy_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/post_category_serializer.rb +0 -23
- data/app/serializers/spree/v2/storefront/post_serializer.rb +0 -51
- data/app/serializers/spree/v2/storefront/product_property_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/product_serializer.rb +0 -92
- data/app/serializers/spree/v2/storefront/shipment_serializer.rb +0 -26
- data/app/serializers/spree/v2/storefront/shipping_category_serializer.rb +0 -10
- data/app/serializers/spree/v2/storefront/shipping_method_serializer.rb +0 -12
- data/app/serializers/spree/v2/storefront/shipping_rate_serializer.rb +0 -26
- data/app/serializers/spree/v2/storefront/state_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/stock_location_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_credit_category_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_credit_event_serializer.rb +0 -15
- data/app/serializers/spree/v2/storefront/store_credit_serializer.rb +0 -19
- data/app/serializers/spree/v2/storefront/store_credit_type_serializer.rb +0 -11
- data/app/serializers/spree/v2/storefront/store_serializer.rb +0 -18
- data/app/serializers/spree/v2/storefront/taxon_image_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/taxon_serializer.rb +0 -55
- data/app/serializers/spree/v2/storefront/taxonomy_serializer.rb +0 -13
- data/app/serializers/spree/v2/storefront/user_serializer.rb +0 -33
- data/app/serializers/spree/v2/storefront/variant_serializer.rb +0 -58
- data/app/serializers/spree/v2/storefront/wished_item_serializer.rb +0 -29
- data/app/serializers/spree/v2/storefront/wishlist_serializer.rb +0 -17
- data/config/initializers/doorkeeper.rb +0 -50
- data/config/initializers/json_api_mime_types.rb +0 -8
- data/config/initializers/user_class_extensions.rb +0 -7
- data/db/migrate/20100107141738_add_api_key_to_spree_users.rb +0 -7
- data/db/migrate/20120411123334_resize_api_key_field.rb +0 -7
- data/db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb +0 -7
- data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +0 -7
- data/db/migrate/20180320110726_create_doorkeeper_tables.rb +0 -69
- data/db/migrate/20210727102516_change_integer_id_columns_type.rb +0 -9
- data/db/migrate/20210919183228_enable_polymorphic_resource_owner.rb +0 -21
- data/lib/generators/spree/api/install/install_generator.rb +0 -24
- data/lib/spree/api/testing_support/factories/oauth_application_factory.rb +0 -6
- data/lib/spree/api/testing_support/serializers.rb +0 -15
- data/lib/spree/api/testing_support/v2/base.rb +0 -13
- data/lib/spree/api/testing_support/v2/current_order.rb +0 -116
- data/lib/spree/api/testing_support/v2/platform_contexts.rb +0 -272
- data/lib/spree/api/testing_support/v2/serializers_params.rb +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9fa3dee62eb2625c3d4c9d7bd34bad4ca81cf4d2674f769392a24df5e8a01953
|
|
4
|
+
data.tar.gz: cce1ee0d81f70c7c06350faed5aee5ccc8e2c1e510f1e598f29e48598c7d0d0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8dd621f3a2059a1308cfb49fc4ff3c7b9e9ee3be7378d6ba1242d387e157cb5c6b2504e32b9df40fed8a15eb5af52ffecfc506b970c99a08d1a4a9e71d11385e
|
|
7
|
+
data.tar.gz: 947276ed295dc4a13408caa6c6da8b5c90d1661b995bd8396007b4363b45c91b9fedf4594261928440ac98bfb99cc8d907f022061d137b227e666d41ad7f0ffd
|
data/README.md
CHANGED
|
@@ -8,55 +8,76 @@ Spree API provides RESTful API endpoints for building custom storefronts, mobile
|
|
|
8
8
|
|
|
9
9
|
This gem includes:
|
|
10
10
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
11
|
+
- **Store API v3** - Customer-facing endpoints for cart, checkout, products, and accounts
|
|
12
|
+
- **Admin API v3** - Administrative endpoints for managing orders, products, and store settings
|
|
13
13
|
- **Webhooks** - Event-driven notifications to external systems
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
14
|
+
- **API Key Authentication** - Secure token-based authentication with scopes
|
|
15
|
+
- **Alba Serializers** - Fast, flexible JSON serialization with TypeScript type generation
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
19
|
This gem is included in every Spree installation. No additional steps are required.
|
|
20
20
|
|
|
21
|
-
## API Endpoints
|
|
21
|
+
## API v3 Endpoints
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Store API
|
|
24
24
|
|
|
25
|
-
The
|
|
25
|
+
The Store API is designed for building custom storefronts:
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
GET /api/
|
|
29
|
-
GET /api/
|
|
30
|
-
GET /api/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
PATCH /api/
|
|
34
|
-
|
|
28
|
+
GET /api/v3/products
|
|
29
|
+
GET /api/v3/products/:id
|
|
30
|
+
GET /api/v3/taxons
|
|
31
|
+
GET /api/v3/taxonomies
|
|
32
|
+
POST /api/v3/cart
|
|
33
|
+
PATCH /api/v3/cart/add_item
|
|
34
|
+
PATCH /api/v3/checkout
|
|
35
|
+
GET /api/v3/account
|
|
35
36
|
```
|
|
36
37
|
|
|
37
|
-
###
|
|
38
|
+
### Admin API
|
|
38
39
|
|
|
39
|
-
The
|
|
40
|
+
The Admin API provides full administrative access:
|
|
40
41
|
|
|
41
42
|
```
|
|
42
|
-
GET /api/
|
|
43
|
-
POST /api/
|
|
44
|
-
PATCH /api/
|
|
45
|
-
DELETE /api/
|
|
43
|
+
GET /api/v3/admin/orders
|
|
44
|
+
POST /api/v3/admin/products
|
|
45
|
+
PATCH /api/v3/admin/variants/:id
|
|
46
|
+
DELETE /api/v3/admin/line_items/:id
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
## Authentication
|
|
49
50
|
|
|
50
|
-
###
|
|
51
|
+
### API Key Authentication
|
|
52
|
+
|
|
53
|
+
Create API keys with appropriate scopes:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# Store API key (customer-facing)
|
|
57
|
+
api_key = Spree::ApiKey.create!(
|
|
58
|
+
name: 'My Storefront',
|
|
59
|
+
scope: 'store',
|
|
60
|
+
store: current_store
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Admin API key (full access)
|
|
64
|
+
admin_key = Spree::ApiKey.create!(
|
|
65
|
+
name: 'Admin Integration',
|
|
66
|
+
scope: 'admin',
|
|
67
|
+
store: current_store
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Use the API key in requests:
|
|
51
72
|
|
|
52
73
|
```bash
|
|
53
|
-
#
|
|
54
|
-
curl -
|
|
55
|
-
-
|
|
74
|
+
# Store API
|
|
75
|
+
curl -H "Authorization: Bearer spree_pk_xxx" \
|
|
76
|
+
https://your-store.com/api/v3/products
|
|
56
77
|
|
|
57
|
-
#
|
|
58
|
-
curl -H "Authorization: Bearer
|
|
59
|
-
https://your-store.com/api/
|
|
78
|
+
# Admin API
|
|
79
|
+
curl -H "Authorization: Bearer spree_sk_xxx" \
|
|
80
|
+
https://your-store.com/api/v3/admin/orders
|
|
60
81
|
```
|
|
61
82
|
|
|
62
83
|
### Guest Cart Token
|
|
@@ -65,25 +86,43 @@ For guest checkout, use the `X-Spree-Order-Token` header:
|
|
|
65
86
|
|
|
66
87
|
```bash
|
|
67
88
|
curl -H "X-Spree-Order-Token: ORDER_TOKEN" \
|
|
68
|
-
https://your-store.com/api/
|
|
89
|
+
https://your-store.com/api/v3/cart
|
|
69
90
|
```
|
|
70
91
|
|
|
71
92
|
## Serializers
|
|
72
93
|
|
|
73
|
-
API
|
|
94
|
+
API v3 uses Alba serializers for fast JSON serialization. Serializers are organized by scope:
|
|
95
|
+
|
|
96
|
+
- `app/serializers/spree/api/v3/` - Store API serializers
|
|
97
|
+
- `app/serializers/spree/api/v3/admin/` - Admin API serializers
|
|
98
|
+
|
|
99
|
+
Customize serializers by creating your own:
|
|
74
100
|
|
|
75
101
|
```ruby
|
|
76
102
|
# app/serializers/my_app/product_serializer.rb
|
|
77
103
|
module MyApp
|
|
78
|
-
class ProductSerializer < Spree::
|
|
104
|
+
class ProductSerializer < Spree::Api::V3::ProductSerializer
|
|
79
105
|
attribute :custom_field
|
|
80
106
|
end
|
|
81
107
|
end
|
|
82
108
|
|
|
83
109
|
# Configure in initializer
|
|
84
|
-
Spree.api.
|
|
110
|
+
Spree.api.product_serializer = 'MyApp::ProductSerializer'
|
|
85
111
|
```
|
|
86
112
|
|
|
113
|
+
## TypeScript Types
|
|
114
|
+
|
|
115
|
+
TypeScript types are automatically generated from serializers using [typelizer](https://github.com/skryukov/typelizer):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Generate TypeScript types
|
|
119
|
+
bundle exec rake typelizer:generate
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Types are output to `sdk/src/types/generated/` with naming:
|
|
123
|
+
- Store types: `StoreProduct`, `StoreOrder`, etc.
|
|
124
|
+
- Admin types: `AdminProduct`, `AdminOrder`, etc.
|
|
125
|
+
|
|
87
126
|
## Testing
|
|
88
127
|
|
|
89
128
|
```bash
|
|
@@ -94,6 +133,5 @@ bundle exec rspec
|
|
|
94
133
|
|
|
95
134
|
## Documentation
|
|
96
135
|
|
|
97
|
-
- [
|
|
98
|
-
- [Platform API Reference](https://docs.spreecommerce.org/api/platform)
|
|
136
|
+
- [API Reference](https://docs.spreecommerce.org/api)
|
|
99
137
|
- [Authentication Guide](https://docs.spreecommerce.org/developer/api/authentication)
|
data/Rakefile
CHANGED
|
@@ -23,7 +23,32 @@ namespace :rswag do
|
|
|
23
23
|
'spec/integration/**/*_spec.rb'
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
+
# OPENAPI env var prevents spec_helper from overriding --order defined with :random
|
|
27
|
+
ENV['OPENAPI'] = 'true'
|
|
26
28
|
t.rspec_opts = ['--format Rswag::Specs::SwaggerFormatter', '--order defined']
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|
|
32
|
+
|
|
33
|
+
namespace :typelizer do
|
|
34
|
+
desc 'Generate TypeScript types from Alba serializers'
|
|
35
|
+
task :generate do
|
|
36
|
+
ENV['RAILS_ENV'] ||= 'test'
|
|
37
|
+
ENV['DISABLE_TYPELIZER'] = 'false'
|
|
38
|
+
|
|
39
|
+
require File.expand_path('spec/dummy/config/environment', __dir__)
|
|
40
|
+
|
|
41
|
+
# Eager load serializers so typelizer can find them
|
|
42
|
+
serializers_path = File.expand_path('app/serializers/spree/api/v3', __dir__)
|
|
43
|
+
Rails.autoloaders.main.eager_load_dir(serializers_path)
|
|
44
|
+
|
|
45
|
+
require 'typelizer/generator'
|
|
46
|
+
serializers = Typelizer::Generator.call(force: true)
|
|
47
|
+
|
|
48
|
+
puts "Generated TypeScript types for #{serializers.size} serializers"
|
|
49
|
+
puts "Output: #{Typelizer.configuration.writer_config.output_dir}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc 'Clean and regenerate TypeScript types'
|
|
53
|
+
task refresh: :generate
|
|
54
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module ApiKeyAuthentication
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
attr_reader :current_api_key
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def authenticate_api_key!
|
|
12
|
+
@current_api_key = current_store.api_keys.active.publishable.find_by(token: extract_api_key)
|
|
13
|
+
|
|
14
|
+
unless @current_api_key
|
|
15
|
+
render_error(
|
|
16
|
+
code: ErrorHandler::ERROR_CODES[:invalid_token],
|
|
17
|
+
message: 'Valid API key required',
|
|
18
|
+
status: :unauthorized
|
|
19
|
+
)
|
|
20
|
+
return false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Spree::ApiKeyTouchJob.perform_later(@current_api_key.id)
|
|
24
|
+
true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def authenticate_secret_key!
|
|
28
|
+
@current_api_key = current_store.api_keys.active.secret.find_by(token: extract_api_key)
|
|
29
|
+
|
|
30
|
+
unless @current_api_key
|
|
31
|
+
render_error(
|
|
32
|
+
code: ErrorHandler::ERROR_CODES[:invalid_token],
|
|
33
|
+
message: 'Valid secret API key required',
|
|
34
|
+
status: :unauthorized
|
|
35
|
+
)
|
|
36
|
+
return false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Spree::ApiKeyTouchJob.perform_later(@current_api_key.id)
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def extract_api_key
|
|
46
|
+
request.headers['X-Spree-Api-Key'].presence || params[:api_key]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module ErrorHandler
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
# Stripe-style error codes for consistent API error responses
|
|
8
|
+
ERROR_CODES = {
|
|
9
|
+
# Authentication & authorization errors
|
|
10
|
+
authentication_required: 'authentication_required',
|
|
11
|
+
authentication_failed: 'authentication_failed',
|
|
12
|
+
access_denied: 'access_denied',
|
|
13
|
+
invalid_token: 'invalid_token',
|
|
14
|
+
invalid_provider: 'invalid_provider',
|
|
15
|
+
|
|
16
|
+
# Resource errors
|
|
17
|
+
record_not_found: 'record_not_found',
|
|
18
|
+
resource_invalid: 'resource_invalid',
|
|
19
|
+
|
|
20
|
+
# Order errors
|
|
21
|
+
order_not_found: 'order_not_found',
|
|
22
|
+
order_already_completed: 'order_already_completed',
|
|
23
|
+
order_cannot_transition: 'order_cannot_transition',
|
|
24
|
+
order_empty: 'order_empty',
|
|
25
|
+
order_invalid_state: 'order_invalid_state',
|
|
26
|
+
|
|
27
|
+
# Line item errors
|
|
28
|
+
line_item_not_found: 'line_item_not_found',
|
|
29
|
+
variant_not_found: 'variant_not_found',
|
|
30
|
+
insufficient_stock: 'insufficient_stock',
|
|
31
|
+
invalid_quantity: 'invalid_quantity',
|
|
32
|
+
|
|
33
|
+
# Validation errors
|
|
34
|
+
validation_error: 'validation_error',
|
|
35
|
+
parameter_missing: 'parameter_missing',
|
|
36
|
+
parameter_invalid: 'parameter_invalid',
|
|
37
|
+
|
|
38
|
+
# Payment errors
|
|
39
|
+
payment_failed: 'payment_failed',
|
|
40
|
+
payment_processing_error: 'payment_processing_error',
|
|
41
|
+
gateway_error: 'gateway_error',
|
|
42
|
+
|
|
43
|
+
# Digital download errors
|
|
44
|
+
attachment_missing: 'attachment_missing',
|
|
45
|
+
download_unauthorized: 'download_unauthorized',
|
|
46
|
+
digital_link_expired: 'digital_link_expired',
|
|
47
|
+
download_limit_exceeded: 'download_limit_exceeded',
|
|
48
|
+
|
|
49
|
+
# General errors
|
|
50
|
+
processing_error: 'processing_error',
|
|
51
|
+
invalid_request: 'invalid_request'
|
|
52
|
+
}.freeze
|
|
53
|
+
|
|
54
|
+
included do
|
|
55
|
+
# Override base controller error handlers
|
|
56
|
+
rescue_from ActiveRecord::RecordNotFound, with: :handle_record_not_found
|
|
57
|
+
rescue_from CanCan::AccessDenied, with: :handle_access_denied
|
|
58
|
+
rescue_from Spree::Core::GatewayError, with: :handle_gateway_error
|
|
59
|
+
rescue_from ActionController::ParameterMissing, with: :handle_parameter_missing
|
|
60
|
+
rescue_from ActiveRecord::RecordInvalid, with: :handle_record_invalid
|
|
61
|
+
rescue_from ArgumentError, with: :handle_argument_error
|
|
62
|
+
rescue_from ActionDispatch::Http::Parameters::ParseError, with: :handle_parse_error
|
|
63
|
+
rescue_from StateMachines::InvalidTransition, with: :handle_invalid_transition
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
protected
|
|
67
|
+
|
|
68
|
+
# Main error rendering method with Stripe-style structure
|
|
69
|
+
def render_error(code:, message:, status:, details: nil)
|
|
70
|
+
error_response = {
|
|
71
|
+
error: {
|
|
72
|
+
code: code,
|
|
73
|
+
message: message
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
error_response[:error][:details] = details if details.present?
|
|
78
|
+
|
|
79
|
+
render json: error_response, status: status
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Convenience method for validation errors with ActiveModel::Errors
|
|
83
|
+
def render_validation_error(errors, code: ERROR_CODES[:validation_error])
|
|
84
|
+
details = errors.is_a?(ActiveModel::Errors) ? format_validation_details(errors) : nil
|
|
85
|
+
message = errors.is_a?(ActiveModel::Errors) ? errors.full_messages.to_sentence : errors.to_s
|
|
86
|
+
|
|
87
|
+
render_error(
|
|
88
|
+
code: code,
|
|
89
|
+
message: message,
|
|
90
|
+
status: :unprocessable_content,
|
|
91
|
+
details: details
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Convenience method for service result errors
|
|
96
|
+
def render_service_error(error, code: ERROR_CODES[:processing_error], status: :unprocessable_content)
|
|
97
|
+
if error.is_a?(ActiveModel::Errors)
|
|
98
|
+
render_validation_error(error, code: code)
|
|
99
|
+
elsif error.is_a?(String)
|
|
100
|
+
render_error(code: code, message: error, status: status)
|
|
101
|
+
else
|
|
102
|
+
render_error(code: code, message: error.to_s, status: status)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Legacy support - redirect to new error handling
|
|
107
|
+
def render_errors(errors, status = :unprocessable_content)
|
|
108
|
+
code = infer_error_code(errors, status)
|
|
109
|
+
|
|
110
|
+
if errors.is_a?(ActiveModel::Errors)
|
|
111
|
+
render_validation_error(errors, code: code)
|
|
112
|
+
else
|
|
113
|
+
message = errors.is_a?(String) ? errors : errors.to_s
|
|
114
|
+
render_error(code: code, message: message, status: status)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Exception handlers
|
|
119
|
+
def handle_record_not_found(exception)
|
|
120
|
+
code = determine_not_found_code(exception)
|
|
121
|
+
message = generate_not_found_message(exception)
|
|
122
|
+
|
|
123
|
+
render_error(
|
|
124
|
+
code: code,
|
|
125
|
+
message: message,
|
|
126
|
+
status: :not_found
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def handle_access_denied(exception)
|
|
131
|
+
render_error(
|
|
132
|
+
code: ERROR_CODES[:access_denied],
|
|
133
|
+
message: exception.message,
|
|
134
|
+
status: :forbidden
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def handle_gateway_error(exception)
|
|
139
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
140
|
+
render_error(
|
|
141
|
+
code: ERROR_CODES[:gateway_error],
|
|
142
|
+
message: exception.message,
|
|
143
|
+
status: :unprocessable_content
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def handle_parameter_missing(exception)
|
|
148
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
149
|
+
render_error(
|
|
150
|
+
code: ERROR_CODES[:parameter_missing],
|
|
151
|
+
message: exception.message,
|
|
152
|
+
status: :bad_request
|
|
153
|
+
)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def handle_record_invalid(exception)
|
|
157
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
158
|
+
render_validation_error(exception.record.errors)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def handle_argument_error(exception)
|
|
162
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
163
|
+
render_error(
|
|
164
|
+
code: ERROR_CODES[:invalid_request],
|
|
165
|
+
message: exception.message,
|
|
166
|
+
status: :bad_request
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def handle_parse_error(exception)
|
|
171
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
172
|
+
message = exception.respond_to?(:original_message) ? exception.original_message : exception.message
|
|
173
|
+
render_error(
|
|
174
|
+
code: ERROR_CODES[:invalid_request],
|
|
175
|
+
message: message,
|
|
176
|
+
status: :bad_request
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def handle_invalid_transition(exception)
|
|
181
|
+
Rails.error.report(exception, context: error_context, source: 'spree.api.v3')
|
|
182
|
+
render_error(
|
|
183
|
+
code: ERROR_CODES[:order_cannot_transition],
|
|
184
|
+
message: exception.message,
|
|
185
|
+
status: :unprocessable_content
|
|
186
|
+
)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
|
|
191
|
+
# Format validation errors for details field
|
|
192
|
+
def format_validation_details(errors)
|
|
193
|
+
errors.messages.transform_values do |messages|
|
|
194
|
+
messages.map { |msg| msg }
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Infer error code from context
|
|
199
|
+
def infer_error_code(errors, status)
|
|
200
|
+
case status
|
|
201
|
+
when :not_found
|
|
202
|
+
ERROR_CODES[:record_not_found]
|
|
203
|
+
when :forbidden
|
|
204
|
+
ERROR_CODES[:access_denied]
|
|
205
|
+
when :bad_request
|
|
206
|
+
ERROR_CODES[:invalid_request]
|
|
207
|
+
when :unprocessable_content
|
|
208
|
+
errors.is_a?(ActiveModel::Errors) ? ERROR_CODES[:validation_error] : ERROR_CODES[:processing_error]
|
|
209
|
+
else
|
|
210
|
+
ERROR_CODES[:processing_error]
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Determine specific not found code based on model
|
|
215
|
+
def determine_not_found_code(exception)
|
|
216
|
+
model_name = extract_model_name(exception)
|
|
217
|
+
|
|
218
|
+
case model_name
|
|
219
|
+
when 'order'
|
|
220
|
+
ERROR_CODES[:order_not_found]
|
|
221
|
+
when 'line_item'
|
|
222
|
+
ERROR_CODES[:line_item_not_found]
|
|
223
|
+
when 'variant'
|
|
224
|
+
ERROR_CODES[:variant_not_found]
|
|
225
|
+
else
|
|
226
|
+
ERROR_CODES[:record_not_found]
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Generate human-readable not found message
|
|
231
|
+
def generate_not_found_message(exception)
|
|
232
|
+
model_name = extract_model_name(exception)
|
|
233
|
+
Spree.t(:record_not_found, scope: 'api', model: model_name&.humanize || 'record')
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Extract clean model name from exception
|
|
237
|
+
def extract_model_name(exception)
|
|
238
|
+
return nil unless exception.model
|
|
239
|
+
|
|
240
|
+
# Remove Spree:: namespace and convert to underscore
|
|
241
|
+
exception.model.to_s.demodulize.underscore
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Error reporting context
|
|
245
|
+
def error_context
|
|
246
|
+
{
|
|
247
|
+
user_id: current_user&.id,
|
|
248
|
+
store_id: current_store&.id,
|
|
249
|
+
request_id: request.request_id
|
|
250
|
+
}
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# Provides HTTP caching support for API v3 controllers
|
|
5
|
+
#
|
|
6
|
+
# Strategy:
|
|
7
|
+
# - Guest users: Public HTTP caching with CDN support (5-15 min TTL)
|
|
8
|
+
# - Authenticated users: Private, no-store (no caching)
|
|
9
|
+
#
|
|
10
|
+
# Uses ETag and Last-Modified headers for cache validation.
|
|
11
|
+
module HttpCaching
|
|
12
|
+
extend ActiveSupport::Concern
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
before_action :set_vary_headers
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
# Check if the current user is a guest (no authentication)
|
|
21
|
+
def guest_user?
|
|
22
|
+
current_user.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Set Vary headers to ensure proper CDN caching by currency/locale
|
|
26
|
+
def set_vary_headers
|
|
27
|
+
if guest_user?
|
|
28
|
+
response.headers['Vary'] = 'Accept, x-spree-currency, x-spree-locale'
|
|
29
|
+
else
|
|
30
|
+
response.headers['Cache-Control'] = 'private, no-store'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Apply HTTP caching for a collection (index actions)
|
|
35
|
+
# Only caches for guest users
|
|
36
|
+
#
|
|
37
|
+
# @param collection [ActiveRecord::Relation] The collection to cache
|
|
38
|
+
# @param expires_in [ActiveSupport::Duration] Cache TTL (default: 5 minutes)
|
|
39
|
+
# @param stale_while_revalidate [ActiveSupport::Duration] Allow stale responses while revalidating
|
|
40
|
+
# @return [Boolean] true if response should be rendered, false if 304 Not Modified
|
|
41
|
+
def cache_collection(collection, expires_in: 5.minutes, stale_while_revalidate: 30.seconds)
|
|
42
|
+
return true unless guest_user?
|
|
43
|
+
|
|
44
|
+
expires_in expires_in, public: true, stale_while_revalidate: stale_while_revalidate
|
|
45
|
+
|
|
46
|
+
# Use collection's cache key for ETag
|
|
47
|
+
cache_key = collection_cache_key(collection)
|
|
48
|
+
response.headers['ETag'] = %("#{Digest::MD5.hexdigest(cache_key)}")
|
|
49
|
+
|
|
50
|
+
# Return false if client has fresh cache (304 Not Modified)
|
|
51
|
+
!request.fresh?(response)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Apply HTTP caching for a single resource (show actions)
|
|
55
|
+
# Only caches for guest users
|
|
56
|
+
#
|
|
57
|
+
# @param resource [ActiveRecord::Base] The resource to cache
|
|
58
|
+
# @param expires_in [ActiveSupport::Duration] Cache TTL (default: 5 minutes)
|
|
59
|
+
# @return [Boolean] true if response should be rendered, false if 304 Not Modified
|
|
60
|
+
def cache_resource(resource, expires_in: 5.minutes)
|
|
61
|
+
return true unless guest_user?
|
|
62
|
+
|
|
63
|
+
expires_in expires_in, public: true
|
|
64
|
+
|
|
65
|
+
# Use Rails' stale? which handles ETag and Last-Modified
|
|
66
|
+
stale?(resource, public: true)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# Build a cache key for a collection
|
|
72
|
+
# Includes: query params, pagination, includes, currency, locale
|
|
73
|
+
# Strips order to avoid PostgreSQL errors with DISTINCT + subquery ORDER BY expressions
|
|
74
|
+
def collection_cache_key(collection)
|
|
75
|
+
parts = [
|
|
76
|
+
collection.reorder(nil).cache_key_with_version,
|
|
77
|
+
params[:include],
|
|
78
|
+
params[:q],
|
|
79
|
+
params[:page],
|
|
80
|
+
params[:per_page],
|
|
81
|
+
current_currency,
|
|
82
|
+
current_locale
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
parts.compact.join('/')
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|