flex_commerce_api 0.6.57
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 +7 -0
- data/.env.example +6 -0
- data/.gitignore +14 -0
- data/.rspec +4 -0
- data/.rubocop.yml +1065 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +56 -0
- data/Rakefile +1 -0
- data/app/models/address.rb +41 -0
- data/app/models/asset_file.rb +26 -0
- data/app/models/asset_folder.rb +14 -0
- data/app/models/bundle.rb +20 -0
- data/app/models/bundle_group.rb +15 -0
- data/app/models/cart.rb +136 -0
- data/app/models/category.rb +70 -0
- data/app/models/category_tree.rb +11 -0
- data/app/models/component.rb +8 -0
- data/app/models/container_coupon.rb +12 -0
- data/app/models/country.rb +11 -0
- data/app/models/coupon.rb +18 -0
- data/app/models/customer_account.rb +96 -0
- data/app/models/customer_account_authentication.rb +5 -0
- data/app/models/customer_segment.rb +6 -0
- data/app/models/customer_segment_member.rb +6 -0
- data/app/models/data_attribute.rb +6 -0
- data/app/models/data_store_record.rb +9 -0
- data/app/models/data_store_type.rb +9 -0
- data/app/models/discount_summary.rb +12 -0
- data/app/models/email.rb +5 -0
- data/app/models/ewis_opt_in.rb +8 -0
- data/app/models/external_url.rb +6 -0
- data/app/models/free_shipping_promotion.rb +12 -0
- data/app/models/import.rb +6 -0
- data/app/models/import_entry.rb +6 -0
- data/app/models/line_item.rb +34 -0
- data/app/models/line_item_discount.rb +7 -0
- data/app/models/markdown_price.rb +11 -0
- data/app/models/menu.rb +36 -0
- data/app/models/menu_item.rb +7 -0
- data/app/models/menu_item_item.rb +5 -0
- data/app/models/note.rb +18 -0
- data/app/models/order.rb +38 -0
- data/app/models/password_recovery.rb +20 -0
- data/app/models/payment_address_verification.rb +13 -0
- data/app/models/payment_process.rb +13 -0
- data/app/models/payment_provider.rb +15 -0
- data/app/models/payment_transaction.rb +13 -0
- data/app/models/product.rb +99 -0
- data/app/models/product_asset_file.rb +12 -0
- data/app/models/promotion.rb +19 -0
- data/app/models/promotion_qualifying_product_exclusion.rb +8 -0
- data/app/models/redirect.rb +14 -0
- data/app/models/refund.rb +14 -0
- data/app/models/remote_address.rb +22 -0
- data/app/models/remote_line_item.rb +11 -0
- data/app/models/remote_order.rb +15 -0
- data/app/models/remote_shipping_method.rb +12 -0
- data/app/models/report.rb +18 -0
- data/app/models/report_invocation.rb +18 -0
- data/app/models/retail_store.rb +18 -0
- data/app/models/role.rb +6 -0
- data/app/models/search_suggestion.rb +17 -0
- data/app/models/section.rb +9 -0
- data/app/models/session.rb +8 -0
- data/app/models/shipping_method.rb +26 -0
- data/app/models/slug.rb +19 -0
- data/app/models/static_page.rb +60 -0
- data/app/models/static_page_folder.rb +8 -0
- data/app/models/stock_level.rb +21 -0
- data/app/models/tax_code.rb +6 -0
- data/app/models/taxonomy.rb +5 -0
- data/app/models/template.rb +9 -0
- data/app/models/template_component.rb +11 -0
- data/app/models/template_definition.rb +12 -0
- data/app/models/template_section.rb +12 -0
- data/app/models/user.rb +8 -0
- data/app/models/user_profile.rb +6 -0
- data/app/models/v2/create_order.rb +10 -0
- data/app/models/v2/deallocate_order.rb +10 -0
- data/app/models/v2/line_item.rb +9 -0
- data/app/models/v2/order.rb +9 -0
- data/app/models/v2/unallocate_order.rb +10 -0
- data/app/models/variant.rb +18 -0
- data/app/models/webhook.rb +17 -0
- data/app/services/param_to_shql.rb +72 -0
- data/app/services/surrogate_keys.rb +44 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/config/locales/payments.en.yml +3 -0
- data/flex-commerce-api.gemspec +41 -0
- data/lib/flex_commerce.rb +95 -0
- data/lib/flex_commerce_api.rb +21 -0
- data/lib/flex_commerce_api/api_base.rb +11 -0
- data/lib/flex_commerce_api/base_resource.rb +250 -0
- data/lib/flex_commerce_api/config.rb +55 -0
- data/lib/flex_commerce_api/error/access_denied.rb +6 -0
- data/lib/flex_commerce_api/error/bad_request.rb +10 -0
- data/lib/flex_commerce_api/error/base.rb +12 -0
- data/lib/flex_commerce_api/error/client_error.rb +7 -0
- data/lib/flex_commerce_api/error/connection_error.rb +6 -0
- data/lib/flex_commerce_api/error/internal_server.rb +37 -0
- data/lib/flex_commerce_api/error/not_found.rb +13 -0
- data/lib/flex_commerce_api/error/record_invalid.rb +16 -0
- data/lib/flex_commerce_api/error/unexpected_status.rb +7 -0
- data/lib/flex_commerce_api/errors.rb +13 -0
- data/lib/flex_commerce_api/json_api_client_extension/builder.rb +28 -0
- data/lib/flex_commerce_api/json_api_client_extension/capture_surrogate_keys_middleware.rb +16 -0
- data/lib/flex_commerce_api/json_api_client_extension/flexible_connection.rb +59 -0
- data/lib/flex_commerce_api/json_api_client_extension/has_many_association_proxy.rb +60 -0
- data/lib/flex_commerce_api/json_api_client_extension/included_data.rb +27 -0
- data/lib/flex_commerce_api/json_api_client_extension/json_format_middleware.rb +20 -0
- data/lib/flex_commerce_api/json_api_client_extension/logging_middleware.rb +24 -0
- data/lib/flex_commerce_api/json_api_client_extension/paginator.rb +26 -0
- data/lib/flex_commerce_api/json_api_client_extension/parse_json.rb +23 -0
- data/lib/flex_commerce_api/json_api_client_extension/parsers/parser.rb +16 -0
- data/lib/flex_commerce_api/json_api_client_extension/previewed_request_middleware.rb +17 -0
- data/lib/flex_commerce_api/json_api_client_extension/remote_builder.rb +29 -0
- data/lib/flex_commerce_api/json_api_client_extension/requestor.rb +42 -0
- data/lib/flex_commerce_api/json_api_client_extension/save_request_body_middleware.rb +20 -0
- data/lib/flex_commerce_api/json_api_client_extension/status_middleware.rb +40 -0
- data/lib/flex_commerce_api/v2/api_base.rb +13 -0
- data/lib/flex_commerce_api/version.rb +3 -0
- data/lib/json_erb.rb +9 -0
- data/lib/json_struct.rb +73 -0
- data/lib/patches.rb +4 -0
- data/lib/patches/json_api_client/resource.rb +50 -0
- data/lib/paypal_express.rb +3 -0
- data/lib/paypal_express/additional_info.rb +45 -0
- data/lib/paypal_express/api.rb +86 -0
- data/lib/paypal_express/auth.rb +83 -0
- data/lib/paypal_express/cart_shipping_method.rb +38 -0
- data/lib/paypal_express/exception/access_denied.rb +10 -0
- data/lib/paypal_express/exception/connection_error.rb +10 -0
- data/lib/paypal_express/exception/not_authorized.rb +10 -0
- data/lib/paypal_express/exception/transaction.rb +15 -0
- data/lib/paypal_express/generate_summary.rb +118 -0
- data/lib/paypal_express/process/paypal_params.rb +123 -0
- data/lib/paypal_express/process/response_parser.rb +146 -0
- data/lib/paypal_express/setup.rb +94 -0
- data/lib/paypal_express/shipping_methods_for_cart.rb +46 -0
- data/lib/retry.rb +20 -0
- data/schemas/jsonapi/schema.json +370 -0
- data/schemas/shift/v1/documents/collection/address.json +45 -0
- data/schemas/shift/v1/documents/collection/asset_file.json +43 -0
- data/schemas/shift/v1/documents/collection/asset_folder.json +43 -0
- data/schemas/shift/v1/documents/collection/customer_account.json +50 -0
- data/schemas/shift/v1/documents/collection/markdown_price.json +43 -0
- data/schemas/shift/v1/documents/collection/product.json +43 -0
- data/schemas/shift/v1/documents/collection/variant.json +43 -0
- data/schemas/shift/v1/documents/member/address.json +39 -0
- data/schemas/shift/v1/documents/member/asset_file.json +37 -0
- data/schemas/shift/v1/documents/member/asset_folder.json +39 -0
- data/schemas/shift/v1/documents/member/customer_account.json +44 -0
- data/schemas/shift/v1/documents/member/markdown_price.json +37 -0
- data/schemas/shift/v1/documents/member/product.json +39 -0
- data/schemas/shift/v1/documents/member/variant.json +46 -0
- data/schemas/shift/v1/resources/address.json +130 -0
- data/schemas/shift/v1/resources/asset_file.json +146 -0
- data/schemas/shift/v1/resources/asset_folder.json +188 -0
- data/schemas/shift/v1/resources/customer_account.json +339 -0
- data/schemas/shift/v1/resources/markdown_price.json +52 -0
- data/schemas/shift/v1/resources/product.json +230 -0
- data/schemas/shift/v1/resources/variant.json +298 -0
- data/tasks/json_schema.thor +275 -0
- data/todo.md +8 -0
- metadata +470 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
require_relative 'api'
|
|
2
|
+
|
|
3
|
+
# @module FlexCommerce::PaypalExpress
|
|
4
|
+
module FlexCommerce
|
|
5
|
+
module PaypalExpress
|
|
6
|
+
# @class Setup
|
|
7
|
+
#
|
|
8
|
+
# This is the main class, which talks to ActiveMerchant gem to initiate a transaction using Paypal
|
|
9
|
+
class Setup
|
|
10
|
+
include ::FlexCommerce::PaypalExpress::Api
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# @initialize
|
|
14
|
+
#
|
|
15
|
+
# @param {FlexCommerce::PaymentProviderSetup} payment_provider_setup
|
|
16
|
+
# @param {FlexCommerce::Cart} cart
|
|
17
|
+
# @param {Paypal Gateway} [gateway_class = ::ActiveMerchant::Billing::PaypalExpressGateway]
|
|
18
|
+
# @param {URL} success_url - Generally Paypal confirmation page
|
|
19
|
+
# @param {URL} cancel_url - Generally new transaction page
|
|
20
|
+
# @param {IP} ip_address - User ip address
|
|
21
|
+
# @param {boolean} [allow_shipping_change = true] - true: display shipping options, false: dont display shipping options
|
|
22
|
+
# @param {URL} callback_url - Generally cart show page
|
|
23
|
+
# @param {FlexCommerce::ShippingMethod} shipping_method_model = FlexCommerce::ShippingMethod
|
|
24
|
+
# @param {boolean} [use_mobile_payments = false]
|
|
25
|
+
# @param {String} [description = nil]
|
|
26
|
+
#
|
|
27
|
+
# @note:
|
|
28
|
+
# For `::ActiveMerchant::Billing::PaypalExpressGateway` to work
|
|
29
|
+
# rails-site should include active merchant gem. Ideally this gem should be included in the gemspec.
|
|
30
|
+
# But as we are using custom gem, which is not published to ruby gems, there is no way of including it within this gem dependency
|
|
31
|
+
def initialize(cart:, gateway_class: ::ActiveMerchant::Billing::PaypalExpressGateway, success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description: nil)
|
|
32
|
+
self.gateway_class = gateway_class
|
|
33
|
+
self.cart = cart
|
|
34
|
+
self.allow_shipping_change = allow_shipping_change
|
|
35
|
+
self.success_url = success_url
|
|
36
|
+
self.cancel_url = cancel_url
|
|
37
|
+
self.ip_address = ip_address
|
|
38
|
+
self.callback_url = callback_url
|
|
39
|
+
self.shipping_method_model = shipping_method_model
|
|
40
|
+
self.use_mobile_payments = use_mobile_payments
|
|
41
|
+
self.description = description
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def call
|
|
45
|
+
validate_shipping_method
|
|
46
|
+
|
|
47
|
+
response = gateway.setup_order(convert_amount(cart.total), paypal_params)
|
|
48
|
+
# If paypal setup went fine, redirect to the paypal page
|
|
49
|
+
if response.success?
|
|
50
|
+
PaypalSetup.new(setup_type: "redirect", redirect_url: gateway.redirect_url_for(response.token, mobile: use_mobile_payments))
|
|
51
|
+
else
|
|
52
|
+
# @TODO Find out where to get the message from and add it
|
|
53
|
+
error = "An error occured communicating with paypal #{response.message} \n\n#{response.params.to_json}. Total sent was #{convert_amount(cart.total)} Parameters sent were \n\n#{paypal_params}"
|
|
54
|
+
raise ::FlexCommerce::PaypalExpress::Exception::AccessDenied.new(error)
|
|
55
|
+
end
|
|
56
|
+
rescue ::FlexCommerce::PaypalExpress::Exception::AccessDenied => exception
|
|
57
|
+
PaypalSetup.new(errors: exception)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
attr_accessor :description, :cart, :gateway_class, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments
|
|
63
|
+
|
|
64
|
+
def paypal_params
|
|
65
|
+
Process::PaypalParams.new(
|
|
66
|
+
cart: cart,
|
|
67
|
+
success_url: success_url,
|
|
68
|
+
cancel_url: cancel_url,
|
|
69
|
+
ip_address: ip_address,
|
|
70
|
+
allow_shipping_change: allow_shipping_change,
|
|
71
|
+
callback_url: callback_url,
|
|
72
|
+
shipping_method_model: shipping_method_model,
|
|
73
|
+
use_mobile_payments: use_mobile_payments,
|
|
74
|
+
description: description
|
|
75
|
+
).call
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @method shipping_methods
|
|
79
|
+
#
|
|
80
|
+
# @returns shipping methods with promotions applied
|
|
81
|
+
def shipping_methods
|
|
82
|
+
@shipping_methods ||= ShippingMethodsForCart.new(cart: cart, shipping_methods: shipping_method_model.all).call.sort_by(&:total)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def validate_shipping_method
|
|
86
|
+
unless cart.shipping_method_id.nil? || shipping_methods.any? {|sm| sm.id == cart.shipping_method_id} then
|
|
87
|
+
raise ::FlexCommerce::PaypalExpress::Exception::AccessDenied.new(I18n.t("payment_setup.shipping_method_not_available"))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class PaypalSetup < OpenStruct; end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @module FlexCommerce::PaypalExpress
|
|
2
|
+
module FlexCommerce
|
|
3
|
+
module PaypalExpress
|
|
4
|
+
# @class ShippingMethodsForCart
|
|
5
|
+
#
|
|
6
|
+
# This deals with free shipping promotions and updates the shipping methods accordingly
|
|
7
|
+
class ShippingMethodsForCart
|
|
8
|
+
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
def initialize(cart:, shipping_methods:)
|
|
12
|
+
self.cart = cart
|
|
13
|
+
self.shipping_methods = shipping_methods
|
|
14
|
+
self.shipping_promotions = cart.available_shipping_promotions
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call
|
|
18
|
+
free_shipping_method_ids = [ ]
|
|
19
|
+
shipping_promotions.reverse.each do |promotion|
|
|
20
|
+
# See if promotion is having a shipping method,
|
|
21
|
+
# and also see if that cart total is eligible for promotion
|
|
22
|
+
if promotion.shipping_methods && can_apply_promotion_to_cart?(promotion: promotion)
|
|
23
|
+
free_shipping_method_ids << promotion.shipping_methods.map(&:id)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
free_shipping_method_ids.flatten!
|
|
28
|
+
updated_shipping_methods = []
|
|
29
|
+
shipping_methods.each do |shipping_method|
|
|
30
|
+
shipping_method_free = free_shipping_method_ids.include?(shipping_method.id)
|
|
31
|
+
updated_shipping_methods << CartShippingMethod.new(shipping_method, shipping_method_free)
|
|
32
|
+
end
|
|
33
|
+
updated_shipping_methods
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
attr_accessor :cart, :shipping_methods, :shipping_promotions
|
|
39
|
+
|
|
40
|
+
def can_apply_promotion_to_cart?(promotion:)
|
|
41
|
+
(cart.sub_total - cart.total_discount) >= promotion.minimum_cart_total&.to_i
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/retry.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Retry
|
|
3
|
+
|
|
4
|
+
DEFAULT_MAX_NO_OF_RETRIES = 2
|
|
5
|
+
DEFAULT_RESCUE_ERRORS = StandardError
|
|
6
|
+
|
|
7
|
+
def self.call(no_of_retries: DEFAULT_MAX_NO_OF_RETRIES, rescue_errors: DEFAULT_RESCUE_ERRORS, &blk)
|
|
8
|
+
total_attempts = 0
|
|
9
|
+
begin
|
|
10
|
+
blk.call
|
|
11
|
+
rescue rescue_errors => ex
|
|
12
|
+
total_attempts += 1
|
|
13
|
+
retry if total_attempts < no_of_retries
|
|
14
|
+
ensure
|
|
15
|
+
if total_attempts == no_of_retries
|
|
16
|
+
return
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
"title": "JSON API Schema",
|
|
4
|
+
"description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
|
|
5
|
+
"oneOf": [
|
|
6
|
+
{
|
|
7
|
+
"$ref": "#/definitions/success"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"$ref": "#/definitions/failure"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"$ref": "#/definitions/info"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
"definitions": {
|
|
18
|
+
"success": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"required": [
|
|
21
|
+
"data"
|
|
22
|
+
],
|
|
23
|
+
"properties": {
|
|
24
|
+
"data": {
|
|
25
|
+
"$ref": "#/definitions/data"
|
|
26
|
+
},
|
|
27
|
+
"included": {
|
|
28
|
+
"description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": {
|
|
31
|
+
"$ref": "#/definitions/resource"
|
|
32
|
+
},
|
|
33
|
+
"uniqueItems": true
|
|
34
|
+
},
|
|
35
|
+
"meta": {
|
|
36
|
+
"$ref": "#/definitions/meta"
|
|
37
|
+
},
|
|
38
|
+
"links": {
|
|
39
|
+
"description": "Link members related to the primary data.",
|
|
40
|
+
"allOf": [
|
|
41
|
+
{
|
|
42
|
+
"$ref": "#/definitions/links"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"$ref": "#/definitions/pagination"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"jsonapi": {
|
|
50
|
+
"$ref": "#/definitions/jsonapi"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"additionalProperties": false
|
|
54
|
+
},
|
|
55
|
+
"failure": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"required": [
|
|
58
|
+
"errors"
|
|
59
|
+
],
|
|
60
|
+
"properties": {
|
|
61
|
+
"errors": {
|
|
62
|
+
"type": "array",
|
|
63
|
+
"items": {
|
|
64
|
+
"$ref": "#/definitions/error"
|
|
65
|
+
},
|
|
66
|
+
"uniqueItems": true
|
|
67
|
+
},
|
|
68
|
+
"meta": {
|
|
69
|
+
"$ref": "#/definitions/meta"
|
|
70
|
+
},
|
|
71
|
+
"jsonapi": {
|
|
72
|
+
"$ref": "#/definitions/jsonapi"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"additionalProperties": false
|
|
76
|
+
},
|
|
77
|
+
"info": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": [
|
|
80
|
+
"meta"
|
|
81
|
+
],
|
|
82
|
+
"properties": {
|
|
83
|
+
"meta": {
|
|
84
|
+
"$ref": "#/definitions/meta"
|
|
85
|
+
},
|
|
86
|
+
"links": {
|
|
87
|
+
"$ref": "#/definitions/links"
|
|
88
|
+
},
|
|
89
|
+
"jsonapi": {
|
|
90
|
+
"$ref": "#/definitions/jsonapi"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"additionalProperties": false
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
"meta": {
|
|
97
|
+
"description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
|
|
98
|
+
"type": "object",
|
|
99
|
+
"additionalProperties": true
|
|
100
|
+
},
|
|
101
|
+
"data": {
|
|
102
|
+
"description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
|
|
103
|
+
"oneOf": [
|
|
104
|
+
{
|
|
105
|
+
"$ref": "#/definitions/resource"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": {
|
|
111
|
+
"$ref": "#/definitions/resource"
|
|
112
|
+
},
|
|
113
|
+
"uniqueItems": true
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"description": "null if the request is one that might correspond to a single resource, but doesn't currently.",
|
|
117
|
+
"type": "null"
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"resource": {
|
|
122
|
+
"description": "\"Resource objects\" appear in a JSON API document to represent resources.",
|
|
123
|
+
"type": "object",
|
|
124
|
+
"required": [
|
|
125
|
+
"type",
|
|
126
|
+
"id"
|
|
127
|
+
],
|
|
128
|
+
"properties": {
|
|
129
|
+
"type": {
|
|
130
|
+
"type": "string"
|
|
131
|
+
},
|
|
132
|
+
"id": {
|
|
133
|
+
"type": "string"
|
|
134
|
+
},
|
|
135
|
+
"attributes": {
|
|
136
|
+
"$ref": "#/definitions/attributes"
|
|
137
|
+
},
|
|
138
|
+
"relationships": {
|
|
139
|
+
"$ref": "#/definitions/relationships"
|
|
140
|
+
},
|
|
141
|
+
"links": {
|
|
142
|
+
"$ref": "#/definitions/links"
|
|
143
|
+
},
|
|
144
|
+
"meta": {
|
|
145
|
+
"$ref": "#/definitions/meta"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"additionalProperties": false
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
"links": {
|
|
152
|
+
"description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.",
|
|
153
|
+
"type": "object",
|
|
154
|
+
"properties": {
|
|
155
|
+
"self": {
|
|
156
|
+
"description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.",
|
|
157
|
+
"type": "string",
|
|
158
|
+
"format": "uri"
|
|
159
|
+
},
|
|
160
|
+
"related": {
|
|
161
|
+
"$ref": "#/definitions/link"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"additionalProperties": true
|
|
165
|
+
},
|
|
166
|
+
"link": {
|
|
167
|
+
"description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
|
|
168
|
+
"oneOf": [
|
|
169
|
+
{
|
|
170
|
+
"description": "A string containing the link's URL.",
|
|
171
|
+
"type": "string",
|
|
172
|
+
"format": "uri"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"type": "object",
|
|
176
|
+
"required": [
|
|
177
|
+
"href"
|
|
178
|
+
],
|
|
179
|
+
"properties": {
|
|
180
|
+
"href": {
|
|
181
|
+
"description": "A string containing the link's URL.",
|
|
182
|
+
"type": "string",
|
|
183
|
+
"format": "uri"
|
|
184
|
+
},
|
|
185
|
+
"meta": {
|
|
186
|
+
"$ref": "#/definitions/meta"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
"attributes": {
|
|
194
|
+
"description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
|
|
195
|
+
"type": "object",
|
|
196
|
+
"patternProperties": {
|
|
197
|
+
"^(?!relationships$|links$)\\w[-\\w_]*$": {
|
|
198
|
+
"description": "Attributes may contain any valid JSON value."
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"additionalProperties": false
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
"relationships": {
|
|
205
|
+
"description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
|
|
206
|
+
"type": "object",
|
|
207
|
+
"patternProperties": {
|
|
208
|
+
"^\\w[-\\w_]*$": {
|
|
209
|
+
"properties": {
|
|
210
|
+
"links": {
|
|
211
|
+
"$ref": "#/definitions/links"
|
|
212
|
+
},
|
|
213
|
+
"data": {
|
|
214
|
+
"description": "Member, whose value represents \"resource linkage\".",
|
|
215
|
+
"oneOf": [
|
|
216
|
+
{
|
|
217
|
+
"$ref": "#/definitions/relationshipToOne"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"$ref": "#/definitions/relationshipToMany"
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
"meta": {
|
|
225
|
+
"$ref": "#/definitions/meta"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"additionalProperties": false
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
"additionalProperties": false
|
|
232
|
+
},
|
|
233
|
+
"relationshipToOne": {
|
|
234
|
+
"description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.",
|
|
235
|
+
"anyOf": [
|
|
236
|
+
{
|
|
237
|
+
"$ref": "#/definitions/empty"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"$ref": "#/definitions/linkage"
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"relationshipToMany": {
|
|
245
|
+
"description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
|
|
246
|
+
"type": "array",
|
|
247
|
+
"items": {
|
|
248
|
+
"$ref": "#/definitions/linkage"
|
|
249
|
+
},
|
|
250
|
+
"uniqueItems": true
|
|
251
|
+
},
|
|
252
|
+
"empty": {
|
|
253
|
+
"description": "Describes an empty to-one relationship.",
|
|
254
|
+
"type": "null"
|
|
255
|
+
},
|
|
256
|
+
"linkage": {
|
|
257
|
+
"description": "The \"type\" and \"id\" to non-empty members.",
|
|
258
|
+
"type": "object",
|
|
259
|
+
"required": [
|
|
260
|
+
"type",
|
|
261
|
+
"id"
|
|
262
|
+
],
|
|
263
|
+
"properties": {
|
|
264
|
+
"type": {
|
|
265
|
+
"type": "string"
|
|
266
|
+
},
|
|
267
|
+
"id": {
|
|
268
|
+
"type": "string"
|
|
269
|
+
},
|
|
270
|
+
"meta": {
|
|
271
|
+
"$ref": "#/definitions/meta"
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
"additionalProperties": false
|
|
275
|
+
},
|
|
276
|
+
"pagination": {
|
|
277
|
+
"type": "object",
|
|
278
|
+
"properties": {
|
|
279
|
+
"first": {
|
|
280
|
+
"description": "The first page of data",
|
|
281
|
+
"oneOf": [
|
|
282
|
+
{ "type": "string", "format": "uri" },
|
|
283
|
+
{ "type": "null" }
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
"last": {
|
|
287
|
+
"description": "The last page of data",
|
|
288
|
+
"oneOf": [
|
|
289
|
+
{ "type": "string", "format": "uri" },
|
|
290
|
+
{ "type": "null" }
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
"prev": {
|
|
294
|
+
"description": "The previous page of data",
|
|
295
|
+
"oneOf": [
|
|
296
|
+
{ "type": "string", "format": "uri" },
|
|
297
|
+
{ "type": "null" }
|
|
298
|
+
]
|
|
299
|
+
},
|
|
300
|
+
"next": {
|
|
301
|
+
"description": "The next page of data",
|
|
302
|
+
"oneOf": [
|
|
303
|
+
{ "type": "string", "format": "uri" },
|
|
304
|
+
{ "type": "null" }
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
"jsonapi": {
|
|
311
|
+
"description": "An object describing the server's implementation",
|
|
312
|
+
"type": "object",
|
|
313
|
+
"properties": {
|
|
314
|
+
"version": {
|
|
315
|
+
"type": "string"
|
|
316
|
+
},
|
|
317
|
+
"meta": {
|
|
318
|
+
"$ref": "#/definitions/meta"
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"additionalProperties": false
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
"error": {
|
|
325
|
+
"type": "object",
|
|
326
|
+
"properties": {
|
|
327
|
+
"id": {
|
|
328
|
+
"description": "A unique identifier for this particular occurrence of the problem.",
|
|
329
|
+
"type": "string"
|
|
330
|
+
},
|
|
331
|
+
"links": {
|
|
332
|
+
"$ref": "#/definitions/links"
|
|
333
|
+
},
|
|
334
|
+
"status": {
|
|
335
|
+
"description": "The HTTP status code applicable to this problem, expressed as a string value.",
|
|
336
|
+
"type": "string"
|
|
337
|
+
},
|
|
338
|
+
"code": {
|
|
339
|
+
"description": "An application-specific error code, expressed as a string value.",
|
|
340
|
+
"type": "string"
|
|
341
|
+
},
|
|
342
|
+
"title": {
|
|
343
|
+
"description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
|
|
344
|
+
"type": "string"
|
|
345
|
+
},
|
|
346
|
+
"detail": {
|
|
347
|
+
"description": "A human-readable explanation specific to this occurrence of the problem.",
|
|
348
|
+
"type": "string"
|
|
349
|
+
},
|
|
350
|
+
"source": {
|
|
351
|
+
"type": "object",
|
|
352
|
+
"properties": {
|
|
353
|
+
"pointer": {
|
|
354
|
+
"description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
|
|
355
|
+
"type": "string"
|
|
356
|
+
},
|
|
357
|
+
"parameter": {
|
|
358
|
+
"description": "A string indicating which query parameter caused the error.",
|
|
359
|
+
"type": "string"
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
"meta": {
|
|
364
|
+
"$ref": "#/definitions/meta"
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
"additionalProperties": false
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|