API: Return 409 when trying to create something existing and 410 when trying to delete something already gone
Probably missed a few more cases where we always return sucess when the user requests status quo, but this should cover most ground
This commit is contained in:
parent
e8b9a70fbf
commit
04744b4dac
11 changed files with 60 additions and 27 deletions
|
|
@ -36,7 +36,7 @@ module Api
|
||||||
like_service.create(params[:post_id])
|
like_service.create(params[:post_id])
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
if e.message == "Validation failed: Target has already been taken"
|
if e.message == "Validation failed: Target has already been taken"
|
||||||
return render_error 422, I18n.t("api.endpoint_errors.likes.like_exists")
|
return render_error 409, I18n.t("api.endpoint_errors.likes.like_exists")
|
||||||
end
|
end
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
@ -52,7 +52,7 @@ module Api
|
||||||
if success
|
if success
|
||||||
head :no_content
|
head :no_content
|
||||||
else
|
else
|
||||||
render_error 404, I18n.t("api.endpoint_errors.likes.no_like")
|
render_error 410, I18n.t("api.endpoint_errors.likes.no_like")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ module Api
|
||||||
|
|
||||||
def subscribe
|
def subscribe
|
||||||
post = find_post
|
post = find_post
|
||||||
|
return head :conflict if current_user.participations.find_by(target_id: post.id)
|
||||||
|
|
||||||
current_user.participate!(post)
|
current_user.participate!(post)
|
||||||
head :no_content
|
head :no_content
|
||||||
rescue ActiveRecord::RecordInvalid
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
|
@ -29,7 +31,9 @@ module Api
|
||||||
|
|
||||||
def mute
|
def mute
|
||||||
post = find_post
|
post = find_post
|
||||||
participation = current_user.participations.find_by!(target_id: post.id)
|
participation = current_user.participations.find_by(target_id: post.id)
|
||||||
|
return head :gone unless participation
|
||||||
|
|
||||||
participation.destroy
|
participation.destroy
|
||||||
head :no_content
|
head :no_content
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,9 @@ module Api
|
||||||
|
|
||||||
def create
|
def create
|
||||||
reshare = reshare_service.create(params.require(:post_id))
|
reshare = reshare_service.create(params.require(:post_id))
|
||||||
rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid, RuntimeError
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
render_error 409, I18n.t("reshares.create.error")
|
||||||
|
rescue ActiveRecord::RecordNotFound, RuntimeError
|
||||||
render_error 422, I18n.t("reshares.create.error")
|
render_error 422, I18n.t("reshares.create.error")
|
||||||
else
|
else
|
||||||
render json: PostPresenter.new(reshare, current_user).as_api_response
|
render json: PostPresenter.new(reshare, current_user).as_api_response
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ module Api
|
||||||
def create
|
def create
|
||||||
tag_followings_service.create(params.require(:name))
|
tag_followings_service.create(params.require(:name))
|
||||||
head :no_content
|
head :no_content
|
||||||
|
rescue TagFollowingService::DuplicateTag
|
||||||
|
render_error 409, I18n.t("api.endpoint_errors.tags.cant_process")
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
render_error 422, I18n.t("api.endpoint_errors.tags.cant_process")
|
render_error 422, I18n.t("api.endpoint_errors.tags.cant_process")
|
||||||
end
|
end
|
||||||
|
|
@ -25,6 +27,8 @@ module Api
|
||||||
def destroy
|
def destroy
|
||||||
tag_followings_service.destroy_by_name(params.require(:id))
|
tag_followings_service.destroy_by_name(params.require(:id))
|
||||||
head :no_content
|
head :no_content
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_error 410, I18n.t("api.endpoint_errors.tags.cant_process")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ class TagFollowingsController < ApplicationController
|
||||||
def create
|
def create
|
||||||
tag = tag_followings_service.create(params["name"])
|
tag = tag_followings_service.create(params["name"])
|
||||||
render json: tag.to_json, status: :created
|
render json: tag.to_json, status: :created
|
||||||
|
rescue TagFollowingService::DuplicateTag
|
||||||
|
render json: tag_followings_service.find(params["name"]), status: created
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
head :forbidden
|
head :forbidden
|
||||||
end
|
end
|
||||||
|
|
@ -23,18 +25,16 @@ class TagFollowingsController < ApplicationController
|
||||||
# DELETE /tag_followings/1
|
# DELETE /tag_followings/1
|
||||||
# DELETE /tag_followings/1.xml
|
# DELETE /tag_followings/1.xml
|
||||||
def destroy
|
def destroy
|
||||||
success = tag_followings_service.destroy(params["id"])
|
tag_followings_service.destroy(params["id"])
|
||||||
|
|
||||||
if success
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.any(:js, :json) { head :no_content }
|
format.any(:js, :json) { head :no_content }
|
||||||
end
|
end
|
||||||
else
|
rescue ActiveRecord::RecordNotFound
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.any(:js, :json) { head :forbidden }
|
format.any(:js, :json) { head :forbidden }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
|
||||||
|
|
@ -10,24 +10,33 @@ class TagFollowingService
|
||||||
raise ArgumentError, "Name field null or empty" if name_normalized.blank?
|
raise ArgumentError, "Name field null or empty" if name_normalized.blank?
|
||||||
|
|
||||||
tag = ActsAsTaggableOn::Tag.find_or_create_by(name: name_normalized)
|
tag = ActsAsTaggableOn::Tag.find_or_create_by(name: name_normalized)
|
||||||
|
raise DuplicateTag if @user.tag_followings.exists?(tag_id: tag.id)
|
||||||
|
|
||||||
tag_following = @user.tag_followings.new(tag_id: tag.id)
|
tag_following = @user.tag_followings.new(tag_id: tag.id)
|
||||||
raise "Can't process tag entity" unless tag_following.save
|
raise "Can't process tag entity" unless tag_following.save
|
||||||
|
|
||||||
tag
|
tag
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find(name)
|
||||||
|
name_normalized = ActsAsTaggableOn::Tag.normalize(name)
|
||||||
|
ActsAsTaggableOn::Tag.find_or_create_by(name: name_normalized)
|
||||||
|
end
|
||||||
|
|
||||||
def destroy(id)
|
def destroy(id)
|
||||||
tag_following = @user.tag_followings.find_by(tag_id: id)
|
tag_following = @user.tag_followings.find_by!(tag_id: id)
|
||||||
tag_following&.destroy
|
tag_following.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_by_name(name)
|
def destroy_by_name(name)
|
||||||
name_normalized = ActsAsTaggableOn::Tag.normalize(name)
|
name_normalized = ActsAsTaggableOn::Tag.normalize(name)
|
||||||
followed_tag = @user.followed_tags.find_by(name: name_normalized)
|
followed_tag = @user.followed_tags.find_by!(name: name_normalized)
|
||||||
destroy(followed_tag.id) if followed_tag
|
destroy(followed_tag.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@user.followed_tags
|
@user.followed_tags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DuplicateTag < RuntimeError; end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ describe Api::V1::LikesController do
|
||||||
api_v1_post_likes_path(post_id: @status.guid),
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
confirm_api_error(response, 422, I18n.t("api.endpoint_errors.likes.like_exists"))
|
confirm_api_error(response, 409, I18n.t("api.endpoint_errors.likes.like_exists"))
|
||||||
|
|
||||||
likes = like_service.find_for_post(@status.guid)
|
likes = like_service.find_for_post(@status.guid)
|
||||||
expect(likes.length).to eq(1)
|
expect(likes.length).to eq(1)
|
||||||
|
|
@ -206,7 +206,7 @@ describe Api::V1::LikesController do
|
||||||
api_v1_post_likes_path(post_id: @status.guid),
|
api_v1_post_likes_path(post_id: @status.guid),
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
confirm_api_error(response, 404, I18n.t("api.endpoint_errors.likes.no_like"))
|
confirm_api_error(response, 410, I18n.t("api.endpoint_errors.likes.no_like"))
|
||||||
|
|
||||||
likes = like_service.find_for_post(@status.guid)
|
likes = like_service.find_for_post(@status.guid)
|
||||||
expect(likes.length).to eq(0)
|
expect(likes.length).to eq(0)
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ describe Api::V1::PostInteractionsController do
|
||||||
access_token: access_token
|
access_token: access_token
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(response.status).to eq(422)
|
expect(response.status).to eq(409)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "with improper guid" do
|
it "with improper guid" do
|
||||||
|
|
@ -225,7 +225,7 @@ describe Api::V1::PostInteractionsController do
|
||||||
access_token: access_token
|
access_token: access_token
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(response.status).to eq(404)
|
expect(response.status).to eq(410)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "with insufficient token" do
|
it "with insufficient token" do
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ describe Api::V1::ResharesController do
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
|
|
||||||
confirm_api_error(response, 422, I18n.t("reshares.create.error"))
|
confirm_api_error(response, 409, I18n.t("reshares.create.error"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ describe Api::V1::TagFollowingsController do
|
||||||
params: {name: "tag3", access_token: access_token}
|
params: {name: "tag3", access_token: access_token}
|
||||||
)
|
)
|
||||||
|
|
||||||
confirm_api_error(response, 422, I18n.t("api.endpoint_errors.tags.cant_process"))
|
confirm_api_error(response, 409, I18n.t("api.endpoint_errors.tags.cant_process"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ describe Api::V1::TagFollowingsController do
|
||||||
api_v1_tag_following_path(SecureRandom.uuid.to_s),
|
api_v1_tag_following_path(SecureRandom.uuid.to_s),
|
||||||
params: {access_token: access_token}
|
params: {access_token: access_token}
|
||||||
)
|
)
|
||||||
expect(response.status).to eq(204)
|
confirm_api_error(response, 410, I18n.t("api.endpoint_errors.tags.cant_process"))
|
||||||
|
|
||||||
get(
|
get(
|
||||||
api_v1_tag_followings_path,
|
api_v1_tag_followings_path,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ describe TagFollowingService do
|
||||||
expect { tag_following_service(alice).create("#") }.to raise_error(ArgumentError)
|
expect { tag_following_service(alice).create("#") }.to raise_error(ArgumentError)
|
||||||
expect { tag_following_service(alice).create(" ") }.to raise_error(ArgumentError)
|
expect { tag_following_service(alice).create(" ") }.to raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "throws an error when trying to follow an already followed tag" do
|
||||||
|
name = SecureRandom.uuid
|
||||||
|
tag_following_service.create(name)
|
||||||
|
expect {
|
||||||
|
tag_following_service.create(name)
|
||||||
|
}.to raise_error TagFollowingService::DuplicateTag
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#destroy" do
|
describe "#destroy" do
|
||||||
|
|
@ -44,14 +52,20 @@ describe TagFollowingService do
|
||||||
|
|
||||||
it "Does nothing with tag that isn't already followed" do
|
it "Does nothing with tag that isn't already followed" do
|
||||||
original_length = alice.followed_tags.length
|
original_length = alice.followed_tags.length
|
||||||
|
expect {
|
||||||
tag_following_service(alice).destroy_by_name(SecureRandom.uuid)
|
tag_following_service(alice).destroy_by_name(SecureRandom.uuid)
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
expect {
|
||||||
tag_following_service(alice).destroy(-1)
|
tag_following_service(alice).destroy(-1)
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
expect(alice.followed_tags.length).to eq(original_length)
|
expect(alice.followed_tags.length).to eq(original_length)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "Does nothing with empty tag name" do
|
it "Does nothing with empty tag name" do
|
||||||
original_length = alice.followed_tags.length
|
original_length = alice.followed_tags.length
|
||||||
|
expect {
|
||||||
tag_following_service(alice).destroy_by_name("")
|
tag_following_service(alice).destroy_by_name("")
|
||||||
|
}.to raise_error ActiveRecord::RecordNotFound
|
||||||
expect(alice.followed_tags.length).to eq(original_length)
|
expect(alice.followed_tags.length).to eq(original_length)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue