pragma-operation 1.1.1 → 1.2.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 +4 -4
- data/doc/01-basic-usage.md +116 -5
- data/lib/pragma/operation/base.rb +40 -6
- data/lib/pragma/operation/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4af59fe5624f0ad6a25a16d2f3a34e6b4b24f7cc
|
4
|
+
data.tar.gz: 385279725b2ebbc9210535c274de95060025a4cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11d83a8c30d72bca7e25e86239d6170f6687bdc5113e0a0775feabc979ca9e8e743dbd30af3dc68607a37eb7eaaeb586302b33e641d48ad8359700e23fa614aa
|
7
|
+
data.tar.gz: 3900e69be07c8310c89955a858d100bef14132d47e87cddcd1eab83dc6e70176d152c4a05a568dbf3ccdb178f93b60c2045cddb4956d7ddc526aa93e2d99ed29
|
data/doc/01-basic-usage.md
CHANGED
@@ -12,10 +12,7 @@ module API
|
|
12
12
|
# The `status` parameter is optional (the default is `:ok`).
|
13
13
|
respond_with(
|
14
14
|
status: :ok,
|
15
|
-
resource: { pong: params[:pong] }
|
16
|
-
headers: {
|
17
|
-
'X-Ping-Time' => Time.now.to_i
|
18
|
-
}
|
15
|
+
resource: { pong: params[:pong] }
|
19
16
|
)
|
20
17
|
end
|
21
18
|
end
|
@@ -32,7 +29,6 @@ result = API::V1::Ping::Operation::Create.call(params: { pong: 'HELLO' })
|
|
32
29
|
|
33
30
|
result.status # => :ok
|
34
31
|
result.resource # => { pong: 'HELLO' }
|
35
|
-
result.headers # => { 'X-Ping-Time' => 1482927872 }
|
36
32
|
```
|
37
33
|
|
38
34
|
As you can see, an operation takes parameters as input and responds with:
|
@@ -62,6 +58,121 @@ Since Pragma::Operation is built on top of [Interactor](https://github.com/colle
|
|
62
58
|
you should consult its documentation for the basic usage of operations; the rest of this section
|
63
59
|
only covers the features provided specifically by Pragma::Operation.
|
64
60
|
|
61
|
+
## Headers
|
62
|
+
|
63
|
+
You can attach headers to your response by manipulating the `headers` hash:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
module API
|
67
|
+
module V1
|
68
|
+
module Post
|
69
|
+
module Operation
|
70
|
+
class Create < Pragma::Operation::Base
|
71
|
+
def call
|
72
|
+
post = ::Post.new(params)
|
73
|
+
post.save!
|
74
|
+
|
75
|
+
headers['X-Post-Id'] = post.id
|
76
|
+
|
77
|
+
respond_with status: :created, resource: post
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
You can also set headers when calling `#respond_with`:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
module API
|
90
|
+
module V1
|
91
|
+
module Post
|
92
|
+
module Operation
|
93
|
+
class Create < Pragma::Operation::Base
|
94
|
+
def call
|
95
|
+
post = ::Post.new(params)
|
96
|
+
post.save!
|
97
|
+
|
98
|
+
respond_with status: :created, resource: post, headers: {
|
99
|
+
'X-Post-Id' => post.id
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
## HATEOAS
|
110
|
+
|
111
|
+
Pragma::Operation supports HATEOAS by allowing you to specify a list of links to use for building
|
112
|
+
the `Link` header. You can set the links by manipulating the `links` hash.
|
113
|
+
|
114
|
+
For instance, here's how you could link to a post's comments and author:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
module API
|
118
|
+
module V1
|
119
|
+
module Post
|
120
|
+
module Operation
|
121
|
+
class Show < Pragma::Operation::Base
|
122
|
+
def call
|
123
|
+
post = ::Post.find(params[:id])
|
124
|
+
|
125
|
+
links['comments'] = "/posts/#{post.id}/comments"
|
126
|
+
links['author'] = "/users/#{post.author.id}"
|
127
|
+
|
128
|
+
respond_with resource: post
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
You can also set the links when calling `#respond_with`:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
module API
|
141
|
+
module V1
|
142
|
+
module Post
|
143
|
+
module Operation
|
144
|
+
class Show < Pragma::Operation::Base
|
145
|
+
def call
|
146
|
+
post = ::Post.find(params[:id])
|
147
|
+
|
148
|
+
respond_with resource: post, links: {
|
149
|
+
comments: "/posts/#{post.id}/comments",
|
150
|
+
author: "/users/#{post.author.id}"
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
This will build the `Link` header accordingly:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
result = API::V1::Post::Operation::Show.call(params: { id: 1 })
|
164
|
+
|
165
|
+
result.status # => :ok
|
166
|
+
result.headers
|
167
|
+
# => {
|
168
|
+
# 'Link' => '</posts/1/comments>; rel="comments",
|
169
|
+
# </users/49>; rel="author"'
|
170
|
+
# }
|
171
|
+
```
|
172
|
+
|
173
|
+
**Note: Do not set the `Link` header manually, as it will be replaced when building links from the
|
174
|
+
`links` hash.**
|
175
|
+
|
65
176
|
## Handling errors
|
66
177
|
|
67
178
|
You can use the `#success?` and `#failure?` method to check whether an operation was successful. An
|
@@ -77,6 +77,7 @@ module Pragma
|
|
77
77
|
before :setup_context
|
78
78
|
around :handle_halt
|
79
79
|
after :mark_result, :consolidate_status, :validate_status, :set_default_status
|
80
|
+
after :build_links
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
@@ -121,19 +122,21 @@ module Pragma
|
|
121
122
|
# method can be called multiple times, overriding the previous context.
|
122
123
|
#
|
123
124
|
# @param status [Integer|Symbol] an HTTP status code
|
124
|
-
# @param headers [Hash] HTTP headers
|
125
125
|
# @param resource [Object] an object responding to +#to_json+
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
context.
|
126
|
+
# @param headers [Hash] HTTP headers
|
127
|
+
# @param links [Hash] links to use for building the +Link+ header
|
128
|
+
def respond_with(status: nil, resource: nil, headers: nil, links: nil)
|
129
|
+
context.status = status if status
|
130
|
+
context.resource = resource if resource
|
131
|
+
context.headers = headers if headers
|
132
|
+
context.links = links if links
|
130
133
|
end
|
131
134
|
|
132
135
|
# Same as {#respond_with}, but also halts the execution of the operation.
|
133
136
|
#
|
134
137
|
# @see #respond_with
|
135
138
|
def respond_with!(*args)
|
136
|
-
respond_with
|
139
|
+
respond_with(*args)
|
137
140
|
fail Halt
|
138
141
|
end
|
139
142
|
|
@@ -168,6 +171,24 @@ module Pragma
|
|
168
171
|
context.current_user
|
169
172
|
end
|
170
173
|
|
174
|
+
# Returns the headers we are responding with.
|
175
|
+
#
|
176
|
+
# This is just a shortcut for +context.headers+.
|
177
|
+
#
|
178
|
+
# @return [Hash]
|
179
|
+
def headers
|
180
|
+
context.headers
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns the links we are responding with.
|
184
|
+
#
|
185
|
+
# This is just a shotcut for +context.links+.
|
186
|
+
#
|
187
|
+
# @return [Hash]
|
188
|
+
def links
|
189
|
+
context.links
|
190
|
+
end
|
191
|
+
|
171
192
|
private
|
172
193
|
|
173
194
|
def with_hooks
|
@@ -187,6 +208,7 @@ module Pragma
|
|
187
208
|
def setup_context
|
188
209
|
context.params ||= {}
|
189
210
|
context.headers = {}
|
211
|
+
context.links = {}
|
190
212
|
end
|
191
213
|
|
192
214
|
def handle_halt(interactor)
|
@@ -219,6 +241,18 @@ module Pragma
|
|
219
241
|
return if /\A(2|3)\d{2}\z/ =~ STATUSES.invert[context.status].to_s
|
220
242
|
context.fail!
|
221
243
|
end
|
244
|
+
|
245
|
+
def build_links
|
246
|
+
headers.delete('Link')
|
247
|
+
|
248
|
+
link_header = context.links.each_pair.select do |relation, url|
|
249
|
+
url && !url.empty?
|
250
|
+
end.map do |relation, url|
|
251
|
+
%(<#{url}>; rel="#{relation}")
|
252
|
+
end.join(",\n ")
|
253
|
+
|
254
|
+
headers['Link'] = link_header unless link_header.empty?
|
255
|
+
end
|
222
256
|
end
|
223
257
|
|
224
258
|
Halt = Class.new(StandardError)
|