Skip to content

Commit 6dca29c

Browse files
jfrench9claude
andauthored
Add connection management API endpoints and models (#65)
## Summary Introduces a complete connection management module to the `robosystems_client`, providing full CRUD operations and OAuth support for external data provider connections. This feature adds 8 new API endpoints and 20+ supporting model definitions, along with a minor update to the existing `DownloadQuota` model. ## Key Accomplishments ### New API Endpoints (`api/connections/`) - **Create Connection** – Establish new connections to external providers - **Delete Connection** – Remove existing connections - **Get Connection** – Retrieve details for a specific connection - **Get Connection Options** – Fetch available configuration options for providers - **List Connections** – Query and filter all connections with provider type filtering - **Init OAuth** – Initiate OAuth authentication flows with configurable additional params - **OAuth Callback** – Handle OAuth redirect callbacks to complete authentication - **Sync Connection** – Trigger data synchronization on a connection with customizable sync options ### New Models - **Connection models**: `ConnectionResponse`, `ConnectionResponseMetadata`, `ConnectionOptionsResponse`, `ConnectionProviderInfo` (with auth type and provider enums) - **Request models**: `CreateConnectionRequest`, `OAuthInitRequest`, `OAuthCallbackRequest`, `SyncConnectionRequest` - **Response models**: `OAuthInitResponse`, `SyncConnectionResponseSyncconnection` - **Provider-specific configs**: `PlaidConnectionConfig` (with accounts and institution types), `QuickBooksConnectionConfig`, `SecConnectionConfig` - **Supporting types**: `ListConnectionsProviderType0`, `CreateConnectionRequestProvider`, `OAuthInitRequestAdditionalParamsType0`, `SyncConnectionRequestSyncOptionsType0` ### Modified Models - **`DownloadQuota`** – Updated attribute definitions (28 lines changed, likely field type or naming adjustments) - **`models/__init__.py`** – Updated to export all new model classes ## Breaking Changes - The `DownloadQuota` model has been modified. Consumers relying on its previous attribute structure should verify compatibility after upgrading. ## Testing Notes - Verify each of the 8 connection API endpoints for correct request serialization and response deserialization - Test OAuth flow end-to-end (init → callback) to ensure proper state handling - Validate provider-specific configurations (Plaid, QuickBooks, SEC) with realistic payloads - Confirm `DownloadQuota` changes do not regress existing functionality that depends on this model - Test `list_connections` filtering by provider type, including union/optional type handling ## Infrastructure Considerations - This is a client-side SDK change; no backend deployment is required, but the corresponding API endpoints must be available on the target environment - New provider integrations (Plaid, QuickBooks, SEC) may require environment-specific credentials and OAuth redirect URI configuration - The OAuth callback endpoint implies a redirect flow — ensure client applications have appropriate callback handling in place --- 🤖 Generated with [Claude Code](https://claude.ai/code) **Branch Info:** - Source: `feature/connection-management` - Target: `main` - Type: feature Co-Authored-By: Claude <noreply@anthropic.com>
2 parents 3ed9c6c + e2aee3b commit 6dca29c

32 files changed

Lines changed: 4000 additions & 14 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Contains endpoint functions for accessing the API"""
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
from http import HTTPStatus
2+
from typing import Any
3+
from urllib.parse import quote
4+
5+
import httpx
6+
7+
from ... import errors
8+
from ...client import AuthenticatedClient, Client
9+
from ...models.connection_response import ConnectionResponse
10+
from ...models.create_connection_request import CreateConnectionRequest
11+
from ...models.error_response import ErrorResponse
12+
from ...models.http_validation_error import HTTPValidationError
13+
from ...types import Response
14+
15+
16+
def _get_kwargs(
17+
graph_id: str,
18+
*,
19+
body: CreateConnectionRequest,
20+
) -> dict[str, Any]:
21+
headers: dict[str, Any] = {}
22+
23+
_kwargs: dict[str, Any] = {
24+
"method": "post",
25+
"url": "/v1/graphs/{graph_id}/connections".format(
26+
graph_id=quote(str(graph_id), safe=""),
27+
),
28+
}
29+
30+
_kwargs["json"] = body.to_dict()
31+
32+
headers["Content-Type"] = "application/json"
33+
34+
_kwargs["headers"] = headers
35+
return _kwargs
36+
37+
38+
def _parse_response(
39+
*, client: AuthenticatedClient | Client, response: httpx.Response
40+
) -> ConnectionResponse | ErrorResponse | HTTPValidationError | None:
41+
if response.status_code == 201:
42+
response_201 = ConnectionResponse.from_dict(response.json())
43+
44+
return response_201
45+
46+
if response.status_code == 400:
47+
response_400 = ErrorResponse.from_dict(response.json())
48+
49+
return response_400
50+
51+
if response.status_code == 403:
52+
response_403 = ErrorResponse.from_dict(response.json())
53+
54+
return response_403
55+
56+
if response.status_code == 409:
57+
response_409 = ErrorResponse.from_dict(response.json())
58+
59+
return response_409
60+
61+
if response.status_code == 422:
62+
response_422 = HTTPValidationError.from_dict(response.json())
63+
64+
return response_422
65+
66+
if response.status_code == 500:
67+
response_500 = ErrorResponse.from_dict(response.json())
68+
69+
return response_500
70+
71+
if client.raise_on_unexpected_status:
72+
raise errors.UnexpectedStatus(response.status_code, response.content)
73+
else:
74+
return None
75+
76+
77+
def _build_response(
78+
*, client: AuthenticatedClient | Client, response: httpx.Response
79+
) -> Response[ConnectionResponse | ErrorResponse | HTTPValidationError]:
80+
return Response(
81+
status_code=HTTPStatus(response.status_code),
82+
content=response.content,
83+
headers=response.headers,
84+
parsed=_parse_response(client=client, response=response),
85+
)
86+
87+
88+
def sync_detailed(
89+
graph_id: str,
90+
*,
91+
client: AuthenticatedClient,
92+
body: CreateConnectionRequest,
93+
) -> Response[ConnectionResponse | ErrorResponse | HTTPValidationError]:
94+
"""Create Connection
95+
96+
Create a new data connection for external system integration.
97+
98+
This endpoint initiates connections to external data sources:
99+
100+
**SEC Connections**:
101+
- Provide entity CIK for automatic filing retrieval
102+
- No authentication needed
103+
- Begins immediate data sync
104+
105+
**QuickBooks Connections**:
106+
- Returns OAuth URL for authorization
107+
- Requires admin permissions in QuickBooks
108+
- Complete with OAuth callback
109+
110+
**Plaid Connections**:
111+
- Returns Plaid Link token
112+
- User completes bank authentication
113+
- Exchange public token for access
114+
115+
Note:
116+
This operation is included - no credit consumption required.
117+
118+
Args:
119+
graph_id (str):
120+
body (CreateConnectionRequest): Request to create a new connection.
121+
122+
Raises:
123+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
124+
httpx.TimeoutException: If the request takes longer than Client.timeout.
125+
126+
Returns:
127+
Response[ConnectionResponse | ErrorResponse | HTTPValidationError]
128+
"""
129+
130+
kwargs = _get_kwargs(
131+
graph_id=graph_id,
132+
body=body,
133+
)
134+
135+
response = client.get_httpx_client().request(
136+
**kwargs,
137+
)
138+
139+
return _build_response(client=client, response=response)
140+
141+
142+
def sync(
143+
graph_id: str,
144+
*,
145+
client: AuthenticatedClient,
146+
body: CreateConnectionRequest,
147+
) -> ConnectionResponse | ErrorResponse | HTTPValidationError | None:
148+
"""Create Connection
149+
150+
Create a new data connection for external system integration.
151+
152+
This endpoint initiates connections to external data sources:
153+
154+
**SEC Connections**:
155+
- Provide entity CIK for automatic filing retrieval
156+
- No authentication needed
157+
- Begins immediate data sync
158+
159+
**QuickBooks Connections**:
160+
- Returns OAuth URL for authorization
161+
- Requires admin permissions in QuickBooks
162+
- Complete with OAuth callback
163+
164+
**Plaid Connections**:
165+
- Returns Plaid Link token
166+
- User completes bank authentication
167+
- Exchange public token for access
168+
169+
Note:
170+
This operation is included - no credit consumption required.
171+
172+
Args:
173+
graph_id (str):
174+
body (CreateConnectionRequest): Request to create a new connection.
175+
176+
Raises:
177+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
178+
httpx.TimeoutException: If the request takes longer than Client.timeout.
179+
180+
Returns:
181+
ConnectionResponse | ErrorResponse | HTTPValidationError
182+
"""
183+
184+
return sync_detailed(
185+
graph_id=graph_id,
186+
client=client,
187+
body=body,
188+
).parsed
189+
190+
191+
async def asyncio_detailed(
192+
graph_id: str,
193+
*,
194+
client: AuthenticatedClient,
195+
body: CreateConnectionRequest,
196+
) -> Response[ConnectionResponse | ErrorResponse | HTTPValidationError]:
197+
"""Create Connection
198+
199+
Create a new data connection for external system integration.
200+
201+
This endpoint initiates connections to external data sources:
202+
203+
**SEC Connections**:
204+
- Provide entity CIK for automatic filing retrieval
205+
- No authentication needed
206+
- Begins immediate data sync
207+
208+
**QuickBooks Connections**:
209+
- Returns OAuth URL for authorization
210+
- Requires admin permissions in QuickBooks
211+
- Complete with OAuth callback
212+
213+
**Plaid Connections**:
214+
- Returns Plaid Link token
215+
- User completes bank authentication
216+
- Exchange public token for access
217+
218+
Note:
219+
This operation is included - no credit consumption required.
220+
221+
Args:
222+
graph_id (str):
223+
body (CreateConnectionRequest): Request to create a new connection.
224+
225+
Raises:
226+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
227+
httpx.TimeoutException: If the request takes longer than Client.timeout.
228+
229+
Returns:
230+
Response[ConnectionResponse | ErrorResponse | HTTPValidationError]
231+
"""
232+
233+
kwargs = _get_kwargs(
234+
graph_id=graph_id,
235+
body=body,
236+
)
237+
238+
response = await client.get_async_httpx_client().request(**kwargs)
239+
240+
return _build_response(client=client, response=response)
241+
242+
243+
async def asyncio(
244+
graph_id: str,
245+
*,
246+
client: AuthenticatedClient,
247+
body: CreateConnectionRequest,
248+
) -> ConnectionResponse | ErrorResponse | HTTPValidationError | None:
249+
"""Create Connection
250+
251+
Create a new data connection for external system integration.
252+
253+
This endpoint initiates connections to external data sources:
254+
255+
**SEC Connections**:
256+
- Provide entity CIK for automatic filing retrieval
257+
- No authentication needed
258+
- Begins immediate data sync
259+
260+
**QuickBooks Connections**:
261+
- Returns OAuth URL for authorization
262+
- Requires admin permissions in QuickBooks
263+
- Complete with OAuth callback
264+
265+
**Plaid Connections**:
266+
- Returns Plaid Link token
267+
- User completes bank authentication
268+
- Exchange public token for access
269+
270+
Note:
271+
This operation is included - no credit consumption required.
272+
273+
Args:
274+
graph_id (str):
275+
body (CreateConnectionRequest): Request to create a new connection.
276+
277+
Raises:
278+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
279+
httpx.TimeoutException: If the request takes longer than Client.timeout.
280+
281+
Returns:
282+
ConnectionResponse | ErrorResponse | HTTPValidationError
283+
"""
284+
285+
return (
286+
await asyncio_detailed(
287+
graph_id=graph_id,
288+
client=client,
289+
body=body,
290+
)
291+
).parsed

0 commit comments

Comments
 (0)