Skip to content

Commit c4d383b

Browse files
authored
Merge pull request #13 from globusonline/add-get-registered-api-command
Add get command to retrieve a single registered API
2 parents 047dd2f + 0b7f669 commit c4d383b

File tree

7 files changed

+220
-16
lines changed

7 files changed

+220
-16
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
Added
3+
-----
4+
5+
* Add ``get`` CLI command to retrieve a single registered API by ID.

src/globus_registered_api/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,31 @@ def list_registered_apis(
209209
click.echo(f"{api['id']} | {api['name']}")
210210

211211

212+
@cli.command("get")
213+
@click.argument("registered_api_id")
214+
@click.option("--format", type=click.Choice(["json", "text"]), default="text")
215+
@click.pass_context
216+
def get_registered_api(
217+
ctx: click.Context, registered_api_id: str, format: str
218+
) -> None:
219+
"""
220+
Get a registered API by ID.
221+
"""
222+
app: UserApp | ClientApp = ctx.obj
223+
flows_client = _create_flows_client(app)
224+
225+
res = flows_client.get_registered_api(registered_api_id)
226+
227+
if format == "json":
228+
click.echo(json.dumps(res.data, indent=2))
229+
else:
230+
click.echo(f"ID: {res['id']}")
231+
click.echo(f"Name: {res['name']}")
232+
click.echo(f"Description: {res['description']}")
233+
click.echo(f"Created: {res['created_timestamp']}")
234+
click.echo(f"Updated: {res['updated_timestamp']}")
235+
236+
212237
# --- willdelete command group ---
213238

214239

src/globus_registered_api/extended_flows_client.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,15 @@ def list_registered_apis(
6767
}
6868

6969
return self.get("/registered_apis", query_params=query_params)
70+
71+
def get_registered_api(
72+
self,
73+
registered_api_id: str | uuid.UUID,
74+
) -> GlobusHTTPResponse:
75+
"""
76+
Get a single registered API by ID.
77+
78+
:param registered_api_id: The ID of the registered API to retrieve
79+
:return: Response containing the registered API details
80+
"""
81+
return self.get(f"/registered_apis/{registered_api_id}")

tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
# Copyright 2025 Globus <support@globus.org>
44
# SPDX-License-Identifier: Apache-2.0
55

6+
import re
67
import typing as t
78
from pathlib import Path
89

910
import pytest
1011
import responses
1112
from click.testing import CliRunner
1213

14+
# URL patterns for mocking Flows service responses
15+
LIST_REGISTERED_APIS_URL = re.compile(r"https://.*flows.*\.globus\.org/registered_apis")
16+
GET_REGISTERED_API_URL = re.compile(
17+
r"https://.*flows.*\.globus\.org/registered_apis/[a-f0-9-]+"
18+
)
19+
1320

1421
@pytest.fixture(autouse=True)
1522
def mocked_responses():

tests/test_extended_flows_client.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# Copyright 2025 Globus <support@globus.org>
44
# SPDX-License-Identifier: Apache-2.0
55

6-
import re
76
import uuid
87

98
import pytest
@@ -12,8 +11,7 @@
1211

1312
from globus_registered_api.extended_flows_client import ExtendedFlowsClient
1413

15-
# Match any Flows service base URL (production or sandbox)
16-
REGISTERED_APIS_URL = re.compile(r"https://.*flows.*\.globus\.org/registered_apis")
14+
from conftest import GET_REGISTERED_API_URL, LIST_REGISTERED_APIS_URL
1715

1816

1917
@pytest.fixture
@@ -25,7 +23,7 @@ def test_list_registered_apis_basic(client):
2523
api_id = str(uuid.uuid4())
2624
responses.add(
2725
responses.GET,
28-
REGISTERED_APIS_URL,
26+
LIST_REGISTERED_APIS_URL,
2927
json={
3028
"registered_apis": [
3129
{"id": api_id, "name": "Test API"},
@@ -48,7 +46,7 @@ def test_list_registered_apis_with_filter_roles(client):
4846
api_id = str(uuid.uuid4())
4947
responses.add(
5048
responses.GET,
51-
REGISTERED_APIS_URL,
49+
LIST_REGISTERED_APIS_URL,
5250
json={
5351
"registered_apis": [
5452
{"id": api_id, "name": "Owned API"},
@@ -70,7 +68,7 @@ def test_list_registered_apis_with_filter_roles_string(client):
7068
api_id = str(uuid.uuid4())
7169
responses.add(
7270
responses.GET,
73-
REGISTERED_APIS_URL,
71+
LIST_REGISTERED_APIS_URL,
7472
json={
7573
"registered_apis": [
7674
{"id": api_id, "name": "Viewable API"},
@@ -92,7 +90,7 @@ def test_list_registered_apis_with_per_page(client):
9290
api_ids = [str(uuid.uuid4()) for _ in range(3)]
9391
responses.add(
9492
responses.GET,
95-
REGISTERED_APIS_URL,
93+
LIST_REGISTERED_APIS_URL,
9694
json={
9795
"registered_apis": [
9896
{"id": api_ids[0], "name": "API One"},
@@ -117,7 +115,7 @@ def test_list_registered_apis_with_marker(client):
117115
api_id = str(uuid.uuid4())
118116
responses.add(
119117
responses.GET,
120-
REGISTERED_APIS_URL,
118+
LIST_REGISTERED_APIS_URL,
121119
json={
122120
"registered_apis": [
123121
{"id": api_id, "name": "Next Page API"},
@@ -140,7 +138,7 @@ def test_list_registered_apis_with_orderby_string(client):
140138
api_ids = [str(uuid.uuid4()) for _ in range(2)]
141139
responses.add(
142140
responses.GET,
143-
REGISTERED_APIS_URL,
141+
LIST_REGISTERED_APIS_URL,
144142
json={
145143
"registered_apis": [
146144
{"id": api_ids[0], "name": "Alpha API"},
@@ -158,3 +156,26 @@ def test_list_registered_apis_with_orderby_string(client):
158156
assert len(response["registered_apis"]) == 2
159157
assert response["registered_apis"][0]["name"] == "Alpha API"
160158
assert response["registered_apis"][1]["name"] == "Beta API"
159+
160+
161+
def test_get_registered_api(client):
162+
api_id = uuid.uuid4()
163+
responses.add(
164+
responses.GET,
165+
GET_REGISTERED_API_URL,
166+
json={
167+
"id": str(api_id),
168+
"name": "Test API",
169+
"description": "A test API",
170+
"created_timestamp": "2025-01-01T00:00:00+00:00",
171+
"updated_timestamp": "2025-01-01T00:00:00+00:00",
172+
},
173+
)
174+
175+
response = client.get_registered_api(api_id)
176+
177+
assert isinstance(response, GlobusHTTPResponse)
178+
assert response["id"] == str(api_id)
179+
assert response["name"] == "Test API"
180+
assert response["description"] == "A test API"
181+
assert f"/registered_apis/{api_id}" in responses.calls[0].request.url

tests/test_get_registered_api.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# This file is a part of globus-registered-api.
2+
# https://github.com/globusonline/globus-registered-api
3+
# Copyright 2025 Globus <support@globus.org>
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
from unittest.mock import patch
7+
8+
import responses
9+
10+
import globus_registered_api.cli
11+
from globus_registered_api.extended_flows_client import ExtendedFlowsClient
12+
13+
from conftest import GET_REGISTERED_API_URL
14+
15+
16+
@patch("globus_registered_api.cli._create_flows_client")
17+
def test_get_registered_api_text_format(mock_create_client, cli_runner):
18+
mock_create_client.return_value = ExtendedFlowsClient()
19+
responses.add(
20+
responses.GET,
21+
GET_REGISTERED_API_URL,
22+
json={
23+
"id": "abc-123-def-456",
24+
"name": "Test API",
25+
"description": "A test description",
26+
"created_timestamp": "2025-01-01T00:00:00+00:00",
27+
"updated_timestamp": "2025-01-02T00:00:00+00:00",
28+
},
29+
)
30+
31+
result = cli_runner.invoke(
32+
globus_registered_api.cli.cli, ["get", "abc-123-def-456"]
33+
)
34+
35+
assert result.exit_code == 0
36+
assert "ID:" in result.output
37+
assert "abc-123-def-456" in result.output
38+
assert "Name:" in result.output
39+
assert "Test API" in result.output
40+
assert "Description:" in result.output
41+
assert "A test description" in result.output
42+
assert "Created:" in result.output
43+
assert "Updated:" in result.output
44+
45+
46+
@patch("globus_registered_api.cli._create_flows_client")
47+
def test_get_registered_api_json_format(mock_create_client, cli_runner):
48+
mock_create_client.return_value = ExtendedFlowsClient()
49+
responses.add(
50+
responses.GET,
51+
GET_REGISTERED_API_URL,
52+
json={
53+
"id": "abc-123-def-456",
54+
"name": "Test API",
55+
"description": "A test description",
56+
"created_timestamp": "2025-01-01T00:00:00+00:00",
57+
"updated_timestamp": "2025-01-02T00:00:00+00:00",
58+
},
59+
)
60+
61+
result = cli_runner.invoke(
62+
globus_registered_api.cli.cli, ["get", "abc-123-def-456", "--format", "json"]
63+
)
64+
65+
assert result.exit_code == 0
66+
assert '"id": "abc-123-def-456"' in result.output
67+
assert '"name": "Test API"' in result.output
68+
assert '"description": "A test description"' in result.output
69+
70+
71+
@patch("globus_registered_api.cli._create_flows_client")
72+
def test_get_registered_api_empty_description(mock_create_client, cli_runner):
73+
mock_create_client.return_value = ExtendedFlowsClient()
74+
responses.add(
75+
responses.GET,
76+
GET_REGISTERED_API_URL,
77+
json={
78+
"id": "abc-123-def-456",
79+
"name": "Minimal API",
80+
"description": "",
81+
"created_timestamp": "2025-01-01T00:00:00+00:00",
82+
"updated_timestamp": "2025-01-01T00:00:00+00:00",
83+
},
84+
)
85+
86+
result = cli_runner.invoke(
87+
globus_registered_api.cli.cli, ["get", "abc-123-def-456"]
88+
)
89+
90+
assert result.exit_code == 0
91+
assert "Minimal API" in result.output
92+
assert "Description:" in result.output
93+
94+
95+
@patch("globus_registered_api.cli._create_flows_client")
96+
def test_get_registered_api_calls_correct_endpoint(mock_create_client, cli_runner):
97+
mock_create_client.return_value = ExtendedFlowsClient()
98+
api_id = "12345678-1234-1234-1234-123456789abc"
99+
responses.add(
100+
responses.GET,
101+
GET_REGISTERED_API_URL,
102+
json={
103+
"id": api_id,
104+
"name": "Test",
105+
"description": "",
106+
"created_timestamp": "2025-01-01T00:00:00+00:00",
107+
"updated_timestamp": "2025-01-01T00:00:00+00:00",
108+
},
109+
)
110+
111+
cli_runner.invoke(globus_registered_api.cli.cli, ["get", api_id])
112+
113+
assert f"/registered_apis/{api_id}" in responses.calls[0].request.url
114+
115+
116+
@patch("globus_registered_api.cli._create_flows_client")
117+
def test_get_registered_api_not_found(mock_create_client, cli_runner):
118+
mock_create_client.return_value = ExtendedFlowsClient()
119+
api_id = "12345678-1234-1234-1234-123456789abc"
120+
responses.add(
121+
responses.GET,
122+
GET_REGISTERED_API_URL,
123+
status=404,
124+
json={
125+
"error": {
126+
"code": "NOT_FOUND",
127+
"detail": f"No Registered API exists with id value {api_id}",
128+
}
129+
},
130+
)
131+
132+
result = cli_runner.invoke(globus_registered_api.cli.cli, ["get", api_id])
133+
134+
assert result.exit_code != 0
135+
assert "No Registered API exists" in str(result.exception)

tests/test_list_registered_apis.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,22 @@
33
# Copyright 2025 Globus <support@globus.org>
44
# SPDX-License-Identifier: Apache-2.0
55

6-
import re
76
from unittest.mock import patch
87

98
import responses
109

1110
import globus_registered_api.cli
1211
from globus_registered_api.extended_flows_client import ExtendedFlowsClient
1312

14-
REGISTERED_APIS_URL = re.compile(r"https://.*flows.*\.globus\.org/registered_apis")
13+
from conftest import LIST_REGISTERED_APIS_URL
1514

1615

1716
@patch("globus_registered_api.cli._create_flows_client")
1817
def test_list_registered_apis_text_format(mock_create_client, cli_runner):
1918
mock_create_client.return_value = ExtendedFlowsClient()
2019
responses.add(
2120
responses.GET,
22-
REGISTERED_APIS_URL,
21+
LIST_REGISTERED_APIS_URL,
2322
json={
2423
"registered_apis": [
2524
{"id": "abc-123", "name": "Test API 1"},
@@ -46,7 +45,7 @@ def test_list_registered_apis_json_format(mock_create_client, cli_runner):
4645
mock_create_client.return_value = ExtendedFlowsClient()
4746
responses.add(
4847
responses.GET,
49-
REGISTERED_APIS_URL,
48+
LIST_REGISTERED_APIS_URL,
5049
json={
5150
"registered_apis": [
5251
{"id": "abc-123", "name": "Test API 1"},
@@ -70,7 +69,7 @@ def test_list_registered_apis_empty_result(mock_create_client, cli_runner):
7069
mock_create_client.return_value = ExtendedFlowsClient()
7170
responses.add(
7271
responses.GET,
73-
REGISTERED_APIS_URL,
72+
LIST_REGISTERED_APIS_URL,
7473
json={
7574
"registered_apis": [],
7675
"has_next_page": False,
@@ -89,7 +88,7 @@ def test_list_registered_apis_with_filter_roles(mock_create_client, cli_runner):
8988
mock_create_client.return_value = ExtendedFlowsClient()
9089
responses.add(
9190
responses.GET,
92-
REGISTERED_APIS_URL,
91+
LIST_REGISTERED_APIS_URL,
9392
json={
9493
"registered_apis": [],
9594
"has_next_page": False,
@@ -110,7 +109,7 @@ def test_list_registered_apis_with_per_page(mock_create_client, cli_runner):
110109
mock_create_client.return_value = ExtendedFlowsClient()
111110
responses.add(
112111
responses.GET,
113-
REGISTERED_APIS_URL,
112+
LIST_REGISTERED_APIS_URL,
114113
json={
115114
"registered_apis": [],
116115
"has_next_page": False,

0 commit comments

Comments
 (0)