Skip to content

Conversation

@timurvafin
Copy link
Member

@timurvafin timurvafin commented Sep 12, 2018

Implement JSON API

Token request:

curl "https://fs-rails-base-api-pr-230.herokuapp.com/v1/tokens" -d '{"data":{"type":"token_requests","attributes":{"email":"user@example.com","password":"123456"}}}' -X POST \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json"

Users requests (specify token from Tokens request):

curl -g "https://fs-rails-base-api-pr-230.herokuapp.com/v1/users" -X GET \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "Authorization: Bearer TOKEN"  

Closes #208

* Update Ruby to 2.5.1
* Replace factory_girl -> factory_bot
* Add JWT
* Generate markdown API docs only
* Errors refactor
* Update README and remove unused gems
@timurvafin timurvafin temporarily deployed to fs-rails-base-api-pr-230 September 12, 2018 12:17 Inactive
@timurvafin timurvafin temporarily deployed to fs-rails-base-api-pr-230 September 12, 2018 12:25 Inactive
* `bin/setup` - setup required gems and migrate db if needed
* `bin/quality` - runs rubocop, brakeman, rails_best_practices and bundle-audit for the app
* `bin/ci` - should be used in the CI or locally
* `bin/server` - to run server locally

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add bin/doc script description here?

Also we can remove bin/foreman.

* [knock](https://github.com/nsarno/knock) – seamless JWT authentication
* [puma](https://github.com/puma/puma) as Rails web server
* [rack-cors](https://github.com/cyu/rack-cors) for [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
* [responders](https://github.com/plataformatec/responders) - DRY controllers

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not use them as I see. Is it planned for future using in admin panel for example?

module V1
class UsersController < V1::BaseController
expose :user
expose :users, -> { User.all }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add pagination?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can consider https://github.com/davidcelis/api-pagination gem to mimic pagination like User.page(params[:page][:number]).per(params[:page][:size]) in controller as I think.

config.log_level = :info
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use :info log level in production env to reduce logs size? If not then we can comment or remove this line (it is default).

@@ -1,93 +1,59 @@
# Skeleton for new Rails 4 application for REST API
# Skeleton for new Rails 5 application for JSON API

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update doc/README_TEMPLATE.md accordingly?

context "with invalid password" do
let(:password) { "invalid" }

example "Create Token with invalid password" do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here...

context "with invalid id" do
let(:id) { 0 }

example "Retrive User with invalid id" do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here...

@@ -0,0 +1,12 @@
# rubocop:disable RSpec/EmptyExampleGroup
shared_examples "API endpoint with authorization" do
context "without authorization headers", document: false do
Copy link

@ArthurZaharov ArthurZaharov Sep 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

document: false does not work on context as I know. It should be written like:

context "..." do
  example "...", document: false do
    do_request
    ...
  end
end

it "fails" do
interactor.run
expect(context).to be_failure
expect(context.message).to eql(params[:message]) if params

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our interactor returns code on failure. Should we check it here?

@@ -0,0 +1,6 @@
shared_examples "success interactor" do
it "success" do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it "succeeds"

skip_before_action :authenticate_user!

def create
result = CreateJwt.call(authentication_params)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we really introduce custom logic for generating a token? It is already provided by a gem. Also creating a separate JwtToken model not necessary. Looks like you are doing it only to response in JSON API format, but maybe we can return token here in JSON API manually?

class V1::TokensController < Knock::AuthTokenController
  skip_before_action :verify_authenticity_token, only: :create

  def create
    render json: response_data, status: :created
  end

  private

  def response_data
    { data: { id: auth_token.token, type: "tokens" } }
  end

  def entity_class
    User
  end

  def auth_params
    jsonapi_params(only: %i[email password])
  end
end

In this case, we can remove JwtToken model, CreateJwt interactor and JwtTokenSerializer. Any thoughts?

devise :database_authenticatable, :registerable,
:recoverable, :trackable, :validatable
validates :email, presence: true
validates :password, length: { minimum: 6 }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To update a user's attribute he always needs to pass a password. Was it intended? Looks like if you need to update a full_name for example, you don't need to provide a password.

validates :password, length: { minimum: 6 }, if: -> { new_record? || password_digest_changed? }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Apply JSONAPI

4 participants