pragma-operation 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3721ff3095c7adde870e9d879340f12d1aed3a90
4
- data.tar.gz: 5a10bdd0eaeb67e0a3457fc2881eaef1b01eedcc
3
+ metadata.gz: 4af59fe5624f0ad6a25a16d2f3a34e6b4b24f7cc
4
+ data.tar.gz: 385279725b2ebbc9210535c274de95060025a4cd
5
5
  SHA512:
6
- metadata.gz: dfc63fb63cebc9737babfcdf3ee1bb831911c44460407432d23d3d173fb2f58743bd8cd6f15cf469c1d6b4c746c218a5cdf6e9a14205f1888f5582a01029c87f
7
- data.tar.gz: 42b1fca36ece4067a9e31674edacdbf3b0c99560c4088961c990ef82e81f860bfe9f91f7087d47e3edc435dd7b0e5fee8bd6ab3540c284ce8cc002af6671f83a
6
+ metadata.gz: 11d83a8c30d72bca7e25e86239d6170f6687bdc5113e0a0775feabc979ca9e8e743dbd30af3dc68607a37eb7eaaeb586302b33e641d48ad8359700e23fa614aa
7
+ data.tar.gz: 3900e69be07c8310c89955a858d100bef14132d47e87cddcd1eab83dc6e70176d152c4a05a568dbf3ccdb178f93b60c2045cddb4956d7ddc526aa93e2d99ed29
@@ -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
- def respond_with(status: nil, headers: {}, resource: nil)
127
- context.status = status
128
- context.headers = headers.to_h
129
- context.resource = resource
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 *args
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)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Pragma
3
3
  module Operation
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pragma-operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Desantis