madeindjs / api_on_rails Goto Github PK
View Code? Open in Web Editor NEWLearn best practices to build an API using Ruby on Rails 5/6
Home Page: https://leanpub.com/apionrails6
License: MIT License
Learn best practices to build an API using Ruby on Rails 5/6
Home Page: https://leanpub.com/apionrails6
License: MIT License
Hi!
Where's the source code mentioned in the book?
Regards.
Hi madeindjs
Thanks for looking at this book there are very little covering Rails APIs. I couldn't work out this bit on Chapter 2:
Api versioning
At this point we should have a nice routes mapping using a namespace. Your routes.rb file should look like this:
Listing 5. config/routes.rb
Rails.application.routes.draw do # Api definition namespace :api, defaults: { format: :json }, path: '/' do <=== ? # We are going to list our resources here end end
The only problem is that the path: '/'
has just appeared after the final commit and it's not clear where it came from as it was not in any of the previous listings.
Running rails g devise:install
gives this error
/home/tac/.rvm/gems/ruby-2.6.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:74:in 'block in load_missing_constant': uninitialized constant ApiConstraints (NameError)
Also the git clone link given at the start of chapter 3 does not seem to be valid.
Hi, i understand you using prax/pow but if i dont want to use them and instead try out the api on postman/browser using localhost:3000 , then what would be the URI/URL for that ? Thanks in advance.
Hi, first of all thanks for working on updating this tutorial.
I have been trying to follow the rails 6 version and on chapter 3, when testing via the api for the first time via curl, I noticed 2 issues:
/api/v1/users/1
while it should be /users/1
curl http://api.localhost:3000/users/1
is invalid (unless you define api.localhost on your hosts file)What I would suggest to be able to use the subdomain constraint on local development is:
config.hosts << "api.lvh.me"
somewhere in your development.rb
environment file.curl http://api.lvh.me:3000/users/1
Logged user
So we implemented the following logic: API returns the authentication token to the client if credentials are correct.
We will now implement the following logic: we’ll find the corresponding user of an authentication token given into the HTTP header. We’ll need to do so each time this client requests a protected page.
My question is: Do you mean "protected page"? Protected pages make sense in a standard Rails application but I'm confused about how an API app has pages. I was wondering if it might be better described as:
We’ll need to do so each time a client request requires permission.
Otherwise authorization?
The fix in the code is incorrect it should be include_s_ and not include. I can't do a PR because I'm not sure how you want to fix it.
The wrong code is first introduced in Prevention of N + 1 requests. Listing 152. app/controllers/api/v1/products_controller.rb
ApplicationController
# ...
def index
@products = Product.includes(:user)
.page(current_page)
.per(per_page)
.search(params)
options = get_links_serializer_options('api_v1_products_path', @products)
# needs an s \/
options[:include] = [:user]
render json: ProductSerializer.new(@products, options).serializable_hash.to_json
end
# ...
end
The book code demonstrates that with the change in Listing 152 there is still an N+1 error in products.
GET /api/v1/products
USE eager loading detected
Product => [:user]
Add to your finder: :includes => [:user]
He even tells us how to correct it:
> Add to your search engine
includes ⇒ [: user]
Then there's a final listing 154 that copies the Listing 152, along with the mistake.
I can't see a way of changing just the code. I think some writing must be changed as well.
Under: Chapter 3: Build users Listing 11
The book shows UsersControllerTest
with no namespace nesting:
Listing 11. test/controllers/api/v1/users_controller_test.rb
# v------------- THIS BIT
class UsersControllerTest < ActionDispatch::IntegrationTest
...
... None generated code. Entered by you.
...
end
When I do the generation rails g controller api::v1::users
- I get additional namespace of Api::V1
generated:
require 'test_helper'
V----------- THIS BIT
class Api::V1::UsersControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
However, I did get the same namespace as Listing 12 for the users_controller.rb.
# app/controllers/api/v1/users_controllers.rb
class Api::V1::UsersController < ApplicationController
end
Note: If you make a change then Listing 11 then Listing 14 will need to be changed also.
In the test/models/user_test.rb file, I think
test 'user with a valid email should be valid' do user = User.new(email: '[email protected]', **password_digest**: 'test') assert user.valid? end
should rather be :
test 'user with a valid email should be valid' do user = User.new(email: '[email protected]', **password**: 'test') assert user.valid? end
In my case it caused a failure during a rake test
.
The link on 'here'
I’m not covering those in this book, since we are trying to learn how to actually implement this kind of functionality, but it is good to know though. By the way the code up to this point is here.
I believe this is the link: madeindjs/market_place_api@1248737
Confusing as it's rspec configuration when this book is covering minitest.
I'm not sure how important the move from 1.5 to 2.0 so I haven't put a pull request in. Before you can run the rake build the user has to fix this issue.
# Gemfile
gem 'asciidoctor', '~> 1.5'
# Gemfile.lock
asciidoctor (2.0.10)
There are no chapter headings in the book. It makes it difficult to find where you are in the book.
I'm using EPUB but checking PDF it looks missing as well..
There is a broken link : "Schema of links betweens models".
I'm going through the book again... :-}
In listing 88 you're testing for a sort order but in listing 89 it's a WHERE clause without any ordering. SQL makes no guarantees in this situation, if it passes that's luck. You need some ordering or remove the test.
Listing 88. test/models/product_test.rb
class ProductTest < ActiveSupport::TestCase
# ...
test 'should filter products by name and sort them' do
assert_equal [products(:another_tv), products(:one)], Product.filter_by_title('tv').sort
end
end
Listing 89. app/models/product.rb
class Product < ApplicationRecord
# ...
scope :filter_by_title, lambda { |keyword|
where('lower(title) LIKE ?', "%#{keyword.downcase}%")
}
end
The fast_jsonapi gem is no longer maintained by Netflix, as stated on the GitHub repo. Consider updating the content to reflect the jsonapi-serializer gem which is a community maintained fork.
Title explains.
Chapter 4 autoload
Listing 5. lib/json_web_token.rb
# ...
module MarketPlaceApi
class Application < Rails::Application
# ...
config.autoload_paths << Rails.root.join('lib')
end
end
I notice you're using autoload. I find the area confusing. My understanding is autoloading lib was not threadsafe which is a problem with Puma in production and the suggestion was you should stick lib into app :-| I couldn't bring myself to do that and went with the other suggestion of changing autoload to eager load, which autoloads in development and eager loads, no requests until code loaded, in production.
test 'should sort product by most recent' do
# we will touch some products to update them
products(:two).touch
products(:one)
I implemented the test code and code on model but test fails becuase doesn't return products in expected order, also anyone can explain me what does those two last lines? I understand that the first line updates the datetime on "updated_at" atrribute, but second line, what does?
Hi Alex,
On the page 58 of the PDF, when running tests, you mentioned 19 assertions as per screenshot below.
But in my case, the number is 18.
https://github.com/tenzan/cms-rails-api/tree/3459ebbf5a8a8bf9c02e32e30e773cadd39696aa
Regards,
Askar
rake build:all[6,en] => zsh: no matches found: build:all[6,en]
rake "build:all[6,en]" => Book compiled
One of the confusing things in Chapter 2 is the block inside the namespace :api
Listing 4. config/routes.rb
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
namespace :v1 do <= This guy
# We are going to list our resources here
end
end
end
You then commit as "Set the routes constraints for the api". So far no problem. Then we see.
Listing 5. config/routes.rb
Rails.application.routes.draw do
# Api definition
namespace :api, defaults: { format: :json } do
# We are going to list our resources here <= where's it gone?
end
end
This is a bit confusing as the version namespace :v1
has disappeared. Maybe it's because it wasn't interesting? Maybe because it's a mistake? However, In Listing 6 we have namespace changed to scope.
Listing 6. config/routes.rb
Rails.application.routes.draw do
# Api definition
namespace :api, defaults: { format: :json } do
scope module: :v1 do <= so we changed namespace to scope?
# We are going to list our resources here
end
end
end
Is the progression from Listing 4 (adding an inner namespace), Listing 5 (missing it out again) and Listing 6 (inner scope module) deliberate? It's quite confusing to follow and not clear from the text why these changes happened.
Hi Alex,
In your PDF book, regarding test/controllers/concerns/authenticable_test.rb
on page 56 it is
@authentication = MockController.new
but on page 57, it is
@authentication = Authentication.new
Which one is correct?
Regards,
Askar
When I run "rake build:pdf[6,en]" for generate the pdf version. I get:
asciidoctor: WARNING: image to embed not found or not readable: .../api_on_rails/rails6/en/img/img/data_model.png
This happened after merge the pull request #24
Rails 5.2 replaced secrets with credentials. Chapter 4 still uses secrets which is not best practice anymore.
A few lines have command controller
, it should be order controller
, and
particular command
-> particular order
something like that
Check this part
it should be
def user_params
params.require(:user).permit(:email, :password, :password_digest)
end
otherwise it gets
Unpermitted parameter: :password_digest
Chapter 3
Build users
It's time to make our first entry point. We will just start building the
show
action for the user who will display a user in JSON. We will first
Not sure what you mean:
user who will display a user in JSON.
In Chapter 6 - section Serialize Products. We use a generator like so:
rails generate serializer Product title price published
This automatically adds the attributes. However, in the text you are encouraged to add the, already created, attributes. As follows:
$ rails generate serializer Product title price published
create app/serializers/product_serializer.rb
Now let’s add attributes to serialize the product:
Now check the generated product serializer:
Listing 75. app/serializers/product_serializer.rb
class ProductSerializer
include JSONAPI::Serializer
attributes :title, :price, :published
end
There you go. It’s no more complicated than that. Everything looks right. Let’s change our controller a little bit.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.