1- import {
2- fetchAtlassian ,
3- getAtlassianCredentials ,
4- } from '../utils/transport.util.js' ;
1+ import atlassianApiService from '../services/vendor.atlassian.api.service.js' ;
52import { Logger } from '../utils/logger.util.js' ;
63import { handleControllerError } from '../utils/error-handler.util.js' ;
74import { ControllerResponse } from '../types/common.types.js' ;
@@ -10,15 +7,21 @@ import {
107 RequestWithBodyArgsType ,
118} from '../tools/atlassian.api.types.js' ;
129import { applyJqFilter , toOutputString } from '../utils/jq.util.js' ;
13- import { createAuthMissingError } from '../utils/error.util.js' ;
14-
15- // Logger instance for this module
16- const logger = Logger . forContext ( 'controllers/atlassian.api.controller.ts' ) ;
1710
1811/**
19- * Supported HTTP methods for API requests
12+ * @namespace AtlassianApiController
13+ * @description Controller for handling generic Jira API requests.
14+ * Orchestrates calls to the Atlassian API service and handles
15+ * response formatting (JQ filtering, TOON/JSON output).
16+ *
17+ * Architecture:
18+ * - Tool → Controller (this file) → Service → Transport
19+ * - Controller handles: JQ filtering, output formatting, error context
20+ * - Service handles: Credentials, path normalization, API calls
2021 */
21- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' ;
22+
23+ // Logger instance for this module
24+ const logger = Logger . forContext ( 'controllers/atlassian.api.controller.ts' ) ;
2225
2326/**
2427 * Output format type
@@ -42,45 +45,15 @@ interface RequestWithBodyOptions extends BaseRequestOptions {
4245 body ?: Record < string , unknown > ;
4346}
4447
45- /**
46- * Normalizes the API path by ensuring it starts with /
47- * @param path - The raw path provided by the user
48- * @returns Normalized path
49- */
50- function normalizePath ( path : string ) : string {
51- let normalizedPath = path ;
52- if ( ! normalizedPath . startsWith ( '/' ) ) {
53- normalizedPath = '/' + normalizedPath ;
54- }
55- return normalizedPath ;
56- }
57-
58- /**
59- * Appends query parameters to a path
60- * @param path - The base path
61- * @param queryParams - Optional query parameters
62- * @returns Path with query string appended
63- */
64- function appendQueryParams (
65- path : string ,
66- queryParams ?: Record < string , string > ,
67- ) : string {
68- if ( ! queryParams || Object . keys ( queryParams ) . length === 0 ) {
69- return path ;
70- }
71- const queryString = new URLSearchParams ( queryParams ) . toString ( ) ;
72- return path + ( path . includes ( '?' ) ? '&' : '?' ) + queryString ;
73- }
74-
7548/**
7649 * Shared handler for all HTTP methods
7750 *
7851 * @param method - HTTP method (GET, POST, PUT, PATCH, DELETE)
7952 * @param options - Request options including path, queryParams, body (for non-GET), and jq filter
80- * @returns Promise with raw JSON response (optionally filtered)
53+ * @returns Promise with formatted response content
8154 */
8255async function handleRequest (
83- method : HttpMethod ,
56+ method : 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' ,
8457 options : RequestWithBodyOptions ,
8558) : Promise < ControllerResponse > {
8659 const methodLogger = logger . forMethod ( `handle${ method } ` ) ;
@@ -91,46 +64,28 @@ async function handleRequest(
9164 ...( options . body && { bodyKeys : Object . keys ( options . body ) } ) ,
9265 } ) ;
9366
94- // Get credentials
95- const credentials = getAtlassianCredentials ( ) ;
96- if ( ! credentials ) {
97- throw createAuthMissingError ( ) ;
98- }
99-
100- // Normalize path and append query params
101- let path = normalizePath ( options . path ) ;
102- path = appendQueryParams ( path , options . queryParams ) ;
103-
104- methodLogger . debug ( `${ method } ing: ${ path } ` ) ;
105-
106- const fetchOptions : {
107- method : 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' ;
108- body ?: unknown ;
109- } = {
110- method,
111- } ;
112-
113- // Add body for methods that support it
114- if ( options . body && [ 'POST' , 'PUT' , 'PATCH' ] . includes ( method ) ) {
115- fetchOptions . body = options . body ;
116- }
117-
118- const response = await fetchAtlassian < unknown > (
119- credentials ,
120- path ,
121- fetchOptions ,
67+ // Call the service layer (returns TransportResponse with data and rawResponsePath)
68+ const response = await atlassianApiService . request < unknown > (
69+ options . path ,
70+ {
71+ method,
72+ queryParams : options . queryParams ,
73+ body : options . body ,
74+ } ,
12275 ) ;
123- methodLogger . debug ( 'Successfully received response' ) ;
76+
77+ methodLogger . debug ( 'Successfully received response from service' ) ;
12478
12579 // Apply JQ filter if provided, otherwise return raw data
126- const result = applyJqFilter ( response , options . jq ) ;
80+ const result = applyJqFilter ( response . data , options . jq ) ;
12781
12882 // Convert to output format (TOON by default, JSON if requested)
12983 const useToon = options . outputFormat !== 'json' ;
13084 const content = await toOutputString ( result , useToon ) ;
13185
13286 return {
13387 content,
88+ rawResponsePath : response . rawResponsePath ,
13489 } ;
13590 } catch ( error ) {
13691 throw handleControllerError ( error , {
0 commit comments