stitches 3.4.0 → 3.5.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: 92db17e3cd6257c963b095a50458cfd637a259cf
4
- data.tar.gz: 1671aa6e97c74fd316d3e3882062bd82c6a72e4c
3
+ metadata.gz: 62009fed84cc0754e785017cc928284f840b63fd
4
+ data.tar.gz: 4284223ca7d0b02b50de0ec7aed0027a85cd9f20
5
5
  SHA512:
6
- metadata.gz: f6fa15947f707659a8395c34509be4f314265665311f99aa925c43d26d7a40ee78a56eedcb1605b7c9a2dabb3532244c7dabcb1c9afd0161dedceb2cb9bad6ac
7
- data.tar.gz: db499c16dfb16a95bc605b91904918562164d838a6cc3b4c6a644768bb0d78a98f4f5839d61b37db222f048725eb7ef225b3bba1ff380c70c46d98852c9346d0
6
+ metadata.gz: b69a8d5c5bc964c70902d0becb072d69af02ed587e9b593ae972bc5df32baa3d9203aadf425791047527f68a9ced87d4f02b0f02eba51871e46604dbf63969fd
7
+ data.tar.gz: e375f477cf060d106d42ba8a5ff3644e70dd75c515c7840b68c1010e58aaeedcd16ac73089ccf45479abbbc623c6aa64c4b97ddb66247c2234407051b6c8807f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stitches (3.4.0)
4
+ stitches (3.5.0)
5
5
  apitome
6
6
  pg
7
7
  rails
@@ -11,39 +11,39 @@ PATH
11
11
  GEM
12
12
  remote: https://www.rubygems.org/
13
13
  specs:
14
- actioncable (5.1.0)
15
- actionpack (= 5.1.0)
14
+ actioncable (5.1.3)
15
+ actionpack (= 5.1.3)
16
16
  nio4r (~> 2.0)
17
17
  websocket-driver (~> 0.6.1)
18
- actionmailer (5.1.0)
19
- actionpack (= 5.1.0)
20
- actionview (= 5.1.0)
21
- activejob (= 5.1.0)
18
+ actionmailer (5.1.3)
19
+ actionpack (= 5.1.3)
20
+ actionview (= 5.1.3)
21
+ activejob (= 5.1.3)
22
22
  mail (~> 2.5, >= 2.5.4)
23
23
  rails-dom-testing (~> 2.0)
24
- actionpack (5.1.0)
25
- actionview (= 5.1.0)
26
- activesupport (= 5.1.0)
24
+ actionpack (5.1.3)
25
+ actionview (= 5.1.3)
26
+ activesupport (= 5.1.3)
27
27
  rack (~> 2.0)
28
28
  rack-test (~> 0.6.3)
29
29
  rails-dom-testing (~> 2.0)
30
30
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
31
- actionview (5.1.0)
32
- activesupport (= 5.1.0)
31
+ actionview (5.1.3)
32
+ activesupport (= 5.1.3)
33
33
  builder (~> 3.1)
34
34
  erubi (~> 1.4)
35
35
  rails-dom-testing (~> 2.0)
36
36
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
37
- activejob (5.1.0)
38
- activesupport (= 5.1.0)
37
+ activejob (5.1.3)
38
+ activesupport (= 5.1.3)
39
39
  globalid (>= 0.3.6)
40
- activemodel (5.1.0)
41
- activesupport (= 5.1.0)
42
- activerecord (5.1.0)
43
- activemodel (= 5.1.0)
44
- activesupport (= 5.1.0)
40
+ activemodel (5.1.3)
41
+ activesupport (= 5.1.3)
42
+ activerecord (5.1.3)
43
+ activemodel (= 5.1.3)
44
+ activesupport (= 5.1.3)
45
45
  arel (~> 8.0)
46
- activesupport (5.1.0)
46
+ activesupport (5.1.3)
47
47
  concurrent-ruby (~> 1.0, >= 1.0.2)
48
48
  i18n (~> 0.7)
49
49
  minitest (~> 5.1)
@@ -56,49 +56,49 @@ GEM
56
56
  builder (3.2.3)
57
57
  concurrent-ruby (1.0.5)
58
58
  diff-lcs (1.3)
59
- erubi (1.6.0)
59
+ erubi (1.6.1)
60
60
  globalid (0.4.0)
61
61
  activesupport (>= 4.2.0)
62
- i18n (0.8.1)
63
- kramdown (1.13.2)
62
+ i18n (0.8.6)
63
+ kramdown (1.14.0)
64
64
  loofah (2.0.3)
65
65
  nokogiri (>= 1.5.9)
66
- mail (2.6.5)
66
+ mail (2.6.6)
67
67
  mime-types (>= 1.16, < 4)
68
68
  method_source (0.8.2)
69
69
  mime-types (3.1)
70
70
  mime-types-data (~> 3.2015)
71
71
  mime-types-data (3.2016.0521)
72
- mini_portile2 (2.1.0)
73
- minitest (5.10.1)
72
+ mini_portile2 (2.2.0)
73
+ minitest (5.10.3)
74
74
  mustache (1.0.5)
75
- nio4r (2.0.0)
76
- nokogiri (1.7.1)
77
- mini_portile2 (~> 2.1.0)
78
- pg (0.20.0)
79
- rack (2.0.2)
75
+ nio4r (2.1.0)
76
+ nokogiri (1.8.0)
77
+ mini_portile2 (~> 2.2.0)
78
+ pg (0.21.0)
79
+ rack (2.0.3)
80
80
  rack-test (0.6.3)
81
81
  rack (>= 1.0)
82
- rails (5.1.0)
83
- actioncable (= 5.1.0)
84
- actionmailer (= 5.1.0)
85
- actionpack (= 5.1.0)
86
- actionview (= 5.1.0)
87
- activejob (= 5.1.0)
88
- activemodel (= 5.1.0)
89
- activerecord (= 5.1.0)
90
- activesupport (= 5.1.0)
91
- bundler (>= 1.3.0, < 2.0)
92
- railties (= 5.1.0)
82
+ rails (5.1.3)
83
+ actioncable (= 5.1.3)
84
+ actionmailer (= 5.1.3)
85
+ actionpack (= 5.1.3)
86
+ actionview (= 5.1.3)
87
+ activejob (= 5.1.3)
88
+ activemodel (= 5.1.3)
89
+ activerecord (= 5.1.3)
90
+ activesupport (= 5.1.3)
91
+ bundler (>= 1.3.0)
92
+ railties (= 5.1.3)
93
93
  sprockets-rails (>= 2.0.0)
94
- rails-dom-testing (2.0.2)
95
- activesupport (>= 4.2.0, < 6.0)
96
- nokogiri (~> 1.6)
94
+ rails-dom-testing (2.0.3)
95
+ activesupport (>= 4.2.0)
96
+ nokogiri (>= 1.6)
97
97
  rails-html-sanitizer (1.0.3)
98
98
  loofah (~> 2.0)
99
- railties (5.1.0)
100
- actionpack (= 5.1.0)
101
- activesupport (= 5.1.0)
99
+ railties (5.1.3)
100
+ actionpack (= 5.1.3)
101
+ activesupport (= 5.1.3)
102
102
  method_source
103
103
  rake (>= 0.8.7)
104
104
  thor (>= 0.18.1, < 2.0)
@@ -124,7 +124,7 @@ GEM
124
124
  rspec-mocks (~> 3.6.0)
125
125
  rspec-support (~> 3.6.0)
126
126
  rspec-support (3.6.0)
127
- rspec_api_documentation (4.9.0)
127
+ rspec_api_documentation (5.0.0)
128
128
  activesupport (>= 3.0.0)
129
129
  mustache (~> 1.0, >= 0.99.4)
130
130
  rspec (~> 3.0)
@@ -135,7 +135,7 @@ GEM
135
135
  actionpack (>= 4.0)
136
136
  activesupport (>= 4.0)
137
137
  sprockets (>= 3.0.0)
138
- thor (0.19.4)
138
+ thor (0.20.0)
139
139
  thread_safe (0.3.6)
140
140
  tzinfo (1.2.3)
141
141
  thread_safe (~> 0.1)
@@ -151,4 +151,4 @@ DEPENDENCIES
151
151
  stitches!
152
152
 
153
153
  BUNDLED WITH
154
- 1.14.6
154
+ 1.15.3
data/README.md CHANGED
@@ -1,12 +1,16 @@
1
- You'll be in stitches at how easy it is to get your API service up and running!
1
+ Create Microservices in Rails by pretty much just writing regular Rails code.
2
2
 
3
3
  ![build status](https://travis-ci.org/stitchfix/stitches.svg?branch=master)
4
4
 
5
5
  This gem provides:
6
6
 
7
- * Rails plugin to handle api key and versioned requests
8
- * Generator to get you set up and validate your API before you write any code
9
- * Spec helpers to use when building your API
7
+ * transparent API key authentication.
8
+ * router-level API version based on headers.
9
+ * a way to document your microservice endpoints via acceptance tests.
10
+ * structured errors, buildable from invalid Active Records, Exceptions, or by hand.
11
+
12
+ This, plus much of what you get from Rails already, means you can create a microservice Rails application by just writing the
13
+ same Rails code you write today. Instead of rendering web views, you render JSON (which is built into Rails).
10
14
 
11
15
  ## To install
12
16
 
@@ -16,218 +20,80 @@ Add to your `Gemfile`:
16
20
  gem 'stitches'
17
21
  ```
18
22
 
19
- Then of course:
23
+ Then:
20
24
 
21
25
  ```
22
26
  bundle install
23
27
  ```
24
28
 
25
- If your app is brand new or you don't already have rspec or Apitome, be sure to run those generators and set them up first. You can skip this if you've done either of these before:
26
-
27
- ```
28
- rails generate rspec:install
29
- rails generate apitome:install
30
- ```
31
-
32
- Then, run the Stitches generator:
33
-
34
- ```
35
- rails g stitches:api
36
- ```
37
-
38
- Run database migrations (do `rake db:create` first if you haven't yet set up a database)
39
-
40
- ```
41
- rake db:migrate
42
- ```
43
-
44
- ### Upgrading from older verison of Stitches
45
-
46
- If you have used stitches before the `enabled` field was added to `ApiClients`, you need to add that field to your database. You can do this by running
47
- the included generator:
48
-
49
- ```
50
- rails g stitches:add_enabled_to_api_clients
51
- ```
52
-
53
- And then:
54
-
55
- ```
56
- rake db:migrate
57
- ```
58
-
59
- ## Test the install
60
-
61
- In your app run:
62
-
63
- ```
64
- rake generate_api_key[some_name_you_pick]
65
- ```
66
-
67
- Then follow the instructions it outputs.
68
-
69
- If you are doing this locally and get an error like the following:
70
-
71
- > WEBrick::HTTPStatus::LengthRequired
72
-
73
- that's because WEBrick doesn't want an empty body. Throw on a `-d ''` to the end of the command.
74
-
75
- ## Rails Plugin
76
-
77
- Just using this gem will get you:
78
-
79
- * Middleware that requires an api key in the request. See `Stitches::ApiKey`.
80
- * Middleware that requires a versioned JSON mime type. We aren't using version numbers in the URLs but putting versions in the `Accept` header. See `Stitches::ValidMimeType`.
81
- * Monkeypatch ActiveSupport's `TimeWithZone` to use ISO8601 UTC as the encoding for all timestamps. This ensures that every JSON response is using the same timezone and can be parsed properly with JavaScript.
82
- * `Error` and `Errors` objects for creating error reponses that will be rendered properly in API responses. These can work with exceptions, ActiveRecord objects, or whatever you like.
83
-
84
- The plugin works in conjunction with other pieces of this gem set up by using the generator.
85
-
86
- ### A word on errors
87
-
88
- The error format generated by `Errors` and friends is designed for two purposes:
89
-
90
- * provide a "programmer key" upon which logic can be based for each error
91
- * provide a message to explain the error to the programmer and, in times of desperation, the user
92
-
93
- The idea is that the caller should not have made a call that generates an error, although this isn't always 100% possible to avoid. As such, the error messages that come back are not as "rich" as you might get
94
- from ActiveRecord. APIs aren't intended to be used for validating user input. The messages are aimed at a programmer trying to understand why a call failed.
95
-
96
- ## Generator
97
-
98
- When you run the generator via `rails g stitches:api`, you'll get a lot of handy setup done for you:
99
-
100
- * Two "ping" controllers that do nothing but respond to requests. This are useful when creating an API client or when validating
101
- a deployed instance, as they will succeed when all the moving parts are working, but won't actually hit a database or depend on
102
- any particular business logic.
103
- * Routes configured using `Stitches::ApiVersionConstraint` to route to your ping controllers based on the version in
104
- the `Accept` header. This allows your api client to fully validate that it's using the versioning system properly.
105
- * An `ApiClient` model and migration for your database. This additionally sets up UUID support in Postgres.
106
- * An `api_spec.rb` spec that will spin up your application and check that all the RESTful/HTTP stuff is working as designed.
107
- * A means to write API documentation via [rspec_api_documentation](https://github.com/zipmark/rspec_api_documentation), and serve it nicely via [apitome](https://github.com/modeset/apitome). You write tests using a slightly modified DSL that allows you to document the API. The produced documentation shows the headers and wire formats with your test data.
108
-
109
- Once this is done, you can (and possibly should) deploy your app to validate everything's working before you get too into your
110
- business logic.
111
-
112
- Once you start writing your app, there's a few spec helpers available.
113
-
114
- ## Generator-provided tests
115
-
116
- The generator will provide some tests for your app to test a base level of functionality. To use them, add the Capybara gem to your app:
117
-
118
- ```
119
- gem 'capybara'
120
- ```
121
-
122
- And in your `spec_helper.rb`:
29
+ Then, set it up:
123
30
 
124
- ```ruby
125
- require 'capybara/rails'
126
31
  ```
127
-
128
- ## Spec Helpers
129
-
130
- ```ruby
131
- # in your spec_helper.rb
132
- require 'stitches/spec'
32
+ > bin/rails generate rspec:install
33
+ > bin/rails generate apitome:install
34
+ > bin/rails generate stitches:api
35
+ > bundle exec rake db:migrate
133
36
  ```
134
37
 
135
- ### `have_api_error`
136
-
137
- This can be used in a feature spec on a response object to check that the error format is in our "canonical" format, which is as
138
- follows:
139
-
140
- ```json
141
- {
142
- "errors": [
143
- {
144
- "code": "some_code",
145
- "message": "some readable message"
146
- },
147
- {
148
- "code": "some_other_code",
149
- "message": "some other readable message"
150
- }
151
- # etc.
152
- ]
153
- }
154
- ```
38
+ ## Example Microservice Endpoint
155
39
 
156
- To assert this in your specs:
40
+ Suppose we wish to allow our consumers to create Widgets
157
41
 
158
42
  ```ruby
159
- expect(response).to have_api_error(status: 404,
160
- code: "not_found",
161
- message: "the exact error message")
162
-
163
- # regexps also work
164
- expect(response).to have_api_error(status: 404,
165
- code: "name_invalid",
166
- message: /can't be blank/)
167
- ```
168
-
169
- Omitting `status` will use a default of 422, which is Rails' default for validation errors.
170
-
171
- ### `be_iso8601_utc_encoded`
172
-
173
- This can be used to ensure that your JSON-encoded timestamps meet the recommended format of IS8601 UTC-encoded strings.
174
-
175
- ```ruby
176
- expect(json["created_at"]).to be_iso8601_utc_encoded
177
- ```
178
-
179
- ### `TestHeaders`
180
-
181
- This class is useful when creating headers in feature specs that will conform to what's needed by the API you are building.
182
- The generated `api_spec.rb` is a complete example, but here's a sampling:
183
-
184
- ```ruby
185
- # Create headers for a version 2 request
186
- headers = TestHeaders.new(version: 2)
187
- post "/api/ping", {}.to_json, headers.headers
188
-
189
- # Create headers that have the wrong mime type in them
190
- headers = TestHeaders.new(mime_type: "application/foobar")
191
- post "/api/ping", {}.to_json, headers.headers
43
+ class Api::V1::WidgetsController < ApiController
44
+ def create
45
+ widget = Widget.create(widget_params)
46
+ if widget.valid?
47
+ head 201
48
+ else
49
+ render json: {
50
+ errors: Stitches::Errors.from_active_record(widget)
51
+ }, status: 422
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def widget_params
58
+ params.require(:widget).permit(:name, :type, :sub_type)
59
+ end
60
+ end
192
61
  ```
193
62
 
194
- ### `ApiClients` module
63
+ If you think there's nothing special about this—you are correct. This is the vanillaest of vanilla Rails controllers, with a few
64
+ notable exceptions:
195
65
 
196
- Mixing this in provides the method `api_client` that will return the one api client. This is because fixtures have been so flaky
197
- in our tests, and factories don't always work for stuff like this. Also, why require the use of factories?
66
+ * We aren't checking content type. A stitches-based microservice always uses JSON and refuses to route requests for non-JSON to
67
+ you, so there's zero need to use `respond_to` and friends.
68
+ * The error-building is structured and reliable.
69
+ * This is an authenticated request. No request without proper authentication will be routed here, so you don't have to worry
70
+ about it in your code.
71
+ * This is a versioned request. While the URL will *not* contain `v1` in it, the `Accept` header will require a version and get
72
+ routed here. If you make a V2, it's just a new controller and this concern is handled at the routing layer.
198
73
 
199
- ## Configuration
74
+ All this means that the Rails skills of you and your team can be directly applied to building microservices. You don't have to make a bunch of boring decisions about auth, versioning, or content-types. It also means you can start deploying and creating microservices with little friction. No need to deal with a complex DSL or new programming language to get yourselves going with Microservices.
200
75
 
201
- You'll see in the initializer that you can configure aspects of the library globally. `Stitches::Configuration` documents the available
202
- options.
76
+ ## More Info
203
77
 
204
- ## Avoiding auto-magical Set-up
78
+ See [the wiki](https://github.com/stitchfix/stitches/wiki/Setup) for how to setup stitches.
205
79
 
206
- Instead of requiring `stitches`, you can avoid the railtie and configure things yourself:
80
+ * [Stitches Features](https://github.com/stitchfix/stitches/wiki/Features-of-Stitches) include:
81
+ - Authorization via API key
82
+ - Versioned requests via HTTP content types
83
+ - Structured Errors
84
+ - ISO 8601-formatted dates
85
+ * The [Generator](https://github.com/stitchfix/stitches/wiki/Generator) sets up some code in your app, so you can start writing
86
+ APIs using vanilla Rails idioms:
87
+ - a "ping" controller that can vaidate your app is working
88
+ - version routing based on content-type (requests for V2 use the same URL, but are serviced by a different controller)
89
+ - An ApiClient Active Record
90
+ - Acceptance tests that can produce API documentation as they test your app.
91
+ * Stitches provides [testing support](https://github.com/stitchfix/stitches/wiki/Testing)
207
92
 
208
- ```
209
- # Gemfile
210
- gem 'stitches', require: false
211
-
212
- # config/initializers/stitches.rb
213
- require 'stitches_norailtie'
214
-
215
- Stitches.configure do |config|
216
- config.whatever = :foo
217
- end
218
-
219
- # config/application.rb
220
- config.app_middleware.use Stitches::ApiKey, except: %r{/super-secret}
221
- config.app_middleware.use Stitches::ValidMimeType, except: %r{/super-secret}
222
- # or whatever you want to do
223
- ```
224
93
 
225
94
  ## Developing
226
95
 
227
- Although `Stitches.configuration` is global, do not depend directly on that in your logic. Instead, allow all classes to receive a
228
- configuration object in their constructor. This makes the classes easier to deal with and change, without incurring much of a real cost to development.
229
- Global symbols suck, but are convienient. This is how you make the most of it.
230
-
96
+ Although `Stitches.configuration` is global, do not depend directly on that in your logic. Instead, allow all classes to receive a configuration object in their constructor. This makes the classes easier to deal with and change, without incurring much of a real cost to development. Global symbols suck, but are convienient. This is how you make the most of it.
231
97
 
232
98
  ---
233
99
 
@@ -46,7 +46,7 @@ module Stitches
46
46
  # if person.valid?
47
47
  # render json: { person: person }, status: 201
48
48
  # else
49
- # render json: { errors: Stitches::Errors.from_active_record_object(person)
49
+ # render json: { errors: Stitches::Errors.from_active_record_object(person) }, status: 422
50
50
  # end
51
51
  #
52
52
  # This will create one error for each field of the main object. The code will be "field_invalid" and
@@ -98,4 +98,4 @@ module Stitches
98
98
  end
99
99
  end
100
100
  end
101
- end
101
+ end
@@ -1,4 +1,8 @@
1
+ <% if Rails::VERSION::MAJOR >= 5 %>
2
+ class AddEnabledToApiClients < ActiveRecord::Migration[<%= Rails::VERSION::MAJOR %>.<%= Rails::VERSION::MINOR %>]
3
+ <% else %>
1
4
  class AddEnabledToApiClients < ActiveRecord::Migration
5
+ <% end %>
2
6
  def change
3
7
  add_column :api_clients, :enabled, :bool, null: false, default: true
4
8
  remove_index :api_clients, [:name ] # existing one would be unique
@@ -1,4 +1,8 @@
1
+ <% if Rails::VERSION::MAJOR >= 5 %>
2
+ class CreateApiClients < ActiveRecord::Migration[<%= Rails::VERSION::MAJOR %>.<%= Rails::VERSION::MINOR %>]
3
+ <% else %>
1
4
  class CreateApiClients < ActiveRecord::Migration
5
+ <% end %>
2
6
  def change
3
7
  create_table :api_clients do |t|
4
8
  t.string :name, null: false
@@ -1,4 +1,8 @@
1
+ <% if Rails::VERSION::MAJOR >= 5 %>
2
+ class EnableUuidOsspExtension < ActiveRecord::Migration[<%= Rails::VERSION::MAJOR %>.<%= Rails::VERSION::MINOR %>]
3
+ <% else %>
1
4
  class EnableUuidOsspExtension < ActiveRecord::Migration
5
+ <% end %>
2
6
  def change
3
7
  enable_extension 'uuid-ossp'
4
8
  end
@@ -1,3 +1,3 @@
1
1
  module Stitches
2
- VERSION = '3.4.0'
2
+ VERSION = '3.5.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stitches
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stitch Fix Engineering
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-05-09 00:00:00.000000000 Z
14
+ date: 2017-08-24 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails