woowahan-api-demo
-> https://github.com/ahastudio/woowahan-api-demo
$ git remote add origin [email protected]:ahastudio/woowahan-api-demo.git
$ git push -u origin master
그냥 GitHub 계정으로 가입하고 프로젝트 추가하면 됩니다.
https://www.codacy.com/app/ahastudio/woowahan-api-demo
http://www.extremeprogramming.org/rules/standards.html
https://github.com/dalzony/ruby-style-guide/blob/master/README-koKR.md
https://github.com/bbatsov/rubocop
$ gem install rubocop --no-document
$ rubocop
엄청난 고통!
https://github.com/bbatsov/rubocop/blob/master/config/default.yml
https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
$ vi .rubocop.yml
Documentation:
Enabled: false
AllCops:
Exclude:
- 'Gemfile'
- 'Rakefile'
- 'Guardfile'
- 'config.ru'
- 'bin/**/*'
- 'db/**/*'
- 'config/**/*'
$ rubocop | grep "Line is too long"
$ vi app/channels/application_cable/channel.rb
$ vi app/channels/application_cable/connection.rb
$ vi test/controllers/posts_controller_test.rb
$ vi test/test_helper.rb
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
app/controllers/posts_controller.rb
는 고쳐도 새로운 에러가 발생한다. 잠시 후에 개선하기로 하고 일단 다음으로 넘어간다.
"Method has too many lines" check not smart enough
$ rubocop | grep "Prefer single-quoted strings when you don't need string interpolation or special symbols"
$ vi test/controllers/posts_controller_test.rb
Vim에서 정규표현식을 이용해 문자열 바꾸기.
:%s/"/'/g
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
$ rubocop | grep "Keep a blank line before and after private"
$ vi app/controllers/posts_controller.rb
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
$ rubocop | grep "Inconsistent indentation detected"
$ vi app/controllers/posts_controller.rb
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
$ rubocop | grep "Use nested module/class definitions instead of compact style"
$ vi test/test_helper.rb
module ActiveSupport
class TestCase
# (중략)
end
end
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
https://github.com/plataformatec/responders
$ vi Gemfile
G -> 파일 끝으로 이동 o -> 다음 줄에 추가
gem 'responders', '~> 2.0'
$ bundle
$ bin/rails generate responders:install
자동으로 추가된 코드 수정.
$ vi app/controllers/application_controller.rb
:%s/"/'/g
$ vi app/controllers/posts_controller.rb
respond_to
추가.
class PostsController < ApplicationController
respond_to :html, :json
respond_with
로 변경.
# POST /posts
# POST /posts.json
def create
@post = Post.new(post_params)
@post.save
respond_with(@post)
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@post.update(post_params)
respond_with(@post)
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
@post.destroy
respond_with(@post)
end
혹시라도 문제가 생겼는지 확인.
$ bin/rake test
모두 통과하는지 확인.
$ rubocop
작업이 한 단계 끝났다면? Commit을 잊지 마세요.
$ git add .
$ git commit
https://github.com/ahastudio/woowahan-api-demo -> http://refactorcop.com/ahastudio/woowahan-api-demo
어떻게 해야 Validation이 올바르게 됐다고 할 수 있을까?
- 제목과 내용을 모두 넣는다 -> Save 성공
- 제목을 빼먹고 내용만 넣는다 -> Save 실패
- 제목만 넣고 내용을 빼먹는다 -> Save 실패
$ vi test/models/post_test.rb
require 'test_helper'
class PostTest < ActiveSupport::TestCase
test 'create a new post' do
post = Post.new
post.title = '조은 글이다'
post.body = '냉무'
assert post.save
end
test 'cannot create a new post without title' do
post = Post.new
post.body = '냉무'
assert_not post.save
end
test 'cannot create a new post without body' do
post = Post.new
post.title = '조은 글이다'
assert_not post.save
end
end
$ bin/rake test
다른 방법이 있을까?
공부할 때나, 작업할 때 항상 스스로에게 물어야 할 질문: “더 나은 다른 방법은 없을까요?”
- 제목과 내용을 모두 넣는다 -> Post 갯수 증가
- 제목을 빼먹고 내용만 넣는다 -> Post 갯수 변화 없음
- 제목만 넣고 내용을 빼먹는다 -> Post 갯수 변화 없음
- [새로운 조건] 제목과 내용 모두 빼먹는다 -> Post 갯수 변화 없음
$ vi test/models/post_test.rb
require 'test_helper'
class PostTest < ActiveSupport::TestCase
test 'create a new post with valid attributes' do
assert_difference -> { Post.count }, 1 do
Post.create(title: '조은 글이다', body: '냉무')
end
end
test 'cannot create a new post without title' do
assert_no_difference -> { Post.count } do
Post.create(title: '', body: '냉무')
end
end
test 'cannot create a new post without body' do
assert_no_difference -> { Post.count } do
Post.create(title: '조은 글이다', body: '')
end
end
test 'cannot create a new post without title and body' do
assert_no_difference -> { Post.count } do
Post.create(title: '', body: '')
end
end
end
$ bin/rake test
어떤 게 낫다고 할 수 없다. 다만, 어떻게 확신을 얻으려고 했는지 나와 남에게 설명할 수 있어야 한다.
$ rubocop
$ git add .
$ git commit
$ git checkout -b feature/post-api
$ git branch
브랜치 전환
$ git checkout master
$ git branch
$ git checkout feature/post-api
$ git branch
무엇을 만들 것인가?
GET /posts.json
-> 게시물 목록 얻기GET /posts/37.json
-> 게시물 상세 보기
Controller 코드 생성.
$ bin/rails generate controller api/posts --no-helper --no-assets
GET /api/posts.json
어떻게 확인할 것인가?
- HTTP 상태 코드는 200 = success 이다.
- JSON에 제목이 포함된다.
- JSON에 내용이 포함되지 않는다.
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
end
end
end
테스트 실행
$ bin/rake test
$ vi config/routes.rb
namespace :api do
resources :posts, only: :index
end
테스트 실행
$ bin/rake test
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
def index
end
end
end
테스트 실행
$ bin/rake test
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
Post.create!(title: '제목', body: '조...조은 글이다')
end
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
end
end
end
테스트 실행
$ bin/rake test
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
def index
render json: { title: '제목' }
end
end
end
테스트 실행
$ bin/rake test
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
respond_with(@posts)
end
end
end
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
Post.create!(title: '제목', body: '조...조은 글이다')
end
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_not_includes response.body, '조은 글이다'
end
end
end
테스트 실행
$ bin/rake test
https://github.com/rails/jbuilder
기본으로 사용 중이다.
$ mkdir -p app/views/api/posts/
$ vi app/views/api/posts/index.json.jbuilder
json.array! @posts do |post|
json.id post.id
json.title post.title
end
테스트 실행
$ bin/rake test
$ curl http://api-demo.dev/api/posts.json
HTTPie를 쓰면 더 보기 좋다.
$ brew install httpie
$ http GET api-demo.dev/api/posts.json
$ rubocop
$ git add .
$ git commit
GET /api/posts/<ID>.json
어떻게 확인할 것인가?
- 올바른 ID를 받으면, HTTP 상태 코드는 200 = success 이다.
- JSON에 제목과 내용이 포함된다.
- 알 수 없는 ID를 받으면, HTTP 상태 코드는 404 = not found 다.
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
@post = Post.create!(title: '제목', body: '조...조은 글이다')
end
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_not_includes response.body, '조은 글이다'
end
test 'GET #show' do
get api_post_url(@post.id), params: { format: :json }
assert_response :success
end
end
end
테스트 실행
$ bin/rake test
$ vi config/routes.rb
namespace :api do
resources :posts, only: [:index, :show]
end
테스트 실행
$ bin/rake test
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
respond_with(@posts)
end
def show
respond_with(@post)
end
end
end
테스트 실행
$ bin/rake test
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
@post = Post.create!(title: '제목', body: '조...조은 글이다')
end
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_not_includes response.body, '조은 글이다'
end
test 'GET #show' do
get api_post_url(@post.id), params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_includes response.body, '조은 글이다'
end
end
end
테스트 실행
$ bin/rake test
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
respond_with(@posts)
end
def show
@post = Post.find(params[:id])
respond_with(@post)
end
end
end
테스트 실행
$ bin/rake test
$ vi app/views/api/posts/show.json.jbuilder
json.id @post.id
json.title @post.title
json.body @post.body
json.created_at @post.created_at
테스트 실행
$ bin/rake test
$ vi test/controllers/api/posts_controller_test.rb
require 'test_helper'
module Api
class PostsControllerTest < ActionDispatch::IntegrationTest
setup do
@post = Post.create!(title: '제목', body: '조...조은 글이다')
end
test 'GET #index' do
get api_posts_url, params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_not_includes response.body, '조은 글이다'
end
test 'GET #show (200)' do
get api_post_url(@post.id), params: { format: :json }
assert_response :success
assert_includes response.body, '제목'
assert_includes response.body, '조은 글이다'
end
test 'GET #show (404)' do
get api_post_url('NOT-FOUND'), params: { format: :json }
assert_response :not_found
end
end
end
테스트 실행
$ bin/rake test
ActiveRecord::RecordNotFound
예외를 rescue_from
으로 처리.
$ vi app/controllers/api/posts_controller.rb
module Api
class PostsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :not_found
respond_to :json
def index
@posts = Post.all
respond_with(@posts)
end
def show
@post = Post.find(params[:id])
respond_with(@post)
end
private
def not_found
head status: :not_found
end
end
end
테스트 실행
$ bin/rake test
$ http GET api-demo.dev/api/posts/1.json
$ http GET api-demo.dev/api/posts/NOT-FOUND.json
$ rubocop
$ git add .
$ git commit
작업 중인 브랜치를 origin으로 Push.
$ git push origin feature/post-api
GitHub 저장소에 가서 “Compare & pull request” 버튼 클릭.
https://github.com/ahastudio/woowahan-api-demo/compare/feature/post-api?expand=1 -> ahastudio/woowahan-api-demo#2