55import jsonschema
66from airbyte_protocol_dataclasses .models import AirbyteStateMessage , ConfiguredAirbyteCatalog
77from fastapi import APIRouter , Depends , HTTPException
8+ from fastapi .responses import JSONResponse
89
910from airbyte_cdk .models import AirbyteStateMessageSerializer
11+ from airbyte_cdk .utils .traced_exception import AirbyteTracedException
1012from airbyte_cdk .sources .declarative .concurrent_declarative_source import (
1113 ConcurrentDeclarativeSource ,
1214)
@@ -98,15 +100,21 @@ def test_read(request: StreamTestReadRequest) -> StreamReadResponse:
98100 )
99101
100102 runner = ManifestCommandProcessor (source )
101- cdk_result = runner .test_read (
102- config_dict ,
103- catalog ,
104- converted_state ,
105- request .record_limit ,
106- request .page_limit ,
107- request .slice_limit ,
108- )
109- return StreamReadResponse .model_validate (asdict (cdk_result ))
103+ try :
104+ cdk_result = runner .test_read (
105+ config_dict ,
106+ catalog ,
107+ converted_state ,
108+ request .record_limit ,
109+ request .page_limit ,
110+ request .slice_limit ,
111+ )
112+ return StreamReadResponse .model_validate (asdict (cdk_result ))
113+ except Exception as exc :
114+ error = AirbyteTracedException .from_exception (
115+ exc , message = f"Error reading stream: { str (exc )} "
116+ )
117+ raise HTTPException (status_code = 400 , detail = error .message )
110118
111119
112120@router .post ("/check" , operation_id = "check" )
@@ -119,10 +127,16 @@ def check(request: CheckRequest) -> CheckResponse:
119127 project_id = request .context .project_id ,
120128 )
121129
122- source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
123- runner = ManifestCommandProcessor (source )
124- success , message = runner .check_connection (request .config .model_dump ())
125- return CheckResponse (success = success , message = message )
130+ try :
131+ source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
132+ runner = ManifestCommandProcessor (source )
133+ success , message = runner .check_connection (request .config .model_dump ())
134+ return CheckResponse (success = success , message = message )
135+ except Exception as exc :
136+ error = AirbyteTracedException .from_exception (
137+ exc , message = f"Error checking connection: { str (exc )} "
138+ )
139+ raise HTTPException (status_code = 400 , detail = error .message )
126140
127141
128142@router .post ("/discover" , operation_id = "discover" )
@@ -135,12 +149,21 @@ def discover(request: DiscoverRequest) -> DiscoverResponse:
135149 project_id = request .context .project_id ,
136150 )
137151
138- source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
139- runner = ManifestCommandProcessor (source )
140- catalog = runner .discover (request .config .model_dump ())
141- if catalog is None :
142- raise HTTPException (status_code = 422 , detail = "Connector did not return a discovered catalog" )
143- return DiscoverResponse (catalog = catalog )
152+ try :
153+ source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
154+ runner = ManifestCommandProcessor (source )
155+ catalog = runner .discover (request .config .model_dump ())
156+ if catalog is None :
157+ raise HTTPException (status_code = 422 , detail = "Connector did not return a discovered catalog" )
158+ return DiscoverResponse (catalog = catalog )
159+ except HTTPException :
160+ # Re-raise HTTPExceptions as-is (like the catalog None check above)
161+ raise
162+ except Exception as exc :
163+ error = AirbyteTracedException .from_exception (
164+ exc , message = f"Error discovering streams: { str (exc )} "
165+ )
166+ raise HTTPException (status_code = 400 , detail = error .message )
144167
145168
146169@router .post ("/resolve" , operation_id = "resolve" )
@@ -153,8 +176,14 @@ def resolve(request: ResolveRequest) -> ManifestResponse:
153176 project_id = request .context .project_id ,
154177 )
155178
156- source = safe_build_source (request .manifest .model_dump (), {})
157- return ManifestResponse (manifest = Manifest (** source .resolved_manifest ))
179+ try :
180+ source = safe_build_source (request .manifest .model_dump (), {})
181+ return ManifestResponse (manifest = Manifest (** source .resolved_manifest ))
182+ except Exception as exc :
183+ error = AirbyteTracedException .from_exception (
184+ exc , message = f"Error resolving manifest: { str (exc )} "
185+ )
186+ raise HTTPException (status_code = 400 , detail = error .message )
158187
159188
160189@router .post ("/full_resolve" , operation_id = "fullResolve" )
@@ -171,21 +200,27 @@ def full_resolve(request: FullResolveRequest) -> ManifestResponse:
171200 project_id = request .context .project_id ,
172201 )
173202
174- source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
175- manifest = {** source .resolved_manifest }
176- streams = manifest .get ("streams" , [])
177- for stream in streams :
178- stream ["dynamic_stream_name" ] = None
179-
180- mapped_streams : Dict [str , List [Dict [str , Any ]]] = {}
181- for stream in source .dynamic_streams :
182- generated_streams = mapped_streams .setdefault (stream ["dynamic_stream_name" ], [])
183-
184- if len (generated_streams ) < request .stream_limit :
185- generated_streams += [stream ]
186-
187- for generated_streams_list in mapped_streams .values ():
188- streams .extend (generated_streams_list )
189-
190- manifest ["streams" ] = streams
191- return ManifestResponse (manifest = Manifest (** manifest ))
203+ try :
204+ source = safe_build_source (request .manifest .model_dump (), request .config .model_dump ())
205+ manifest = {** source .resolved_manifest }
206+ streams = manifest .get ("streams" , [])
207+ for stream in streams :
208+ stream ["dynamic_stream_name" ] = None
209+
210+ mapped_streams : Dict [str , List [Dict [str , Any ]]] = {}
211+ for stream in source .dynamic_streams :
212+ generated_streams = mapped_streams .setdefault (stream ["dynamic_stream_name" ], [])
213+
214+ if len (generated_streams ) < request .stream_limit :
215+ generated_streams += [stream ]
216+
217+ for generated_streams_list in mapped_streams .values ():
218+ streams .extend (generated_streams_list )
219+
220+ manifest ["streams" ] = streams
221+ return ManifestResponse (manifest = Manifest (** manifest ))
222+ except Exception as exc :
223+ error = AirbyteTracedException .from_exception (
224+ exc , message = f"Error full resolving manifest: { str (exc )} "
225+ )
226+ raise HTTPException (status_code = 400 , detail = error .message )
0 commit comments