You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: rails6/en/chapter02-api.adoc
+4-167Lines changed: 4 additions & 167 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -135,9 +135,7 @@ Up to this point we have not made anything crazy. What we want to generate is a
135
135
136
136
NOTE: Setting the API under a subdomain is a good practice because it allows the application to be adapted to a DNS level. But we will simplify things for now in our case.
137
137
138
-
You should be concerned about versioning your application from the beginning as this will give your API a *better structure*. So when changes occur on your API you can thus propose to developers to adapt to the new features while the old ones are depreciated.
139
-
140
-
//thus ?
138
+
You should be concerned about versioning your application from the beginning as this will give your API a *better structure*. So when changes occur on your API you can thus propose to developers to adapt to the new features while the old ones are depreciated.
141
139
142
140
[source,ruby]
143
141
.config/routes.rb
@@ -197,14 +195,14 @@ $ git merge chapter02
197
195
198
196
== Api versioning
199
197
200
-
At this point we should have a nice routes mapping using a subdomain for name spacing the requests. Your _routes.rb_ file should look like this:
198
+
At this point we should have a nice routes mapping using a namespace. Your _routes.rb_ file should look like this:
namespace :api, defaults: { format: :json }, path: '/' do
230
228
scope module: :v1 do
231
229
# We are going to list our resources here
232
230
end
@@ -236,167 +234,6 @@ end
236
234
237
235
By this point the API is now scoped via the URL. For example with the current configuration an end point for retrieving a product would be like: http://localhost:3000/v1/products/1.
238
236
239
-
=== Improving the versioning
240
-
241
-
So far we have the API versioned scoped via the URL, but something doesn’t feel quite right, isn’t it? From my point of view the developer should not be aware of the version using it, by default they should be using the last version of your endpoints, but how do we accomplish this?.
242
-
243
-
Well first of all, we need to improve the API version access through http://en.wikipedia.org/wiki/List_of_HTTP_header_fields[HTTP Headers]. This has two benefits:
244
-
245
-
* Removes the version from the URL
246
-
* The API description is handle through request headers
247
-
248
-
.Most commons HTTP headers fields
249
-
****
250
-
HTTP header fields are components of the message header of requests and responses in the Hypertext Transfer Protocol (HTTP). They define an operating parameters of an HTTP transaction. A common list of used headers is presented below:
251
-
252
-
* *Accept*: Content-Types acceptables for the response. Example: `Accept: text/plain`
* *Content-Type*: The MIME type of the body of the request (used with POST and PUT requests). Example: `Content-Type: application/x-www-form-urlencoded`
255
-
* *Origin*: Initiates a request for cross-origin resource sharing (asks server for an `Access-Control-Allow-Origin' response header). Example: `Origin: http://www.example-social-network.com`
256
-
* *User-Agent*: The user agent string of the user agent. Example: `User-Agent: Mozilla/5.0`
257
-
258
-
It is important you feel comfortable with this ones and understand them.
259
-
260
-
****
261
-
262
-
// In Rails it's very easy to add this type versioning through an _Accept_ header. We will create a class under the `lib` directory of your rails app, and remember we are doing http://en.wikipedia.org/wiki/Test-driven_development[TDD] so first things first.
263
-
264
-
// First we need to add our testing suite, which in our case is going to be http://rspec.info/[Rspe]:
265
-
266
-
// [source,ruby]
267
-
// .Gemfile
268
-
// ----
269
-
// group :test do
270
-
// gem 'rspec-rails', '~> 3.8'
271
-
// gem 'factory_bot_rails', '~> 4.9'
272
-
// gem 'ffaker', '~> 2.10'
273
-
// end
274
-
// ----
275
-
276
-
// Then we run the bundle command to install the gems
277
-
278
-
// [source,bash]
279
-
// ----
280
-
// $ bundle install
281
-
// ----
282
-
283
-
// Finally we install the `rspec` and add some configuration to prevent views and helpers tests from being generated:
284
-
285
-
// [source,bash]
286
-
// ----
287
-
// $ rails generate rspec:install
288
-
// ----
289
-
290
-
// [source,ruby]
291
-
// .config/application.rb
292
-
// ----
293
-
// # ...
294
-
// module MarketPlaceApi
295
-
// class Application < Rails::Application
296
-
// # Initialize configuration defaults for originally generated Rails version.
// Let me walk you through the code. We are initializing the class with an https://ruby-doc.org/core-2.4.0/Hash.html[`Hash`] option. https://ruby-doc.org/core-2.4.0/Hash.html[`Hash`] option will contain the version of the API and a default value for handling the default version. We provide a `matches?` method which the router will trigger for the constraint to see if the default version is required or the `Accept` header matches the given string.
// scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
381
-
// # We are going to list our resources here
382
-
// end
383
-
// end
384
-
// end
385
-
// ----
386
-
387
-
// The configuration above now handles versioning through headers, and for now the version 1 is the default one, so every request will be redirected to that version, no matter if the header with the version is present or not.
388
-
389
-
// Before we say goodbye, let’s run our first tests and make sure everything is nice and green:
// Finished in 0.00294 seconds (files took 0.06292 seconds to load)
397
-
// 2 examples, 0 failures
398
-
// ----
399
-
400
237
== Conclusion
401
238
402
239
It’s been a long way, I know, but you made it, don’t give up this is just our small scaffolding for something big, so keep it up. In the meantime and if you feel curious there are some gems that handle this kind of configuration:
0 commit comments