Commit a69aa3da authored by Sean McGivern's avatar Sean McGivern

Merge branch 'api-empty-return' into 'master'

Return 204 on all DELETE endpoints

Closes #20429

See merge request !9397
parents 71fbbc9d 2b8005ae
......@@ -68,7 +68,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
gem 'grape', '~> 0.18.0'
gem 'grape', '~> 0.19.0'
gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
......
......@@ -304,7 +304,7 @@ GEM
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
grape (0.18.0)
grape (0.19.1)
activesupport
builder
hashie (>= 2.1.0)
......@@ -353,8 +353,8 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.2)
i18n (0.8.0)
ice_nine (0.11.1)
i18n (0.8.1)
ice_nine (0.11.2)
influxdb (0.2.3)
cause
json
......@@ -417,7 +417,7 @@ GEM
minitest (5.7.0)
mousetrap-rails (1.4.6)
multi_json (1.12.1)
multi_xml (0.5.5)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (0.4.0)
tool (~> 0.2)
......@@ -758,7 +758,7 @@ GEM
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thor (0.19.4)
thread_safe (0.3.5)
thread_safe (0.3.6)
tilt (2.0.6)
timecop (0.8.1)
timfel-krb5-auth (0.8.3)
......@@ -886,7 +886,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.1.0)
google-api-client (~> 0.8.6)
grape (~> 0.18.0)
grape (~> 0.19.0)
grape-entity (~> 0.6.0)
haml_lint (~> 0.21.0)
hamlit (~> 2.6.1)
......@@ -1011,4 +1011,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.14.3
1.14.4
---
title: 'API: Return 204 for all delete endpoints'
merge_request: 9397
author: Robert Schilling
......@@ -159,6 +159,7 @@ The following table shows the possible return codes for API requests.
| Return values | Description |
| ------------- | ----------- |
| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. |
| `204 OK` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. |
| `201 Created` | The `POST` request was successful and the resource is returned as JSON. |
| `304 Not Modified` | Indicates that the resource has not been modified since the last request. |
| `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. |
......
......@@ -178,27 +178,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/344
```
Example Response:
```json
{
"id": 344,
"name": "blowfish",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T17:47:29.266Z",
"updated_at": "2016-06-17T17:47:29.266Z",
"awardable_id": 80,
"awardable_type": "Issue"
}
```
## Award Emoji on Notes
The endpoints documented above are available for Notes as well. Notes
......@@ -350,25 +329,4 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/345
```
Example Response:
```json
{
"id": 345,
"name": "rocket",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T19:59:55.888Z",
"updated_at": "2016-06-17T19:59:55.888Z",
"awardable_id": 1,
"awardable_type": "Note"
}
```
[ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575
......@@ -226,16 +226,3 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1
```
Example response:
```json
{
"id" : 1,
"label" : {
"name" : "Testing",
"color" : "#F0AD4E",
"description" : null
},
"position" : 1
}
```
......@@ -244,14 +244,6 @@ In case of an error, an explaining message is provided.
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/repository/branches/newbranch"
```
Example response:
```json
{
"branch_name": "newbranch"
}
```
## Delete merged branches
Will delete all branches that are merged into the project's default branch.
......
......@@ -138,17 +138,3 @@ DELETE /broadcast_messages/:id
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/broadcast_messages/1
```
Example response:
```json
{
"message":"Update message",
"starts_at":"2016-08-26T00:41:35.060Z",
"ends_at":"2016-08-26T01:41:35.060Z",
"color":"#000",
"font":"#FFFFFF",
"id":1,
"active": true
}
```
......@@ -106,13 +106,3 @@ DELETE /projects/:id/triggers/:token
```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d"
```
```json
{
"created_at": "2015-12-23T16:25:56.760Z",
"deleted_at": "2015-12-24T12:32:20.100Z",
"last_used": null,
"token": "7b9148c158980bbd9bcea92c17522d",
"updated_at": "2015-12-24T12:32:20.100Z"
}
```
......@@ -119,10 +119,3 @@ DELETE /projects/:id/variables/:key
```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/variables/VARIABLE_1"
```
```json
{
"key": "VARIABLE_1",
"value": "VALUE_1"
}
```
......@@ -152,18 +152,6 @@ DELETE /projects/:id/deploy_keys/:key_id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys/13"
```
Example response:
```json
{
"id": 6,
"deploy_key_id": 14,
"project_id": 1,
"created_at" : "2015-08-29T12:50:57.259Z",
"updated_at" : "2015-08-29T12:50:57.259Z"
}
```
## Enable a deploy key
Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful.
......
......@@ -108,14 +108,3 @@ DELETE /projects/:id/environments/:environment_id
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/environments/1"
```
Example response:
```json
{
"id": 1,
"name": "deploy",
"slug": "deploy",
"external_url": "https://deploy.example.gitlab.com"
}
```
......@@ -581,43 +581,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/unsubscribe
```
Example response:
```json
{
"id": 93,
"iid": 12,
"project_id": 5,
"title": "Incidunt et rerum ea expedita iure quibusdam.",
"description": "Et cumque architecto sed aut ipsam.",
"state": "opened",
"created_at": "2016-04-05T21:41:45.217Z",
"updated_at": "2016-04-07T13:02:37.905Z",
"labels": [],
"milestone": null,
"assignee": {
"name": "Edwardo Grady",
"username": "keyon",
"id": 21,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/3e6f06a86cf27fa8b56f3f74f7615987?s=80&d=identicon",
"web_url": "https://gitlab.example.com/keyon"
},
"author": {
"name": "Vivian Hermann",
"username": "orville",
"id": 11,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/orville"
},
"subscribed": false,
"due_date": null,
"web_url": "http://example.com/example/example/issues/12",
"confidential": false
}
```
## Create a todo
Manually creates a todo for the current user on an issue. If
......
......@@ -131,22 +131,6 @@ DELETE /projects/:id/labels
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/labels?name=bug"
```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
## Edit an existing label
Updates an existing label with new name or new color. At least one parameter
......@@ -239,19 +223,3 @@ POST /projects/:id/labels/:label_id/unsubscribe
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/labels/1/unsubscribe
```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
......@@ -123,30 +123,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/11/notes/636
```
Example Response:
```json
{
"id": 636,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:10:44.164Z",
"system": false,
"noteable_id": 11,
"noteable_type": "Issue"
}
```
## Snippets
### List all snippet notes
......@@ -245,30 +221,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/snippets/52/notes/1659
```
Example Response:
```json
{
"id": 1659,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-06T16:51:53.239Z",
"system": false,
"noteable_id": 52,
"noteable_type": "Snippet"
}
```
## Merge Requests
### List all merge request notes
......@@ -369,27 +321,3 @@ Parameters:
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/7/notes/1602
```
Example Response:
```json
{
"id": 1602,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:11:59.923Z",
"system": false,
"noteable_id": 7,
"noteable_type": "MergeRequest"
}
```
......@@ -210,18 +210,6 @@ DELETE /runners/:id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/runners/6"
```
Example response:
```json
{
"active": true,
"description": "test-1-20150125-test",
"id": 6,
"is_shared": false,
"name": null,
}
```
## List project's runners
List all runners (specific and shared) available in the project. Shared runners
......@@ -308,15 +296,3 @@ DELETE /projects/:id/runners/:runner_id
```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/9/runners/9"
```
Example response:
```json
{
"active": true,
"description": "test-2016-02-01",
"id": 9,
"is_shared": false,
"name": null
}
```
......@@ -125,22 +125,3 @@ Example request:
```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/hooks/2
```
Example response:
```json
{
"note_events" : false,
"project_id" : null,
"enable_ssl_verification" : true,
"url" : "https://gitlab.example.com/hook",
"updated_at" : "2015-11-04T20:12:15.931Z",
"issues_events" : false,
"merge_requests_events" : false,
"created_at" : "2015-11-04T20:12:15.931Z",
"service_id" : null,
"id" : 2,
"push_events" : true,
"tag_push_events" : false
}
```
......@@ -141,11 +141,6 @@ Parameters:
- `id` (required) - The ID of a project
- `tag_name` (required) - The name of a tag
```json
{
"tag_name": "v4.3.0"
}
```
## Create a new release
......
......@@ -5,10 +5,13 @@ module API
version %w(v3 v4), using: :path
version 'v3', using: :path do
mount ::API::V3::AwardEmoji
mount ::API::V3::Boards
mount ::API::V3::Branches
mount ::API::V3::BroadcastMessages
mount ::API::V3::Commits
mount ::API::V3::DeployKeys
mount ::API::V3::Environments
mount ::API::V3::Files
mount ::API::V3::Groups
mount ::API::V3::Issues
......@@ -21,12 +24,16 @@ module API
mount ::API::V3::Projects
mount ::API::V3::ProjectSnippets
mount ::API::V3::Repositories
mount ::API::V3::Runners
mount ::API::V3::Services
mount ::API::V3::Subscriptions
mount ::API::V3::SystemHooks
mount ::API::V3::Tags
mount ::API::V3::Todos
mount ::API::V3::Templates
mount ::API::V3::Todos
mount ::API::V3::Triggers
mount ::API::V3::Users
mount ::API::V3::Variables
end
before { allow_access_with_scope :api }
......
......@@ -83,7 +83,6 @@ module API
unauthorized! unless award.user == current_user || current_user.admin?
award.destroy
present award, with: Entities::AwardEmoji
end
end
end
......
......@@ -127,9 +127,7 @@ module API
service = ::Boards::Lists::DestroyService.new(user_project, current_user)
if service.execute(list)
present list, with: Entities::List
else
unless service.execute(list)
render_api_error!({ error: 'List could not be deleted!' }, 400)
end
end
......
......@@ -124,11 +124,7 @@ module API
result = DeleteBranchService.new(user_project, current_user).
execute(params[:branch])
if result[:status] == :success
{
branch: params[:branch]
}
else
if result[:status] != :success
render_api_error!(result[:message], result[:return_code])
end
end
......
......@@ -91,7 +91,7 @@ module API
delete ':id' do
message = find_message
present message.destroy, with: Entities::BroadcastMessage
message.destroy
end
end
end
......
......@@ -79,7 +79,7 @@ module API
environment = user_project.environments.find(params[:environment_id])
present environment.destroy, with: Entities::Environment
environment.destroy
end
end
end
......
......@@ -118,10 +118,7 @@ module API
file_params = declared_params(include_missing: false)
result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute
if result[:status] == :success
status(200)
commit_response(file_params)
else
if result[:status] != :success
render_api_error!(result[:message], 400)
end
end
......
module API
class Labels < Grape::API
include PaginationParams
before { authenticate! }
params do
......@@ -56,7 +56,7 @@ module API
label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label
present label.destroy, with: Entities::Label, current_user: current_user, project: user_project
label.destroy
end
desc 'Update an existing label. At least one optional parameter is required.' do
......
......@@ -93,24 +93,10 @@ module API
end
delete ":id/members/:user_id" do
source = find_source(source_type, params[:id])
# Ensure that memeber exists
source.members.find_by!(user_id: params[:user_id])
# This is to ensure back-compatibility but find_by! should be used
# in that casse in 9.0!
member = source.members.find_by(user_id: params[:user_id])
# This is to ensure back-compatibility but this should be removed in
# favor of find_by! in 9.0!
not_found!("Member: user_id:#{params[:user_id]}") if source_type == 'group' && member.nil?
# This is to ensure back-compatibility but 204 behavior should be used
# for all DELETE endpoints in 9.0!
if member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
else
::Members::DestroyService.new(source, current_user, declared_params).execute
present member.user, with: Entities::Member, member: member
end
::Members::DestroyService.new(source, current_user, declared_params).execute
end
end
end
......
......@@ -132,8 +132,6 @@ module API
authorize! :admin_note, note
::Notes::DestroyService.new(user_project, current_user).execute(note)
present note, with: Entities::Note
end
end
end
......
......@@ -90,12 +90,9 @@ module API
requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
end
delete ":id/hooks/:hook_id" do
begin
present user_project.hooks.destroy(params[:hook_id]), with: Entities::ProjectHook
rescue
# ProjectHook can raise Error if hook_id not found
not_found!("Error deleting hook #{params[:hook_id]}")
end
hook = user_project.hooks.find(params.delete(:hook_id))
hook.destroy
end
end
end
......
......@@ -353,7 +353,6 @@ module API
not_found!('Group Link') unless link
link.destroy
no_content!
end
desc 'Upload a file'
......
......@@ -38,7 +38,7 @@ module API
end
desc 'Deletes a registered Runner' do
http_codes [[200, 'Runner was deleted'], [403, 'Forbidden']]
http_codes [[204, 'Runner was deleted'], [403, 'Forbidden']]
end
params do
requires :token, type: String, desc: %q(Runner's authentication token)
......
......@@ -78,9 +78,8 @@ module API
delete ':id' do
runner = get_runner(params[:id])
authenticate_delete_runner!(runner)
runner.destroy!
present runner, with: Entities::Runner
runner.destroy!
end
end
......@@ -136,8 +135,6 @@ module API
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
runner_project.destroy
present runner, with: Entities::Runner
end
end
......
......@@ -654,9 +654,7 @@ module API
hash.merge!(key => nil)
end