simple_jsonapi 1.0.0
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/.gitignore +10 -0
- data/.rubocop.yml +131 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +5 -0
- data/Jenkinsfile +92 -0
- data/LICENSE.txt +22 -0
- data/README.md +532 -0
- data/Rakefile +10 -0
- data/lib/simple_jsonapi.rb +112 -0
- data/lib/simple_jsonapi/definition/attribute.rb +45 -0
- data/lib/simple_jsonapi/definition/base.rb +50 -0
- data/lib/simple_jsonapi/definition/concerns/has_links_object.rb +36 -0
- data/lib/simple_jsonapi/definition/concerns/has_meta_object.rb +36 -0
- data/lib/simple_jsonapi/definition/error.rb +70 -0
- data/lib/simple_jsonapi/definition/error_source.rb +29 -0
- data/lib/simple_jsonapi/definition/link.rb +27 -0
- data/lib/simple_jsonapi/definition/meta.rb +27 -0
- data/lib/simple_jsonapi/definition/relationship.rb +60 -0
- data/lib/simple_jsonapi/definition/resource.rb +104 -0
- data/lib/simple_jsonapi/error_serializer.rb +76 -0
- data/lib/simple_jsonapi/errors/bad_request.rb +11 -0
- data/lib/simple_jsonapi/errors/exception_serializer.rb +6 -0
- data/lib/simple_jsonapi/errors/wrapped_error.rb +35 -0
- data/lib/simple_jsonapi/errors/wrapped_error_serializer.rb +35 -0
- data/lib/simple_jsonapi/helpers/exceptions.rb +39 -0
- data/lib/simple_jsonapi/helpers/serializer_inferrer.rb +136 -0
- data/lib/simple_jsonapi/helpers/serializer_methods.rb +36 -0
- data/lib/simple_jsonapi/node/attributes.rb +51 -0
- data/lib/simple_jsonapi/node/base.rb +91 -0
- data/lib/simple_jsonapi/node/data/collection.rb +25 -0
- data/lib/simple_jsonapi/node/data/singular.rb +26 -0
- data/lib/simple_jsonapi/node/document/base.rb +62 -0
- data/lib/simple_jsonapi/node/document/collection.rb +17 -0
- data/lib/simple_jsonapi/node/document/errors.rb +17 -0
- data/lib/simple_jsonapi/node/document/singular.rb +17 -0
- data/lib/simple_jsonapi/node/error.rb +55 -0
- data/lib/simple_jsonapi/node/error_source.rb +40 -0
- data/lib/simple_jsonapi/node/errors.rb +28 -0
- data/lib/simple_jsonapi/node/included.rb +45 -0
- data/lib/simple_jsonapi/node/object_links.rb +40 -0
- data/lib/simple_jsonapi/node/object_meta.rb +40 -0
- data/lib/simple_jsonapi/node/relationship.rb +79 -0
- data/lib/simple_jsonapi/node/relationship_data/base.rb +53 -0
- data/lib/simple_jsonapi/node/relationship_data/collection.rb +32 -0
- data/lib/simple_jsonapi/node/relationship_data/singular.rb +33 -0
- data/lib/simple_jsonapi/node/relationships.rb +60 -0
- data/lib/simple_jsonapi/node/resource/base.rb +21 -0
- data/lib/simple_jsonapi/node/resource/full.rb +49 -0
- data/lib/simple_jsonapi/node/resource/linkage.rb +25 -0
- data/lib/simple_jsonapi/parameters/fields_spec.rb +45 -0
- data/lib/simple_jsonapi/parameters/include_spec.rb +57 -0
- data/lib/simple_jsonapi/parameters/sort_spec.rb +107 -0
- data/lib/simple_jsonapi/serializer.rb +89 -0
- data/lib/simple_jsonapi/version.rb +3 -0
- data/simple_jsonapi.gemspec +29 -0
- data/test/errors/bad_request_test.rb +34 -0
- data/test/errors/error_serializer_test.rb +229 -0
- data/test/errors/exception_serializer_test.rb +25 -0
- data/test/errors/wrapped_error_serializer_test.rb +91 -0
- data/test/errors/wrapped_error_test.rb +44 -0
- data/test/parameters/fields_spec_test.rb +56 -0
- data/test/parameters/include_spec_test.rb +58 -0
- data/test/parameters/sort_spec_test.rb +65 -0
- data/test/resources/attributes_test.rb +109 -0
- data/test/resources/extras_test.rb +70 -0
- data/test/resources/id_and_type_test.rb +76 -0
- data/test/resources/inclusion_test.rb +134 -0
- data/test/resources/links_test.rb +63 -0
- data/test/resources/meta_test.rb +49 -0
- data/test/resources/relationships_test.rb +262 -0
- data/test/resources/sorting_test.rb +79 -0
- data/test/resources/sparse_fieldset_test.rb +160 -0
- data/test/root_objects_test.rb +165 -0
- data/test/test_helper.rb +31 -0
- metadata +235 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
module SimpleJsonapi::Node::Resource
|
2
|
+
# Represents a single resource object.
|
3
|
+
class Full < Base
|
4
|
+
# @param options see {Node::Resource::Base#initialize} for additional parameters
|
5
|
+
def initialize(**options)
|
6
|
+
super(options)
|
7
|
+
|
8
|
+
@attributes_node = build_child_node(
|
9
|
+
SimpleJsonapi::Node::Attributes,
|
10
|
+
resource: resource,
|
11
|
+
resource_type: resource_type,
|
12
|
+
attribute_definitions: serializer.attribute_definitions,
|
13
|
+
)
|
14
|
+
|
15
|
+
@relationships_node = build_child_node(
|
16
|
+
SimpleJsonapi::Node::Relationships,
|
17
|
+
resource: resource,
|
18
|
+
resource_type: resource_type,
|
19
|
+
relationship_definitions: serializer.relationship_definitions,
|
20
|
+
)
|
21
|
+
|
22
|
+
@links_node = build_child_node(
|
23
|
+
SimpleJsonapi::Node::ObjectLinks,
|
24
|
+
object: resource,
|
25
|
+
link_definitions: serializer.link_definitions,
|
26
|
+
)
|
27
|
+
|
28
|
+
@meta_node = build_child_node(
|
29
|
+
SimpleJsonapi::Node::ObjectMeta,
|
30
|
+
object: resource,
|
31
|
+
meta_definitions: serializer.meta_definitions,
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Hash{Symbol => Hash}]
|
36
|
+
def as_jsonapi
|
37
|
+
json = {}
|
38
|
+
json[:id] = resource_id
|
39
|
+
json[:type] = resource_type
|
40
|
+
|
41
|
+
json.merge!(@attributes_node.as_jsonapi)
|
42
|
+
json.merge!(@relationships_node.as_jsonapi)
|
43
|
+
json.merge!(@links_node.as_jsonapi)
|
44
|
+
json.merge!(@meta_node.as_jsonapi)
|
45
|
+
|
46
|
+
json
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SimpleJsonapi::Node::Resource
|
2
|
+
# Represents a single resource linkage object.
|
3
|
+
#
|
4
|
+
# @!attribute [r] meta
|
5
|
+
# @return [Hash{Symbol => Object}]
|
6
|
+
class Linkage < Base
|
7
|
+
attr_reader :meta
|
8
|
+
|
9
|
+
# @param meta [Hash{Symbol => Object}]
|
10
|
+
# @param options see {Node::Resource::Base#initialize} for additional parameters
|
11
|
+
def initialize(meta: nil, **options)
|
12
|
+
super(options)
|
13
|
+
@meta = meta
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Hash{Symbol => Hash}]
|
17
|
+
def as_jsonapi
|
18
|
+
json = {}
|
19
|
+
json[:id] = resource_id
|
20
|
+
json[:type] = resource_type
|
21
|
+
json[:meta] = meta if meta.present?
|
22
|
+
json
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module SimpleJsonapi::Parameters
|
2
|
+
# Represents the +fields+ parameter as defined by the JSONAPI spec.
|
3
|
+
class FieldsSpec
|
4
|
+
# Wraps a +fields+ parameter in a {FieldsSpec} instance.
|
5
|
+
# @param fields [Hash{Symbol => String},FieldsSpec]
|
6
|
+
def self.wrap(fields)
|
7
|
+
if fields.is_a?(FieldsSpec)
|
8
|
+
fields
|
9
|
+
else
|
10
|
+
FieldsSpec.new(fields)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param specs [Hash{Symbol => String,Array<String>,Array<Symbol>}]
|
15
|
+
# The hash keys are resource types, and the values are lists of field names to render in the output.
|
16
|
+
def initialize(specs = {})
|
17
|
+
@data = {}
|
18
|
+
merge(specs) if specs.present?
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param specs [Hash{Symbol => String,Array<String>,Array<Symbol>}]
|
22
|
+
# The hash keys are resource types, and the values are lists of field names to render in the output.
|
23
|
+
# @return [self]
|
24
|
+
def merge(specs = {})
|
25
|
+
specs.each do |type, fields|
|
26
|
+
@data[type.to_sym] = Array
|
27
|
+
.wrap(fields)
|
28
|
+
.flat_map { |s| s.to_s.split(",") }
|
29
|
+
.map { |s| s.strip.to_sym }
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param type [String,Symbol]
|
35
|
+
# @return [Array<Symbol>]
|
36
|
+
def [](type)
|
37
|
+
@data[type.to_sym]
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param type [String,Symbol]
|
41
|
+
def all_fields?(type)
|
42
|
+
@data[type.to_sym].nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module SimpleJsonapi::Parameters
|
2
|
+
# Represents the +include+ parameter as defined by the JSONAPI spec.
|
3
|
+
class IncludeSpec
|
4
|
+
# Wraps an +include+ parameter in an {IncludeSpec} instance.
|
5
|
+
# @param specs [IncludeSpec,String,Array<String>,Array<Symbol>]
|
6
|
+
def self.wrap(specs)
|
7
|
+
if specs.is_a?(IncludeSpec)
|
8
|
+
specs
|
9
|
+
else
|
10
|
+
IncludeSpec.new(specs)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param specs [String,Array<String>,Array<Symbol>]
|
15
|
+
# e.g. <code>"author,comments,comments.author"</code> or <code>["author", "comments", "comments.author"]</code>
|
16
|
+
def initialize(*specs)
|
17
|
+
@data = {}
|
18
|
+
merge(*specs) if specs.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param specs [String,Array<String>,Array<Symbol>]
|
22
|
+
# e.g. <code>"author,comments,comments.author"</code> or <code>["author", "comments", "comments.author"]</code>
|
23
|
+
# @return [self]
|
24
|
+
def merge(*specs)
|
25
|
+
paths = specs.flatten.flat_map { |s| s.to_s.split(",") }
|
26
|
+
|
27
|
+
paths.each do |path|
|
28
|
+
terms = path.split(".")
|
29
|
+
|
30
|
+
nested_spec = @data[terms.first.to_sym] ||= IncludeSpec.new
|
31
|
+
if terms.size > 1
|
32
|
+
nested_spec.merge(terms.drop(1).join("."))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param relationship_name [String,Symbol]
|
40
|
+
# @return [IncludeSpec]
|
41
|
+
def [](relationship_name)
|
42
|
+
@data[relationship_name.to_sym]
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param relationship_name [String,Symbol]
|
46
|
+
def include?(relationship_name)
|
47
|
+
@data.key?(relationship_name.to_sym)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Hash]
|
51
|
+
def to_h
|
52
|
+
@data.each_with_object({}) do |(name, spec), hash|
|
53
|
+
hash[name] = spec.to_h
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module SimpleJsonapi::Parameters
|
2
|
+
# Represents the +sort+ parameter as defined by the JSONAPI spec.
|
3
|
+
class SortSpec
|
4
|
+
# Wraps a +sort+ parameter in a {SortSpec} instance.
|
5
|
+
# @param sorts [SortSpec,Hash{Symbol => String},Hash{Symbol => Array<String>}]
|
6
|
+
def self.wrap(sorts)
|
7
|
+
if sorts.is_a?(SortSpec)
|
8
|
+
sorts
|
9
|
+
else
|
10
|
+
SortSpec.new(sorts)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Creates a {SortSpec} that raises an error when it's called.
|
15
|
+
# @return [SortSpec]
|
16
|
+
def self.not_supported
|
17
|
+
@not_supported ||= new.tap do |spec|
|
18
|
+
spec.instance_variable_set(:@not_supported, true)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :inspect, :to_s, to: :@data
|
23
|
+
|
24
|
+
# @param specs [Hash{Symbol => String},Hash{Symbol => Array<String>}]
|
25
|
+
# e.g., { comments: "-date,author" }
|
26
|
+
def initialize(specs = {})
|
27
|
+
@not_supported = nil
|
28
|
+
@data = Hash.new { |_h, _k| [] }
|
29
|
+
merge(specs) if specs.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param specs [Hash{Symbol => String},Hash{Symbol => Array<String>}]
|
33
|
+
# e.g., { comments: "-date,author" } or { comments: ["-date", "author"] }
|
34
|
+
# @return [self]
|
35
|
+
def merge(specs = {})
|
36
|
+
specs.each do |relationship_name, field_specs|
|
37
|
+
@data[relationship_name.to_sym] = Array
|
38
|
+
.wrap(field_specs)
|
39
|
+
.flat_map { |fs| fs.to_s.split(",") }
|
40
|
+
.map { |fs| SortFieldSpec.new(fs) }
|
41
|
+
.presence
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param relationship_name [String,Symbol]
|
47
|
+
# @return [SortFieldSpec]
|
48
|
+
def [](relationship_name)
|
49
|
+
if not_supported?
|
50
|
+
raise NotImplementedError, "Sorting nested relationships is not implemented."
|
51
|
+
else
|
52
|
+
@data[relationship_name.to_sym]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def not_supported?
|
59
|
+
!!@not_supported
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Represents a single field (and direction) in a {SortSpec}.
|
64
|
+
# @!attribute [rw] field
|
65
|
+
# @return Symbol
|
66
|
+
# @!attribute [rw] dir
|
67
|
+
# @return [:asc,:desc]
|
68
|
+
class SortFieldSpec
|
69
|
+
attr_accessor :field, :dir
|
70
|
+
|
71
|
+
# @param spec [String]
|
72
|
+
def initialize(spec)
|
73
|
+
if spec =~ /\A(-?)(\w+)\Z/
|
74
|
+
self.field = $2.to_sym
|
75
|
+
self.dir = ($1 == '-' ? :desc : :asc)
|
76
|
+
else
|
77
|
+
raise ArgumentError, "field spec must match 'field' or '-field'"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def asc?
|
82
|
+
dir == :asc
|
83
|
+
end
|
84
|
+
|
85
|
+
def desc?
|
86
|
+
dir == :desc
|
87
|
+
end
|
88
|
+
|
89
|
+
def dup
|
90
|
+
SortFieldSpec.new(to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
def ==(other)
|
94
|
+
other.respond_to?(:field) && other.respond_to?(:dir) && [field, dir] == [other.field, other.dir]
|
95
|
+
end
|
96
|
+
alias_method :eql?, :==
|
97
|
+
|
98
|
+
def hash
|
99
|
+
[field, dir].hash
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
"#{'-' if desc?}#{field}"
|
104
|
+
end
|
105
|
+
alias_method :inspect, :to_s
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Subclass {Serializer} to create serializers for specific types of resources.
|
2
|
+
class SimpleJsonapi::Serializer
|
3
|
+
include SimpleJsonapi::SerializerMethods
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# @overload (see Definition::Resource#id)
|
7
|
+
# @return (see Definition::Resource#id)
|
8
|
+
def id(*args, &block)
|
9
|
+
definition.id(*args, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @overload (see Definition::Resource#type)
|
13
|
+
# @return (see Definition::Resource#type)
|
14
|
+
def type(*args, &block)
|
15
|
+
definition.type(*args, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @overload (see Definition::Resource#id)
|
19
|
+
# @return (see Definition::Resource#id)
|
20
|
+
# @overload attribute(name, options = {})
|
21
|
+
# @overload attribute(name, options = {}, &block)
|
22
|
+
# @return (see Definition::Resource#attribute)
|
23
|
+
def attribute(name, **options, &block)
|
24
|
+
definition.attribute(name, **options, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @overload (see Definition::Resource#has_one)
|
28
|
+
# @param (see Definition::Resource#has_one)
|
29
|
+
# @yieldparam (see Definition::Resource#has_one)
|
30
|
+
# @yieldreturn (see Definition::Resource#has_one)
|
31
|
+
# @return (see Definition::Resource#has_one)
|
32
|
+
def has_one(name, **options, &block)
|
33
|
+
definition.has_one(name, **options, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @overload (see Definition::Resource#has_many)
|
37
|
+
# @param (see Definition::Resource#has_many)
|
38
|
+
# @yieldparam (see Definition::Resource#has_many)
|
39
|
+
# @yieldreturn (see Definition::Resource#has_many)
|
40
|
+
# @return (see Definition::Resource#has_many)
|
41
|
+
def has_many(name, **options, &block)
|
42
|
+
definition.has_many(name, **options, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @overload (see Definition::Concerns::HasLinksObject#link)
|
46
|
+
# @return (see Definition::Concerns::HasLinksObject#link)
|
47
|
+
def link(name, *args, **options, &block)
|
48
|
+
definition.link(name, *args, **options, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @overload (see Definition::Concerns::HasMetaObject#meta)
|
52
|
+
# @return (see Definition::Concerns::HasMetaObject#meta)
|
53
|
+
def meta(name, *args, **options, &block)
|
54
|
+
definition.meta(name, *args, **options, &block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
self.definition = SimpleJsonapi::Definition::Resource.new
|
59
|
+
|
60
|
+
# @return (see Definition::Resource#id_definition)
|
61
|
+
def id_definition
|
62
|
+
definition.id_definition
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return (see Definition::Resource#type_definition)
|
66
|
+
def type_definition
|
67
|
+
definition.type_definition
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return (see Definition::Resource#attribute_definitions)
|
71
|
+
def attribute_definitions
|
72
|
+
definition.attribute_definitions
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return (see Definition::Resource#relationship_definitions)
|
76
|
+
def relationship_definitions
|
77
|
+
definition.relationship_definitions
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return (see Definition::Concerns::HasLinksObject#link_definitions)
|
81
|
+
def link_definitions
|
82
|
+
definition.link_definitions
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return (see Definition::Concerns::HasMetaObject#meta_definitions)
|
86
|
+
def meta_definitions
|
87
|
+
definition.meta_definitions
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'simple_jsonapi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'simple_jsonapi'
|
8
|
+
spec.version = SimpleJsonapi::VERSION
|
9
|
+
spec.license = "MIT"
|
10
|
+
spec.authors = ['PatientsLikeMe']
|
11
|
+
spec.email = ['engineers@patientslikeme.com']
|
12
|
+
spec.homepage = 'https://www.patientslikeme.com'
|
13
|
+
|
14
|
+
spec.summary = 'A library for building JSONAPI documents in Ruby.'
|
15
|
+
spec.description = 'A library for building JSONAPI documents in Ruby.'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'activesupport', '~> 5.1'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
spec.add_development_dependency 'minitest'
|
26
|
+
spec.add_development_dependency 'minitest-reporters'
|
27
|
+
spec.add_development_dependency 'pry'
|
28
|
+
spec.add_development_dependency 'mocha'
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BadRequestTest < Minitest::Spec
|
4
|
+
let(:error) do
|
5
|
+
SimpleJsonapi::Errors::BadRequest.new(
|
6
|
+
id: "the id",
|
7
|
+
status: "the status",
|
8
|
+
code: "the code",
|
9
|
+
title: "the title",
|
10
|
+
detail: "the detail",
|
11
|
+
source_pointer: "the source pointer",
|
12
|
+
source_parameter: "the source parameter",
|
13
|
+
about_link: "the about link",
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe SimpleJsonapi::Errors::BadRequest do
|
18
|
+
describe "properties" do
|
19
|
+
it "are assigned specific values" do
|
20
|
+
assert_equal "400", error.status
|
21
|
+
assert_equal "bad_request", error.code
|
22
|
+
assert_equal "Bad request", error.title
|
23
|
+
end
|
24
|
+
|
25
|
+
it "are stored" do
|
26
|
+
assert_equal "the id", error.id
|
27
|
+
assert_equal "the detail", error.detail
|
28
|
+
assert_equal "the source pointer", error.source_pointer
|
29
|
+
assert_equal "the source parameter", error.source_parameter
|
30
|
+
assert_equal "the about link", error.about_link
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|