Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Implement JSON API #230

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

WIP: Implement JSON API #230

wants to merge 12 commits into from

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":"[email protected]","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
@@ -55,39 +54,6 @@ Status of the API could be checked at [http://localhost:5000/docs](http://localh
* `bin/ci` - should be used in the CI or locally
* `bin/server` - to run server locally
Copy link
Contributor

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
Copy link
Contributor

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 }
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add pagination?

Copy link
Contributor

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
Copy link
Contributor

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,52 +1,51 @@
# Skeleton for new Rails 4 application for REST API
# Skeleton for new Rails 5 application for JSON API
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Contributor

@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
Copy link
Contributor

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
Copy link
Contributor

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
3 participants