残りの API を実装しよう - satococoa/api-tutorial GitHub Wiki

引き続き、API を実装していきます。 spec -> 実装の順で開発します。

spec を書く上では、次のページを参考にするとスムーズにいけると思います。

新規投稿機能

spec

こんな感じの spec を追加

  describe "POST /api/v1/posts" do
    let(:params) {
      {post: post_param, format: :json}
    }

    context "正しいパラメータが送られたとき" do
      let(:post_param) { FactoryGirl.attributes_for(:post) }

      it "201 が返る" do
        post api_v1_posts_path, params
        expect(response.status).to eq(201)
      end

      it "1 つ投稿が増える" do
        expect { post api_v1_posts_path, params }.to change { Post.count }.by(1)
      end
    end

    context "不正なパラメータが送られたとき" do
      let(:post_param) { FactoryGirl.attributes_for(:post, title: 'a') }

      it "422 が返る" do
        post api_v1_posts_path, params
        expect(response.status).to eq(422)
      end

      it "投稿は増えない" do
        expect { post api_v1_posts_path, params }.not_to change { Post.count }
      end

      it "エラーメッセージがbodyに含まれる" do
        post api_v1_posts_path, params
        expect(response.body).not_to be_empty
      end
    end
  end

実装コード

  def create
    @post = Post.new(post_params)
    if @post.save
      render json: 'ok', status: :created
    else
      render json: @post.errors.full_messages, status: :unprocessable_entity
    end
  end

  private
    def post_params
      params.require(:post).permit(:title, :name, :body)
    end

respond_to, respond_with などを使って書くこともできますが、上記の書き方が何をしているのかわかりやすいので良いかと思います。

実際に json のリクエストを試してみるときは、Dev HTTP Client という chrome の拡張が便利です。

投稿の更新機能

spec

  describe "PATCH /api/v1/posts/:id" do
    let(:params) {
      {post: post_param, format: :json}
    }
    let(:post) { FactoryGirl.create(:post) }

    context "正しいパラメータが送られたとき" do
      let(:post_param) { FactoryGirl.attributes_for(:post) }

      it "201 が返る" do
        patch api_v1_post_path(post), params
        expect(response.status).to eq(201)
      end

      it "投稿が更新される" do
        patch api_v1_post_path(post), params
        expect(Post.find(post.id).title).to eq(post_param[:title])
      end
    end

    context "不正なパラメータが送られたとき" do
      let(:post_param) { FactoryGirl.attributes_for(:post, title: 'a') }

      it "422 が返る" do
        patch api_v1_post_path(post), params
        expect(response.status).to eq(422)
      end

      it "投稿が更新されない" do
        patch api_v1_post_path(post), params
        expect(Post.find(post.id).title).to eq(post.title)
      end

      it "エラーメッセージがbodyに含まれる" do
        patch api_v1_post_path(post), params
        expect(response.body).not_to be_empty
      end
    end
  end

実装コード

  def update
    @post = Post.find(params[:id])
    if @post.update(post_params)
      render json: 'ok', status: :created
    else
      render json: @post.errors.full_messages, status: :unprocessable_entity
    end
  end

投稿の削除機能

spec

  describe "DELETE /api/v1/posts/:id" do
    let!(:post) { FactoryGirl.create(:post) }

    it "200 が返る" do
      delete api_v1_post_path(post)
      expect(response.status).to eq(200)
    end

    it "1 つ投稿が減る" do
      expect { delete api_v1_post_path(post) }.to change { Post.count }.by(-1)
    end
  end

実装コード

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    render json: 'ok', status: :ok
  end