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.
Files changed (332) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -33
  3. data/Rakefile +25 -0
  4. data/app/controllers/concerns/spree/api/v3/api_key_authentication.rb +51 -0
  5. data/app/controllers/concerns/spree/api/v3/error_handler.rb +255 -0
  6. data/app/controllers/concerns/spree/api/v3/http_caching.rb +90 -0
  7. data/app/controllers/concerns/spree/api/v3/jwt_authentication.rb +95 -0
  8. data/app/controllers/concerns/spree/api/v3/locale_and_currency.rb +73 -0
  9. data/app/controllers/concerns/spree/api/v3/order_concern.rb +51 -0
  10. data/app/controllers/concerns/spree/api/v3/resource_serializer.rb +41 -0
  11. data/app/controllers/spree/api/v3/base_controller.rb +42 -0
  12. data/app/controllers/spree/api/v3/resource_controller.rb +210 -0
  13. data/app/controllers/spree/api/v3/store/auth_controller.rb +140 -0
  14. data/app/controllers/spree/api/v3/store/base_controller.rb +12 -0
  15. data/app/controllers/spree/api/v3/store/cart_controller.rb +82 -0
  16. data/app/controllers/spree/api/v3/store/countries_controller.rb +31 -0
  17. data/app/controllers/spree/api/v3/store/currencies_controller.rb +18 -0
  18. data/app/controllers/spree/api/v3/store/customer/account_controller.rb +38 -0
  19. data/app/controllers/spree/api/v3/store/customer/addresses_controller.rb +85 -0
  20. data/app/controllers/spree/api/v3/store/customer/credit_cards_controller.rb +31 -0
  21. data/app/controllers/spree/api/v3/store/customer/gift_cards_controller.rb +36 -0
  22. data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +35 -0
  23. data/app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb +83 -0
  24. data/app/controllers/spree/api/v3/store/digitals_controller.rb +37 -0
  25. data/app/controllers/spree/api/v3/store/locales_controller.rb +24 -0
  26. data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +68 -0
  27. data/app/controllers/spree/api/v3/store/orders/line_items_controller.rb +87 -0
  28. data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +43 -0
  29. data/app/controllers/spree/api/v3/store/orders/payment_sessions_controller.rb +96 -0
  30. data/app/controllers/spree/api/v3/store/orders/payments_controller.rb +45 -0
  31. data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +53 -0
  32. data/app/controllers/spree/api/v3/store/orders/store_credits_controller.rb +42 -0
  33. data/app/controllers/spree/api/v3/store/orders_controller.rb +125 -0
  34. data/app/controllers/spree/api/v3/store/products/filters_controller.rb +38 -0
  35. data/app/controllers/spree/api/v3/store/products_controller.rb +74 -0
  36. data/app/controllers/spree/api/v3/store/resource_controller.rb +12 -0
  37. data/app/controllers/spree/api/v3/store/stores_controller.rb +26 -0
  38. data/app/controllers/spree/api/v3/store/taxonomies_controller.rb +19 -0
  39. data/app/controllers/spree/api/v3/store/taxons/products_controller.rb +37 -0
  40. data/app/controllers/spree/api/v3/store/taxons_controller.rb +34 -0
  41. data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +33 -0
  42. data/app/controllers/spree/api/v3/store/wishlists_controller.rb +41 -0
  43. data/app/serializers/spree/api/v3/address_serializer.rb +22 -0
  44. data/app/serializers/spree/api/v3/admin/customer_serializer.rb +43 -0
  45. data/app/serializers/spree/api/v3/admin/metafield_serializer.rb +15 -0
  46. data/app/serializers/spree/api/v3/admin/order_serializer.rb +39 -0
  47. data/app/serializers/spree/api/v3/admin/price_serializer.rb +21 -0
  48. data/app/serializers/spree/api/v3/admin/product_serializer.rb +47 -0
  49. data/app/serializers/spree/api/v3/admin/taxon_serializer.rb +20 -0
  50. data/app/serializers/spree/api/v3/admin/taxonomy_serializer.rb +15 -0
  51. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +44 -0
  52. data/app/serializers/spree/api/v3/asset_serializer.rb +20 -0
  53. data/app/serializers/spree/api/v3/base_serializer.rb +98 -0
  54. data/app/serializers/spree/api/v3/country_serializer.rb +35 -0
  55. data/app/serializers/spree/api/v3/credit_card_serializer.rb +12 -0
  56. data/app/serializers/spree/api/v3/currency_serializer.rb +14 -0
  57. data/app/serializers/spree/api/v3/customer_return_serializer.rb +17 -0
  58. data/app/serializers/spree/api/v3/customer_serializer.rb +19 -0
  59. data/app/serializers/spree/api/v3/digital_link_serializer.rb +30 -0
  60. data/app/serializers/spree/api/v3/digital_serializer.rb +17 -0
  61. data/app/serializers/spree/api/v3/export_serializer.rb +19 -0
  62. data/app/serializers/spree/api/v3/gift_card_batch_serializer.rb +28 -0
  63. data/app/serializers/spree/api/v3/gift_card_serializer.rb +78 -0
  64. data/app/serializers/spree/api/v3/image_serializer.rb +43 -0
  65. data/app/serializers/spree/api/v3/import_row_serializer.rb +24 -0
  66. data/app/serializers/spree/api/v3/import_serializer.rb +32 -0
  67. data/app/serializers/spree/api/v3/invitation_serializer.rb +47 -0
  68. data/app/serializers/spree/api/v3/line_item_serializer.rb +48 -0
  69. data/app/serializers/spree/api/v3/locale_serializer.rb +14 -0
  70. data/app/serializers/spree/{v2/storefront → api/v3}/metafield_serializer.rb +5 -3
  71. data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +27 -0
  72. data/app/serializers/spree/api/v3/option_type_serializer.rb +11 -0
  73. data/app/serializers/spree/api/v3/option_value_serializer.rb +24 -0
  74. data/app/serializers/spree/api/v3/order_promotion_serializer.rb +16 -0
  75. data/app/serializers/spree/api/v3/order_serializer.rb +39 -0
  76. data/app/serializers/spree/api/v3/payment_method_serializer.rb +15 -0
  77. data/app/serializers/spree/api/v3/payment_serializer.rb +54 -0
  78. data/app/serializers/spree/api/v3/payment_session_serializer.rb +32 -0
  79. data/app/serializers/spree/api/v3/payment_setup_session_serializer.rb +33 -0
  80. data/app/serializers/spree/api/v3/payment_source_serializer.rb +18 -0
  81. data/app/serializers/spree/api/v3/post_category_serializer.rb +13 -0
  82. data/app/serializers/spree/api/v3/post_serializer.rb +25 -0
  83. data/app/serializers/spree/api/v3/price_serializer.rb +34 -0
  84. data/app/serializers/spree/api/v3/product_serializer.rb +108 -0
  85. data/app/serializers/spree/api/v3/promotion_serializer.rb +28 -0
  86. data/app/serializers/spree/api/v3/refund_serializer.rb +31 -0
  87. data/app/serializers/spree/api/v3/reimbursement_serializer.rb +28 -0
  88. data/app/serializers/spree/api/v3/report_serializer.rb +29 -0
  89. data/app/serializers/spree/api/v3/return_authorization_serializer.rb +31 -0
  90. data/app/serializers/spree/api/v3/return_item_serializer.rb +53 -0
  91. data/app/serializers/spree/api/v3/shipment_serializer.rb +19 -0
  92. data/app/serializers/spree/api/v3/shipping_method_serializer.rb +11 -0
  93. data/app/serializers/spree/api/v3/shipping_rate_serializer.rb +26 -0
  94. data/app/serializers/spree/api/v3/state_serializer.rb +14 -0
  95. data/app/serializers/spree/api/v3/stock_item_serializer.rb +23 -0
  96. data/app/serializers/spree/api/v3/stock_location_serializer.rb +18 -0
  97. data/app/serializers/spree/api/v3/stock_movement_serializer.rb +24 -0
  98. data/app/serializers/spree/api/v3/stock_transfer_serializer.rb +25 -0
  99. data/app/serializers/spree/api/v3/store_credit_serializer.rb +37 -0
  100. data/app/serializers/spree/api/v3/store_serializer.rb +38 -0
  101. data/app/serializers/spree/api/v3/taxon_serializer.rb +78 -0
  102. data/app/serializers/spree/api/v3/taxonomy_serializer.rb +33 -0
  103. data/app/serializers/spree/api/v3/variant_serializer.rb +86 -0
  104. data/app/serializers/spree/api/v3/wished_item_serializer.rb +22 -0
  105. data/app/serializers/spree/api/v3/wishlist_serializer.rb +25 -0
  106. data/app/services/spree/api/v3/filters_aggregator.rb +156 -0
  107. data/app/services/spree/api/v3/orders/update.rb +103 -0
  108. data/config/initializers/alba.rb +5 -0
  109. data/config/initializers/pagy.rb +10 -0
  110. data/config/initializers/typelizer.rb +25 -0
  111. data/config/locales/en.yml +1 -0
  112. data/config/routes.rb +63 -196
  113. data/lib/spree/api/dependencies.rb +68 -0
  114. data/lib/spree/api/engine.rb +0 -5
  115. data/lib/spree/api/openapi/schema_helper.rb +177 -0
  116. data/lib/spree/api/testing_support/factories.rb +1 -3
  117. data/lib/spree/api/testing_support/v3/base.rb +118 -0
  118. data/lib/spree/api.rb +7 -4
  119. metadata +131 -264
  120. data/LICENSE.md +0 -57
  121. data/app/controllers/concerns/spree/api/v2/caching.rb +0 -40
  122. data/app/controllers/concerns/spree/api/v2/coupon_codes_helper.rb +0 -29
  123. data/app/controllers/concerns/spree/api/v2/number_resource.rb +0 -11
  124. data/app/controllers/concerns/spree/api/v2/platform/nested_set_reposition_concern.rb +0 -37
  125. data/app/controllers/concerns/spree/api/v2/platform/promotion_calculator_params.rb +0 -17
  126. data/app/controllers/concerns/spree/api/v2/platform/promotion_rule_params.rb +0 -16
  127. data/app/controllers/concerns/spree/api/v2/product_list_includes.rb +0 -21
  128. data/app/controllers/concerns/spree/api/v2/storefront/metadata_controller_concern.rb +0 -18
  129. data/app/controllers/concerns/spree/api/v2/storefront/order_concern.rb +0 -49
  130. data/app/controllers/spree/api/v2/base_controller.rb +0 -233
  131. data/app/controllers/spree/api/v2/data_feeds/google_controller.rb +0 -24
  132. data/app/controllers/spree/api/v2/platform/addresses_controller.rb +0 -23
  133. data/app/controllers/spree/api/v2/platform/adjustments_controller.rb +0 -23
  134. data/app/controllers/spree/api/v2/platform/classifications_controller.rb +0 -26
  135. data/app/controllers/spree/api/v2/platform/countries_controller.rb +0 -23
  136. data/app/controllers/spree/api/v2/platform/data_feeds_controller.rb +0 -19
  137. data/app/controllers/spree/api/v2/platform/digital_links_controller.rb +0 -29
  138. data/app/controllers/spree/api/v2/platform/digitals_controller.rb +0 -23
  139. data/app/controllers/spree/api/v2/platform/gift_cards_controller.rb +0 -23
  140. data/app/controllers/spree/api/v2/platform/line_items_controller.rb +0 -63
  141. data/app/controllers/spree/api/v2/platform/option_types_controller.rb +0 -19
  142. data/app/controllers/spree/api/v2/platform/option_values_controller.rb +0 -23
  143. data/app/controllers/spree/api/v2/platform/orders_controller.rb +0 -167
  144. data/app/controllers/spree/api/v2/platform/payment_methods_controller.rb +0 -31
  145. data/app/controllers/spree/api/v2/platform/payments_controller.rb +0 -21
  146. data/app/controllers/spree/api/v2/platform/products_controller.rb +0 -41
  147. data/app/controllers/spree/api/v2/platform/promotion_actions_controller.rb +0 -34
  148. data/app/controllers/spree/api/v2/platform/promotion_categories_controller.rb +0 -23
  149. data/app/controllers/spree/api/v2/platform/promotion_rules_controller.rb +0 -29
  150. data/app/controllers/spree/api/v2/platform/promotions_controller.rb +0 -35
  151. data/app/controllers/spree/api/v2/platform/resource_controller.rb +0 -154
  152. data/app/controllers/spree/api/v2/platform/roles_controller.rb +0 -19
  153. data/app/controllers/spree/api/v2/platform/shipments_controller.rb +0 -147
  154. data/app/controllers/spree/api/v2/platform/shipping_categories_controller.rb +0 -19
  155. data/app/controllers/spree/api/v2/platform/shipping_methods_controller.rb +0 -28
  156. data/app/controllers/spree/api/v2/platform/states_controller.rb +0 -23
  157. data/app/controllers/spree/api/v2/platform/stock_items_controller.rb +0 -23
  158. data/app/controllers/spree/api/v2/platform/stock_locations_controller.rb +0 -23
  159. data/app/controllers/spree/api/v2/platform/store_credit_categories_controller.rb +0 -19
  160. data/app/controllers/spree/api/v2/platform/store_credit_types_controller.rb +0 -19
  161. data/app/controllers/spree/api/v2/platform/store_credits_controller.rb +0 -23
  162. data/app/controllers/spree/api/v2/platform/tax_categories_controller.rb +0 -23
  163. data/app/controllers/spree/api/v2/platform/tax_rates_controller.rb +0 -27
  164. data/app/controllers/spree/api/v2/platform/taxonomies_controller.rb +0 -23
  165. data/app/controllers/spree/api/v2/platform/taxons_controller.rb +0 -59
  166. data/app/controllers/spree/api/v2/platform/users_controller.rb +0 -37
  167. data/app/controllers/spree/api/v2/platform/variants_controller.rb +0 -23
  168. data/app/controllers/spree/api/v2/platform/wished_items_controller.rb +0 -23
  169. data/app/controllers/spree/api/v2/platform/wishlists_controller.rb +0 -23
  170. data/app/controllers/spree/api/v2/platform/zones_controller.rb +0 -23
  171. data/app/controllers/spree/api/v2/resource_controller.rb +0 -79
  172. data/app/controllers/spree/api/v2/storefront/account/addresses_controller.rb +0 -77
  173. data/app/controllers/spree/api/v2/storefront/account/credit_cards_controller.rb +0 -52
  174. data/app/controllers/spree/api/v2/storefront/account/orders_controller.rb +0 -50
  175. data/app/controllers/spree/api/v2/storefront/account_controller.rb +0 -52
  176. data/app/controllers/spree/api/v2/storefront/cart_controller.rb +0 -246
  177. data/app/controllers/spree/api/v2/storefront/checkout_controller.rb +0 -183
  178. data/app/controllers/spree/api/v2/storefront/countries_controller.rb +0 -57
  179. data/app/controllers/spree/api/v2/storefront/digitals_controller.rb +0 -58
  180. data/app/controllers/spree/api/v2/storefront/order_status_controller.rb +0 -34
  181. data/app/controllers/spree/api/v2/storefront/policies_controller.rb +0 -31
  182. data/app/controllers/spree/api/v2/storefront/post_categories_controller.rb +0 -35
  183. data/app/controllers/spree/api/v2/storefront/posts_controller.rb +0 -51
  184. data/app/controllers/spree/api/v2/storefront/products_controller.rb +0 -66
  185. data/app/controllers/spree/api/v2/storefront/stores_controller.rb +0 -27
  186. data/app/controllers/spree/api/v2/storefront/taxons_controller.rb +0 -51
  187. data/app/controllers/spree/api/v2/storefront/variants_controller.rb +0 -41
  188. data/app/controllers/spree/api/v2/storefront/wishlists_controller.rb +0 -214
  189. data/app/helpers/spree/api/v2/collection_options_helpers.rb +0 -46
  190. data/app/helpers/spree/api/v2/display_money_helper.rb +0 -63
  191. data/app/helpers/spree/api/v2/store_media_serializer_images_concern.rb +0 -30
  192. data/app/models/concerns/spree/user_api_authentication.rb +0 -19
  193. data/app/models/concerns/spree/user_api_methods.rb +0 -7
  194. data/app/models/spree/oauth_access_grant.rb +0 -7
  195. data/app/models/spree/oauth_access_token.rb +0 -7
  196. data/app/models/spree/oauth_application.rb +0 -22
  197. data/app/paginators/spree/api/paginate.rb +0 -68
  198. data/app/presenters/spree/api/products/filters_presenter.rb +0 -39
  199. data/app/serializers/concerns/spree/api/v2/image_transformation_concern.rb +0 -15
  200. data/app/serializers/concerns/spree/api/v2/public_metafields_concern.rb +0 -15
  201. data/app/serializers/concerns/spree/api/v2/resource_serializer_concern.rb +0 -42
  202. data/app/serializers/concerns/spree/api/v2/taxon_image_transformation_concern.rb +0 -15
  203. data/app/serializers/spree/api/v2/base_serializer.rb +0 -43
  204. data/app/serializers/spree/api/v2/platform/address_serializer.rb +0 -15
  205. data/app/serializers/spree/api/v2/platform/adjustment_serializer.rb +0 -20
  206. data/app/serializers/spree/api/v2/platform/admin_user_serializer.rb +0 -11
  207. data/app/serializers/spree/api/v2/platform/asset_serializer.rb +0 -13
  208. data/app/serializers/spree/api/v2/platform/base_serializer.rb +0 -10
  209. data/app/serializers/spree/api/v2/platform/calculator_serializer.rb +0 -17
  210. data/app/serializers/spree/api/v2/platform/classification_serializer.rb +0 -14
  211. data/app/serializers/spree/api/v2/platform/country_serializer.rb +0 -13
  212. data/app/serializers/spree/api/v2/platform/credit_card_serializer.rb +0 -14
  213. data/app/serializers/spree/api/v2/platform/customer_return_serializer.rb +0 -17
  214. data/app/serializers/spree/api/v2/platform/data_feed_serializer.rb +0 -13
  215. data/app/serializers/spree/api/v2/platform/digital_link_serializer.rb +0 -16
  216. data/app/serializers/spree/api/v2/platform/digital_serializer.rb +0 -29
  217. data/app/serializers/spree/api/v2/platform/gift_card_serializer.rb +0 -17
  218. data/app/serializers/spree/api/v2/platform/image_serializer.rb +0 -17
  219. data/app/serializers/spree/api/v2/platform/inventory_unit_serializer.rb +0 -19
  220. data/app/serializers/spree/api/v2/platform/line_item_serializer.rb +0 -19
  221. data/app/serializers/spree/api/v2/platform/log_entry_serializer.rb +0 -13
  222. data/app/serializers/spree/api/v2/platform/metafield_serializer.rb +0 -21
  223. data/app/serializers/spree/api/v2/platform/option_type_serializer.rb +0 -13
  224. data/app/serializers/spree/api/v2/platform/option_value_serializer.rb +0 -13
  225. data/app/serializers/spree/api/v2/platform/order_promotion_serializer.rb +0 -14
  226. data/app/serializers/spree/api/v2/platform/order_serializer.rb +0 -31
  227. data/app/serializers/spree/api/v2/platform/payment_capture_event_serializer.rb +0 -13
  228. data/app/serializers/spree/api/v2/platform/payment_method_serializer.rb +0 -18
  229. data/app/serializers/spree/api/v2/platform/payment_serializer.rb +0 -22
  230. data/app/serializers/spree/api/v2/platform/payment_source_serializer.rb +0 -12
  231. data/app/serializers/spree/api/v2/platform/price_serializer.rb +0 -19
  232. data/app/serializers/spree/api/v2/platform/product_property_serializer.rb +0 -11
  233. data/app/serializers/spree/api/v2/platform/product_serializer.rb +0 -90
  234. data/app/serializers/spree/api/v2/platform/promotion_action_line_item_serializer.rb +0 -14
  235. data/app/serializers/spree/api/v2/platform/promotion_action_serializer.rb +0 -19
  236. data/app/serializers/spree/api/v2/platform/promotion_category_serializer.rb +0 -13
  237. data/app/serializers/spree/api/v2/platform/promotion_rule_serializer.rb +0 -21
  238. data/app/serializers/spree/api/v2/platform/promotion_serializer.rb +0 -17
  239. data/app/serializers/spree/api/v2/platform/property_serializer.rb +0 -11
  240. data/app/serializers/spree/api/v2/platform/prototype_serializer.rb +0 -15
  241. data/app/serializers/spree/api/v2/platform/refund_reason_serializer.rb +0 -11
  242. data/app/serializers/spree/api/v2/platform/refund_serializer.rb +0 -17
  243. data/app/serializers/spree/api/v2/platform/reimbursement_credit_serializer.rb +0 -10
  244. data/app/serializers/spree/api/v2/platform/reimbursement_serializer.rb +0 -19
  245. data/app/serializers/spree/api/v2/platform/reimbursement_type_serializer.rb +0 -11
  246. data/app/serializers/spree/api/v2/platform/return_authorization_reason_serializer.rb +0 -11
  247. data/app/serializers/spree/api/v2/platform/return_authorization_serializer.rb +0 -17
  248. data/app/serializers/spree/api/v2/platform/return_item_serializer.rb +0 -16
  249. data/app/serializers/spree/api/v2/platform/role_serializer.rb +0 -11
  250. data/app/serializers/spree/api/v2/platform/shipment_serializer.rb +0 -22
  251. data/app/serializers/spree/api/v2/platform/shipping_category_serializer.rb +0 -11
  252. data/app/serializers/spree/api/v2/platform/shipping_method_serializer.rb +0 -16
  253. data/app/serializers/spree/api/v2/platform/shipping_rate_serializer.rb +0 -15
  254. data/app/serializers/spree/api/v2/platform/state_change_serializer.rb +0 -13
  255. data/app/serializers/spree/api/v2/platform/state_serializer.rb +0 -13
  256. data/app/serializers/spree/api/v2/platform/stock_item_serializer.rb +0 -18
  257. data/app/serializers/spree/api/v2/platform/stock_location_serializer.rb +0 -14
  258. data/app/serializers/spree/api/v2/platform/stock_movement_serializer.rb +0 -11
  259. data/app/serializers/spree/api/v2/platform/stock_transfer_serializer.rb +0 -15
  260. data/app/serializers/spree/api/v2/platform/store_credit_category_serializer.rb +0 -12
  261. data/app/serializers/spree/api/v2/platform/store_credit_event_serializer.rb +0 -14
  262. data/app/serializers/spree/api/v2/platform/store_credit_serializer.rb +0 -18
  263. data/app/serializers/spree/api/v2/platform/store_credit_type_serializer.rb +0 -12
  264. data/app/serializers/spree/api/v2/platform/store_serializer.rb +0 -14
  265. data/app/serializers/spree/api/v2/platform/tax_category_serializer.rb +0 -13
  266. data/app/serializers/spree/api/v2/platform/tax_rate_serializer.rb +0 -14
  267. data/app/serializers/spree/api/v2/platform/taxon_image_serializer.rb +0 -15
  268. data/app/serializers/spree/api/v2/platform/taxon_serializer.rb +0 -47
  269. data/app/serializers/spree/api/v2/platform/taxonomy_serializer.rb +0 -14
  270. data/app/serializers/spree/api/v2/platform/user_serializer.rb +0 -37
  271. data/app/serializers/spree/api/v2/platform/variant_serializer.rb +0 -66
  272. data/app/serializers/spree/api/v2/platform/wished_item_serializer.rb +0 -29
  273. data/app/serializers/spree/api/v2/platform/wishlist_serializer.rb +0 -19
  274. data/app/serializers/spree/api/v2/platform/zone_member_serializer.rb +0 -13
  275. data/app/serializers/spree/api/v2/platform/zone_serializer.rb +0 -13
  276. data/app/serializers/spree/v2/storefront/address_serializer.rb +0 -22
  277. data/app/serializers/spree/v2/storefront/base_serializer.rb +0 -10
  278. data/app/serializers/spree/v2/storefront/cart_serializer.rb +0 -67
  279. data/app/serializers/spree/v2/storefront/country_serializer.rb +0 -24
  280. data/app/serializers/spree/v2/storefront/credit_card_serializer.rb +0 -15
  281. data/app/serializers/spree/v2/storefront/digital_link_serializer.rb +0 -11
  282. data/app/serializers/spree/v2/storefront/estimated_shipping_rate_serializer.rb +0 -35
  283. data/app/serializers/spree/v2/storefront/gift_card_serializer.rb +0 -16
  284. data/app/serializers/spree/v2/storefront/image_serializer.rb +0 -13
  285. data/app/serializers/spree/v2/storefront/line_item_serializer.rb +0 -23
  286. data/app/serializers/spree/v2/storefront/option_type_serializer.rb +0 -15
  287. data/app/serializers/spree/v2/storefront/option_value_serializer.rb +0 -13
  288. data/app/serializers/spree/v2/storefront/order_promotion_serializer.rb +0 -14
  289. data/app/serializers/spree/v2/storefront/order_serializer.rb +0 -11
  290. data/app/serializers/spree/v2/storefront/payment_method_serializer.rb +0 -17
  291. data/app/serializers/spree/v2/storefront/payment_serializer.rb +0 -20
  292. data/app/serializers/spree/v2/storefront/payment_source_serializer.rb +0 -12
  293. data/app/serializers/spree/v2/storefront/policy_serializer.rb +0 -19
  294. data/app/serializers/spree/v2/storefront/post_category_serializer.rb +0 -23
  295. data/app/serializers/spree/v2/storefront/post_serializer.rb +0 -51
  296. data/app/serializers/spree/v2/storefront/product_property_serializer.rb +0 -19
  297. data/app/serializers/spree/v2/storefront/product_serializer.rb +0 -92
  298. data/app/serializers/spree/v2/storefront/shipment_serializer.rb +0 -26
  299. data/app/serializers/spree/v2/storefront/shipping_category_serializer.rb +0 -10
  300. data/app/serializers/spree/v2/storefront/shipping_method_serializer.rb +0 -12
  301. data/app/serializers/spree/v2/storefront/shipping_rate_serializer.rb +0 -26
  302. data/app/serializers/spree/v2/storefront/state_serializer.rb +0 -11
  303. data/app/serializers/spree/v2/storefront/stock_location_serializer.rb +0 -11
  304. data/app/serializers/spree/v2/storefront/store_credit_category_serializer.rb +0 -11
  305. data/app/serializers/spree/v2/storefront/store_credit_event_serializer.rb +0 -15
  306. data/app/serializers/spree/v2/storefront/store_credit_serializer.rb +0 -19
  307. data/app/serializers/spree/v2/storefront/store_credit_type_serializer.rb +0 -11
  308. data/app/serializers/spree/v2/storefront/store_serializer.rb +0 -18
  309. data/app/serializers/spree/v2/storefront/taxon_image_serializer.rb +0 -13
  310. data/app/serializers/spree/v2/storefront/taxon_serializer.rb +0 -55
  311. data/app/serializers/spree/v2/storefront/taxonomy_serializer.rb +0 -13
  312. data/app/serializers/spree/v2/storefront/user_serializer.rb +0 -33
  313. data/app/serializers/spree/v2/storefront/variant_serializer.rb +0 -58
  314. data/app/serializers/spree/v2/storefront/wished_item_serializer.rb +0 -29
  315. data/app/serializers/spree/v2/storefront/wishlist_serializer.rb +0 -17
  316. data/config/initializers/doorkeeper.rb +0 -50
  317. data/config/initializers/json_api_mime_types.rb +0 -8
  318. data/config/initializers/user_class_extensions.rb +0 -7
  319. data/db/migrate/20100107141738_add_api_key_to_spree_users.rb +0 -7
  320. data/db/migrate/20120411123334_resize_api_key_field.rb +0 -7
  321. data/db/migrate/20120530054546_rename_api_key_to_spree_api_key.rb +0 -7
  322. data/db/migrate/20131017162334_add_index_to_user_spree_api_key.rb +0 -7
  323. data/db/migrate/20180320110726_create_doorkeeper_tables.rb +0 -69
  324. data/db/migrate/20210727102516_change_integer_id_columns_type.rb +0 -9
  325. data/db/migrate/20210919183228_enable_polymorphic_resource_owner.rb +0 -21
  326. data/lib/generators/spree/api/install/install_generator.rb +0 -24
  327. data/lib/spree/api/testing_support/factories/oauth_application_factory.rb +0 -6
  328. data/lib/spree/api/testing_support/serializers.rb +0 -15
  329. data/lib/spree/api/testing_support/v2/base.rb +0 -13
  330. data/lib/spree/api/testing_support/v2/current_order.rb +0 -116
  331. data/lib/spree/api/testing_support/v2/platform_contexts.rb +0 -272
  332. 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: 8103cf9477d203a505f580a267a96ad940babc92b4dd09814d86dba03e330300
4
- data.tar.gz: 98f44fdc93e9c4cad74c52ccb58b2b82d62064c53dc9f7fa9d963ca78ed37b41
3
+ metadata.gz: 9fa3dee62eb2625c3d4c9d7bd34bad4ca81cf4d2674f769392a24df5e8a01953
4
+ data.tar.gz: cce1ee0d81f70c7c06350faed5aee5ccc8e2c1e510f1e598f29e48598c7d0d0e
5
5
  SHA512:
6
- metadata.gz: 8b63700e0591ed1aa8f55837aec0f9492016f7cd35ccf3b202e8dcb764a35d82188cb7fc2cac64ff99c1f0a07b05142b59c48be48b01629810dfe4a2bd0cecaa
7
- data.tar.gz: 5d8809fcfe387e374449bb285df5c10df363a2e972e8b3c0fba5c2d7644841e437e70b166bd981765801390c706361bdcb2423c2922a0c7e588735a5d9adf2f9
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
- - **Storefront API** - Customer-facing endpoints for cart, checkout, products, and accounts
12
- - **Platform API** - Administrative endpoints for managing orders, products, and store settings
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
- - **OAuth2 Authentication** - Token-based authentication via Doorkeeper
15
- - **JSONAPI Serializers** - Standardized API responses
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
- ### Storefront API (v2)
23
+ ### Store API
24
24
 
25
- The Storefront API is designed for building custom frontends:
25
+ The Store API is designed for building custom storefronts:
26
26
 
27
27
  ```
28
- GET /api/v2/storefront/products
29
- GET /api/v2/storefront/products/:id
30
- GET /api/v2/storefront/taxons
31
- POST /api/v2/storefront/cart
32
- PATCH /api/v2/storefront/cart/add_item
33
- PATCH /api/v2/storefront/checkout
34
- POST /api/v2/storefront/account
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
- ### Platform API
38
+ ### Admin API
38
39
 
39
- The Platform API provides administrative access:
40
+ The Admin API provides full administrative access:
40
41
 
41
42
  ```
42
- GET /api/v2/platform/orders
43
- POST /api/v2/platform/products
44
- PATCH /api/v2/platform/variants/:id
45
- DELETE /api/v2/platform/line_items/:id
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
- ### OAuth2 Token Authentication
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
- # Request access token
54
- curl -X POST https://your-store.com/spree_oauth/token \
55
- -d "grant_type=password&username=user@example.com&password=secret"
74
+ # Store API
75
+ curl -H "Authorization: Bearer spree_pk_xxx" \
76
+ https://your-store.com/api/v3/products
56
77
 
57
- # Use token in requests
58
- curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
59
- https://your-store.com/api/v2/storefront/account
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/v2/storefront/cart
89
+ https://your-store.com/api/v3/cart
69
90
  ```
70
91
 
71
92
  ## Serializers
72
93
 
73
- API responses use JSONAPI format. Customize serializers by creating your own:
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::V2::Storefront::ProductSerializer
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.storefront_product_serializer = 'MyApp::ProductSerializer'
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
- - [Storefront API Reference](https://docs.spreecommerce.org/api/storefront)
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