Commit 33f32314 authored by James Ramsay's avatar James Ramsay

Add _links to epics API

The issues and merge request APIs include links to related resources to
avoid clients needing to understand the URL schema to access related
entities. This adds basics links to the Epics API for consistency.
parent 2d79e081
...@@ -92,7 +92,7 @@ Example response: ...@@ -92,7 +92,7 @@ Example response:
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.", "description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened", "state": "opened",
"confidential": "false", "confidential": "false",
"web_url": "http://localhost:3001/groups/test/-/epics/4", "web_url": "http://gitlab.example.com/groups/test/-/epics/4",
"reference": "&4", "reference": "&4",
"references": { "references": {
"short": "&4", "short": "&4",
...@@ -105,7 +105,7 @@ Example response: ...@@ -105,7 +105,7 @@ Example response:
"username": "kam", "username": "kam",
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon",
"web_url": "http://localhost:3001/kam" "web_url": "http://gitlab.example.com/kam"
}, },
"start_date": null, "start_date": null,
"start_date_is_fixed": false, "start_date_is_fixed": false,
...@@ -123,7 +123,12 @@ Example response: ...@@ -123,7 +123,12 @@ Example response:
"closed_at": "2018-08-18T12:22:05.239Z", "closed_at": "2018-08-18T12:22:05.239Z",
"labels": [], "labels": [],
"upvotes": 4, "upvotes": 4,
"downvotes": 0 "downvotes": 0,
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/4",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/4/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
}
}, },
{ {
"id": 50, "id": 50,
...@@ -133,7 +138,7 @@ Example response: ...@@ -133,7 +138,7 @@ Example response:
"title": "Accusamus iste et ullam ratione voluptatem omnis debitis dolor est.", "title": "Accusamus iste et ullam ratione voluptatem omnis debitis dolor est.",
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.", "description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened", "state": "opened",
"web_url": "http://localhost:3001/groups/test/sample/-/epics/4", "web_url": "http://gitlab.example.com/groups/test/sample/-/epics/35",
"reference": "&4", "reference": "&4",
"references": { "references": {
"short": "&4", "short": "&4",
...@@ -146,7 +151,7 @@ Example response: ...@@ -146,7 +151,7 @@ Example response:
"username": "kam", "username": "kam",
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon",
"web_url": "http://localhost:3001/kam" "web_url": "http://gitlab.example.com/kam"
}, },
"start_date": null, "start_date": null,
"start_date_is_fixed": false, "start_date_is_fixed": false,
...@@ -164,7 +169,12 @@ Example response: ...@@ -164,7 +169,12 @@ Example response:
"closed_at": "2018-08-18T12:22:05.239Z", "closed_at": "2018-08-18T12:22:05.239Z",
"labels": [], "labels": [],
"upvotes": 4, "upvotes": 4,
"downvotes": 0 "downvotes": 0,
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/17/epics/35",
"epic_issues": "http://gitlab.example.com/api/v4/groups/17/epics/35/issues",
"group":"http://gitlab.example.com/api/v4/groups/17"
}
} }
] ]
``` ```
...@@ -196,7 +206,7 @@ Example response: ...@@ -196,7 +206,7 @@ Example response:
"title": "Ea cupiditate dolores ut vero consequatur quasi veniam voluptatem et non.", "title": "Ea cupiditate dolores ut vero consequatur quasi veniam voluptatem et non.",
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.", "description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened", "state": "opened",
"web_url": "http://localhost:3001/groups/test/-/epics/5", "web_url": "http://gitlab.example.com/groups/test/-/epics/5",
"reference": "&5", "reference": "&5",
"references": { "references": {
"short": "&5", "short": "&5",
...@@ -209,7 +219,7 @@ Example response: ...@@ -209,7 +219,7 @@ Example response:
"username": "arnita", "username": "arnita",
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/a2f5c6fcef64c9c69cb8779cb292be1b?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/a2f5c6fcef64c9c69cb8779cb292be1b?s=80&d=identicon",
"web_url": "http://localhost:3001/arnita" "web_url": "http://gitlab.example.com/arnita"
}, },
"start_date": null, "start_date": null,
"start_date_is_fixed": false, "start_date_is_fixed": false,
...@@ -228,7 +238,12 @@ Example response: ...@@ -228,7 +238,12 @@ Example response:
"labels": [], "labels": [],
"upvotes": 4, "upvotes": 4,
"downvotes": 0, "downvotes": 0,
"subscribed": true "subscribed": true,
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/5",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/5/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
}
} }
``` ```
...@@ -273,7 +288,7 @@ Example response: ...@@ -273,7 +288,7 @@ Example response:
"description": "Epic description", "description": "Epic description",
"state": "opened", "state": "opened",
"confidential": "false", "confidential": "false",
"web_url": "http://localhost:3001/groups/test/-/epics/6", "web_url": "http://gitlab.example.com/groups/test/-/epics/6",
"reference": "&6", "reference": "&6",
"references": { "references": {
"short": "&6", "short": "&6",
...@@ -304,7 +319,12 @@ Example response: ...@@ -304,7 +319,12 @@ Example response:
"closed_at": "2018-08-18T12:22:05.239Z", "closed_at": "2018-08-18T12:22:05.239Z",
"labels": [], "labels": [],
"upvotes": 4, "upvotes": 4,
"downvotes": 0 "downvotes": 0,
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/6",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/6/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
}
} }
``` ```
...@@ -350,7 +370,7 @@ Example response: ...@@ -350,7 +370,7 @@ Example response:
"description": "Epic description", "description": "Epic description",
"state": "opened", "state": "opened",
"confidential": "false", "confidential": "false",
"web_url": "http://localhost:3001/groups/test/-/epics/6", "web_url": "http://gitlab.example.com/groups/test/-/epics/6",
"reference": "&6", "reference": "&6",
"references": { "references": {
"short": "&6", "short": "&6",
...@@ -456,9 +476,9 @@ Example response: ...@@ -456,9 +476,9 @@ Example response:
"username": "arnita", "username": "arnita",
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/a2f5c6fcef64c9c69cb8779cb292be1b?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/a2f5c6fcef64c9c69cb8779cb292be1b?s=80&d=identicon",
"web_url": "http://localhost:3001/arnita" "web_url": "http://gitlab.example.com/arnita"
}, },
"web_url": "http://localhost:3001/groups/test/-/epics/5", "web_url": "http://gitlab.example.com/groups/test/-/epics/5",
"reference": "&5", "reference": "&5",
"references": { "references": {
"short": "&5", "short": "&5",
......
---
title: Add _links to epic API entity
merge_request: 37395
author:
type: added
...@@ -55,10 +55,12 @@ module API ...@@ -55,10 +55,12 @@ module API
params do params do
requires :epic_iid, type: Integer, desc: 'The internal ID of an epic' requires :epic_iid, type: Integer, desc: 'The internal ID of an epic'
end end
get ':id/(-/)epics/:epic_iid' do [':id/epics/:epic_iid', ':id/-/epics/:epic_iid'].each do |path|
authorize_can_read! get path do
authorize_can_read!
present epic, epic_options.merge(include_subscribed: true) present epic, epic_options.merge(include_subscribed: true)
end
end end
desc 'Create a new epic' do desc 'Create a new epic' do
......
...@@ -4,6 +4,8 @@ module EE ...@@ -4,6 +4,8 @@ module EE
module API module API
module Entities module Entities
class Epic < Grape::Entity class Epic < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
can_admin_epic = ->(epic, opts) { Ability.allowed?(opts[:user], :admin_epic, epic) } can_admin_epic = ->(epic, opts) { Ability.allowed?(opts[:user], :admin_epic, epic) }
expose :id expose :id
...@@ -77,6 +79,20 @@ module EE ...@@ -77,6 +79,20 @@ module EE
def web_edit_url def web_edit_url
::Gitlab::Routing.url_helpers.group_epic_path(object.group, object) ::Gitlab::Routing.url_helpers.group_epic_path(object.group, object)
end end
expose :_links do
expose :self do |epic|
expose_url(api_v4_groups_epics_path(id: epic.group_id, epic_iid: epic.iid))
end
expose :epic_issues do |epic|
expose_url(api_v4_groups_epics_issues_path(id: epic.group_id, epic_iid: epic.iid))
end
expose :group do |epic|
expose_url(api_v4_groups_path(id: epic.group_id))
end
end
end end
end end
end end
......
...@@ -51,10 +51,19 @@ ...@@ -51,10 +51,19 @@
"relative": {"type": "string"}, "relative": {"type": "string"},
"full": {"type": "string"} "full": {"type": "string"}
}, },
"subscribed": { "type": ["boolean", "null"] } "subscribed": { "type": ["boolean", "null"] },
"_links": {
"type": "object",
"properties": {
"self": { "type": "uri" },
"epic_issues": { "type": "uri" },
"group": { "type": "uri" },
"additionalProperties": false
}
}
}, },
"required": [ "required": [
"id", "iid", "group_id", "title", "confidential" "id", "iid", "group_id", "title", "confidential", "_links"
], ],
"additionalProperties": false "additionalProperties": false
} }
...@@ -522,6 +522,16 @@ RSpec.describe API::Epics do ...@@ -522,6 +522,16 @@ RSpec.describe API::Epics do
expect(json_response['references']['full']).to eq("#{epic.group.path}&#{epic.iid}") expect(json_response['references']['full']).to eq("#{epic.group.path}&#{epic.iid}")
end end
it 'exposes links' do
get api(url)
links = json_response['_links']
expect(links['self']).to end_with("/api/v4/groups/#{epic.group.id}/epics/#{epic.iid}")
expect(links['epic_issues']).to end_with("/api/v4/groups/#{epic.group.id}/epics/#{epic.iid}/issues")
expect(links['group']).to end_with("/api/v4/groups/#{epic.group.id}")
end
it_behaves_like 'can admin epics' it_behaves_like 'can admin epics'
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment