sinatra-schema 0.0.4 → 0.0.5

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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- OTg4NGUxMjY3YWRjOGI3ZTQ4NDI3ZGU5ZTIyNGU2ZmM1OWQ1ZWUxOQ==
5
- data.tar.gz: !binary |-
6
- MGVlODRhMWE1YzgxZjJhNGYyOWYzYzMyNDMwZWQxNzdiMzZlOTVmNg==
2
+ SHA1:
3
+ metadata.gz: efba21adbb69d56337bf911bf277b98f99da8781
4
+ data.tar.gz: f90d52c93a3dc9207f01a075502c383f02f502b4
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MzRmMjhjOGEwODY5ZjU5YWU5OTM0MWExMTgwYzllYmVkMjAxNjMwMmI5NTlj
10
- ZTg3YmVjOGZjNGRmZDgwMmE1NTcyMWUwMTk2YjIwNGU2ZTIxODNmYmQ0NWVm
11
- ZGViNGRhYzgzMzVkNjhmNGMxNGY3M2JlYmE0NDMwMzNmMzk5OTY=
12
- data.tar.gz: !binary |-
13
- Njg2Mjg4MGM5YzFiNjY5YWNhZGM4YjIxYThlYzgyNDQyYTg4NzMzZWUxMThj
14
- MjJkMTU1MzQzNDNjZGNlN2ZiZGNjMGViZjc0NzAzYzk3NjI3M2QyMjkxYmUz
15
- OWM3MjdjNDIyOGQ0ZWE2M2NmZTVkN2RhOTc1NzAwMDEyZDNiZjg=
6
+ metadata.gz: 7eda67c2a0f5d08c9ad7a1b4272c5260c43e96f55cb192e40a1b88f6d0fd3dd9f7c7d9f3fe68cfb1af4daf091e1766bcd75e65cf3cf769ecb83e82a50f3927a2
7
+ data.tar.gz: cd59d186c53e8c262309a6eae7ec232f4d878b65bc76081d4defe6702c22e15785d4ed0e4299879e6c668f40ffd830da57406f75d412b1e7011975a662d264fa
data/README.md CHANGED
@@ -5,8 +5,6 @@
5
5
 
6
6
  Define a schema for your Sinatra application to get requests and responses validated. Dump it schema as a JSON Schema to aid client generation and more!
7
7
 
8
- **Under design**. The reference below might be outdated – please check specs to see the latest.
9
-
10
8
 
11
9
  ## Usage
12
10
 
@@ -39,18 +37,19 @@ resource("/account") do |res|
39
37
 
40
38
  res.link(:post) do |link|
41
39
  link.property.ref :email # reuse the property defined above
40
+ link.property.text :role, optional: true
42
41
  link.property.bool :admin
43
42
 
44
- link.action do |params|
45
- user = User.new(email: params[:email])
46
- if params[:admin] # params are casted accordingly!
43
+ link.action do |data|
44
+ user = User.new(email: data[:email])
45
+ if data[:admin] # schema params are casted accordingly!
47
46
  # ...
48
47
  end
49
48
  end
50
49
  end
51
50
  ```
52
51
 
53
- ### Cross-resource params
52
+ ### Reference properties across resources
54
53
 
55
54
  Reuse properties from other resources when appropriate:
56
55
 
@@ -71,11 +70,8 @@ These are also casted and validated as you'd expect:
71
70
 
72
71
  ```ruby
73
72
  resource("/albums") do |res|
74
- resource.link(:post) do |link|
75
- link.nested :artist do |a|
76
- a.property.text :name
77
- end
78
- end
73
+ res.property[:label].text :name
74
+ res.property[:label].bool :active
79
75
  end
80
76
  ```
81
77
 
@@ -116,6 +112,26 @@ $ rake schema
116
112
  }
117
113
  ```
118
114
 
115
+ ### Error handling
116
+
117
+ By default it will raise a 400 on bad requests (eg: invalid JSON request) and a 422 on bad params (eg: missing mandatory param):
118
+
119
+ ```
120
+ $ curl -d "" http://localhost:5000/account
121
+ {"error":"Missing expected params: email"}
122
+ ```
123
+
124
+ Redefine the error handlers to render a different status or serialize errors differently:
125
+
126
+ ```ruby
127
+ class MyApi < Sinatra::Base
128
+ register Sinatra::Schema
129
+
130
+ error(Sinatra::Schema::BadParams) do |e|
131
+ halt(422, MultiJson.encode(id: "bad_params", message: e.message))
132
+ end
133
+ end
134
+ ```
119
135
 
120
136
  ## Context
121
137
 
@@ -1,12 +1,13 @@
1
1
  module Sinatra
2
2
  module Schema
3
3
  class Definition
4
- attr_accessor :description, :example, :id, :type
4
+ attr_accessor :description, :example, :id, :optional, :type
5
5
 
6
6
  def initialize(options={})
7
7
  @description = options[:description]
8
8
  @example = options[:example]
9
9
  @id = options[:id]
10
+ @optional = options[:optional]
10
11
  @type = options[:type]
11
12
  end
12
13
 
@@ -23,8 +24,7 @@ module Sinatra
23
24
  end
24
25
 
25
26
  def valid?(value)
26
- # always accept nils for now
27
- return if value.nil?
27
+ return true if value.nil? && optional
28
28
 
29
29
  case type
30
30
  when "boolean"
@@ -30,32 +30,35 @@ module Sinatra
30
30
  add Definition.new(options)
31
31
  end
32
32
 
33
- def nested(id)
34
- # add a space in the definitions/properties for the nested def:
35
- targets.each { |h| h[id] = {} }
33
+ # support nested properties. eg: property[:foo].text :bar
34
+ def [](id)
35
+ # make sure all targets have a sub-hash for this nested def:
36
+ targets.each { |h| h[id] ||= {} }
36
37
 
37
- # yield a new DSL with updated targets
38
- yield Definitions.new(resource, targets.map { |h| h[id] })
38
+ # return a new DSL with updated targets so it can be chained:
39
+ Definitions.new(resource, targets.map { |h| h[id] })
39
40
  end
40
41
 
41
- def ref(id)
42
- unless definition = resource.defs[id] || Sinatra::Schema::Root.instance.find_definition(id)
42
+ def ref(id, ref_to=nil)
43
+ ref_to ||= id
44
+ unless definition = resource.defs[ref_to] || Sinatra::Schema::Root.instance.find_definition(ref_to)
43
45
  raise BadReference.new(id)
44
46
  end
45
- add definition, true
47
+ add definition, true, id
46
48
  end
47
49
 
48
50
  # TODO support other types
49
51
 
50
52
  protected
51
53
 
52
- def add(definition, reference=false)
54
+ def add(definition, reference=false, id=nil)
55
+ id ||= definition.id
53
56
  targets.each_with_index do |hash, i|
54
57
  # here's the trick, and here's why the first target is always the
55
58
  # resource def: skip it when adding a reference (eg: it's already)
56
59
  # in the resource def, just add the property!
57
60
  next if reference && i == 0
58
- hash[definition.id] = definition
61
+ hash[id] = definition
59
62
  end
60
63
  end
61
64
  end
@@ -26,6 +26,14 @@ module Sinatra
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ def to_schema
31
+ {
32
+ description: description,
33
+ href: href,
34
+ method: method.to_s.upcase,
35
+ }
36
+ end
29
37
  end
30
38
  end
31
39
  end
@@ -41,13 +41,7 @@ module Sinatra
41
41
  h[id] = definition.to_schema
42
42
  h
43
43
  },
44
- links: links.map { |link|
45
- {
46
- description: link.description,
47
- href: link.href,
48
- method: link.method.to_s.upcase,
49
- }
50
- }
44
+ links: links.map(&:to_schema)
51
45
  }
52
46
  end
53
47
  end
@@ -1,5 +1,5 @@
1
1
  module Sinatra
2
2
  module Schema
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -18,15 +18,18 @@ describe Sinatra::Schema::DSL::Definitions do
18
18
  end
19
19
 
20
20
  it "adds nested definitions" do
21
- dsl.nested(:user) do |prop|
22
- prop.text :email
23
- prop.bool :admin
24
- end
21
+ dsl[:user].text :email
22
+ dsl[:user].bool :admin
25
23
  assert_equal 2, resource.defs[:user].size
26
24
  assert_equal "string", resource.defs[:user][:email].type
27
25
  assert_equal "boolean", resource.defs[:user][:admin].type
28
26
  end
29
27
 
28
+ it "sets other options" do
29
+ dsl.text(:foobar, optional: true)
30
+ assert_equal true, resource.defs[:foobar].optional
31
+ end
32
+
30
33
  describe "#ref" do
31
34
  let(:definition) { Sinatra::Schema::Definition.new(id: :foobar) }
32
35
 
@@ -50,7 +53,15 @@ describe Sinatra::Schema::DSL::Definitions do
50
53
  assert_raises(Sinatra::Schema::BadReference) do
51
54
  dsl.ref :foobar
52
55
  end
56
+ end
53
57
 
58
+ it "allows references to have a different id" do
59
+ other = Sinatra::Schema::Resource.new(path: "/others")
60
+ root.add_resource(other)
61
+ other.defs[:foobar] = definition
62
+ dsl.ref :my_foobar, "other/foobar"
63
+ assert resource.properties.has_key?(:my_foobar)
64
+ assert_equal :foobar, resource.properties[:my_foobar].id
54
65
  end
55
66
  end
56
67
  end
@@ -23,10 +23,8 @@ describe Sinatra::Schema::DSL::Resources do
23
23
  end
24
24
 
25
25
  it "supports nested properties" do
26
- dsl.property.nested :user do |prop|
27
- prop.text :email
28
- prop.bool :admin
29
- end
26
+ dsl.property[:user].text :email
27
+ dsl.property[:user].bool :admin
30
28
  assert_equal 2, dsl.resource.properties[:user].size
31
29
  end
32
30
  end
@@ -26,6 +26,19 @@ describe Sinatra::Schema::ParamValidation do
26
26
  end
27
27
  end
28
28
 
29
+ it "errors out on required params" do
30
+ $properties = { foo: Sinatra::Schema::Definition.new(type: "string", optional: false) }
31
+ assert_raises(Sinatra::Schema::BadParams) do
32
+ post "/", MultiJson.encode(foo: nil)
33
+ end
34
+ end
35
+
36
+ it "allows optional params to be nil" do
37
+ $properties = { foo: Sinatra::Schema::Definition.new(type: "string", optional: true) }
38
+ post "/", MultiJson.encode(foo: nil)
39
+ assert_equal 200, last_response.status
40
+ end
41
+
29
42
  it "errors out on wrong format" do
30
43
  $properties = { bool: Sinatra::Schema::Definition.new(type: "boolean") }
31
44
  assert_raises(Sinatra::Schema::BadParams) do
@@ -37,7 +50,6 @@ describe Sinatra::Schema::ParamValidation do
37
50
  $properties = { foo: { bar: Sinatra::Schema::Definition.new(type: "boolean") }}
38
51
  assert_raises(Sinatra::Schema::BadParams) do
39
52
  post "/", MultiJson.encode(foo: { bar: "omg" })
40
- puts last_response.body
41
53
  end
42
54
  end
43
55
  end
metadata CHANGED
@@ -1,127 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Belo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-07 00:00:00.000000000 Z
11
+ date: 2014-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.0'
20
- - - ! '>='
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
22
  version: '4.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ~>
27
+ - - "~>"
28
28
  - !ruby/object:Gem::Version
29
29
  version: '4.0'
30
- - - ! '>='
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '4.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: multi_json
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ~>
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.9'
40
- - - ! '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: 1.9.3
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ~>
47
+ - - "~>"
48
48
  - !ruby/object:Gem::Version
49
49
  version: '1.9'
50
- - - ! '>='
50
+ - - ">="
51
51
  - !ruby/object:Gem::Version
52
52
  version: 1.9.3
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: sinatra
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - ~>
57
+ - - "~>"
58
58
  - !ruby/object:Gem::Version
59
59
  version: '1.4'
60
- - - ! '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: 1.4.4
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ~>
67
+ - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: '1.4'
70
- - - ! '>='
70
+ - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: 1.4.4
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: rack-test
75
75
  requirement: !ruby/object:Gem::Requirement
76
76
  requirements:
77
- - - ~>
77
+ - - "~>"
78
78
  - !ruby/object:Gem::Version
79
79
  version: '0.6'
80
- - - ! '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.6.2
83
83
  type: :development
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0.6'
90
- - - ! '>='
90
+ - - ">="
91
91
  - !ruby/object:Gem::Version
92
92
  version: 0.6.2
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: rake
95
95
  requirement: !ruby/object:Gem::Requirement
96
96
  requirements:
97
- - - ! '>'
97
+ - - ">"
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  type: :development
101
101
  prerelease: false
102
102
  version_requirements: !ruby/object:Gem::Requirement
103
103
  requirements:
104
- - - ! '>'
104
+ - - ">"
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  - !ruby/object:Gem::Dependency
108
108
  name: rspec
109
109
  requirement: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - ~>
111
+ - - "~>"
112
112
  - !ruby/object:Gem::Version
113
113
  version: '3.1'
114
- - - ! '>='
114
+ - - ">="
115
115
  - !ruby/object:Gem::Version
116
116
  version: 3.1.0
117
117
  type: :development
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ~>
121
+ - - "~>"
122
122
  - !ruby/object:Gem::Version
123
123
  version: '3.1'
124
- - - ! '>='
124
+ - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: 3.1.0
127
127
  description: Define a schema to validate requests and responses, expose it as JSON
@@ -169,17 +169,17 @@ require_paths:
169
169
  - lib
170
170
  required_ruby_version: !ruby/object:Gem::Requirement
171
171
  requirements:
172
- - - ! '>='
172
+ - - ">="
173
173
  - !ruby/object:Gem::Version
174
174
  version: '0'
175
175
  required_rubygems_version: !ruby/object:Gem::Requirement
176
176
  requirements:
177
- - - ! '>='
177
+ - - ">="
178
178
  - !ruby/object:Gem::Version
179
179
  version: '0'
180
180
  requirements: []
181
181
  rubyforge_project:
182
- rubygems_version: 2.2.2
182
+ rubygems_version: 2.4.3
183
183
  signing_key:
184
184
  specification_version: 4
185
185
  summary: Sinatra extension to support schemas