sinatra-schema 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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