From 5005f203b8d6b1d577cdf094b83886bd1fc817a2 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Mon, 21 Feb 2022 04:13:04 +0500 Subject: [PATCH 1/3] fix(stp): return json for webout --- api/public/swagger.yaml | 21 +++++++++++++------- api/src/controllers/code.ts | 9 ++------- api/src/controllers/drive.ts | 2 +- api/src/controllers/internal/Execution.ts | 3 ++- api/src/controllers/stp.ts | 24 ++++++++++++++--------- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index ccb2f70..80eca83 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -92,6 +92,10 @@ components: - clientSecret type: object additionalProperties: false + IRecordOfAny: + properties: {} + type: object + additionalProperties: {} LogLine: properties: line: @@ -110,7 +114,11 @@ components: status: type: string _webout: - type: string + anyOf: + - + type: string + - + $ref: '#/components/schemas/IRecordOfAny' log: items: $ref: '#/components/schemas/LogLine' @@ -539,9 +547,7 @@ paths: content: application/json: schema: - anyOf: - - {$ref: '#/components/schemas/ExecuteReturnJsonResponse'} - - {type: string, format: byte} + $ref: '#/components/schemas/ExecuteReturnJsonResponse' description: 'Execute SAS code.' summary: 'Run SAS Code and returns log' tags: @@ -630,6 +636,7 @@ paths: bearerAuth: [] parameters: - + description: 'Location of SAS program' in: query name: filePath required: true @@ -1068,6 +1075,7 @@ paths: bearerAuth: [] parameters: - + description: 'Location of SAS program' in: query name: _program required: true @@ -1082,9 +1090,7 @@ paths: content: application/json: schema: - anyOf: - - {$ref: '#/components/schemas/ExecuteReturnJsonResponse'} - - {type: string, format: byte} + $ref: '#/components/schemas/ExecuteReturnJsonResponse' examples: 'Example 1': value: {status: success, _webout: 'webout content', log: [], httpHeaders: {Content-type: application/zip, Cache-Control: 'public, max-age=1000'}} @@ -1097,6 +1103,7 @@ paths: bearerAuth: [] parameters: - + description: 'Location of SAS program' in: query name: _program required: false diff --git a/api/src/controllers/code.ts b/api/src/controllers/code.ts index 85e3d54..a2e7bd3 100644 --- a/api/src/controllers/code.ts +++ b/api/src/controllers/code.ts @@ -25,7 +25,7 @@ export class CodeController { public async executeSASCode( @Request() request: express.Request, @Body() body: ExecuteSASCodePayload - ): Promise { + ): Promise { return executeSASCode(request, body) } } @@ -41,14 +41,9 @@ const executeSASCode = async (req: any, { code }: ExecuteSASCodePayload) => { true )) as ExecuteReturnJson - if (webout instanceof Buffer) { - ;(req as any).sasHeaders = httpHeaders - return webout - } - return { status: 'success', - _webout: webout, + _webout: webout as string, log: parseLogToArray(log), httpHeaders } diff --git a/api/src/controllers/drive.ts b/api/src/controllers/drive.ts index bf4b494..dea159c 100644 --- a/api/src/controllers/drive.ts +++ b/api/src/controllers/drive.ts @@ -90,7 +90,7 @@ export class DriveController { /** * @summary Get file from SASjs Drive - * @query filePath Location of SAS program + * @param filePath Location of SAS program * @example filePath "/Public/somefolder/some.file" */ @Example({ diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index 6856923..f3eebf1 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -148,7 +148,8 @@ ${program}` ? await readFile(headersPath) : '' const httpHeaders: HTTPHeaders = extractHeaders(headersContent) - const fileResponse: boolean = httpHeaders.hasOwnProperty('content-type') + const fileResponse: boolean = + httpHeaders.hasOwnProperty('content-type') && !returnJson const webout = (await fileExists(weboutPath)) ? fileResponse diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index 2335e5e..5cf67d1 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -33,9 +33,13 @@ interface ExecuteReturnJsonPayload { */ _program?: string } + +interface IRecordOfAny { + [key: string]: any +} export interface ExecuteReturnJsonResponse { status: string - _webout: string + _webout: string | IRecordOfAny log: LogLine[] message?: string httpHeaders: HTTPHeaders @@ -52,7 +56,7 @@ export class STPController { * Any files provided are placed into the session and * corresponding _WEBIN_XXX variables are created. * @summary Execute Stored Program, return raw content - * @query _program Location of SAS program + * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file" */ @Get('/execute') @@ -70,7 +74,7 @@ export class STPController { * Any files provided are placed into the session and * corresponding _WEBIN_XXX variables are created. * @summary Execute Stored Program, return JSON - * @query _program Location of SAS program + * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file" */ @Example({ @@ -87,7 +91,7 @@ export class STPController { @Request() request: express.Request, @Body() body?: ExecuteReturnJsonPayload, @Query() _program?: string - ): Promise { + ): Promise { const program = _program ?? body?._program return executeReturnJson(request, program!) } @@ -131,7 +135,7 @@ const executeReturnRaw = async ( const executeReturnJson = async ( req: any, _program: string -): Promise => { +): Promise => { const sasCodePath = path .join(getTmpFilesFolderPath(), _program) @@ -149,14 +153,16 @@ const executeReturnJson = async ( true )) as ExecuteReturnJson - if (webout instanceof Buffer) { - ;(req as any).sasHeaders = httpHeaders - return webout + let weboutRes: string | IRecordOfAny = webout + if (httpHeaders['content-type']?.toLowerCase() === 'application/json') { + try { + weboutRes = JSON.parse(webout as string) + } catch (_) {} } return { status: 'success', - _webout: webout, + _webout: weboutRes, log: parseLogToArray(log), httpHeaders } From 7312763339d6769826328561e2c8d11bbfc0c9f4 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Tue, 22 Feb 2022 19:35:58 +0000 Subject: [PATCH 2/3] fix: updating docs --- api/src/controllers/stp.ts | 43 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index 5cf67d1..28dd288 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -50,12 +50,22 @@ export interface ExecuteReturnJsonResponse { @Tags('STP') export class STPController { /** - * Trigger a SAS program using it's location in the _program parameter. - * Enable debugging using the _debug parameter. + * Trigger a SAS program using it's location in the _program URL parameter. + * Enable debugging using the _debug URL parameter. Setting _debug=131 will + * cause the log to be streamed in the output. + * * Additional URL parameters are turned into SAS macro variables. - * Any files provided are placed into the session and - * corresponding _WEBIN_XXX variables are created. - * @summary Execute Stored Program, return raw content + * + * Any files provided in the request body are placed into the SAS session with + * corresponding _WEBIN_XXX variables created. + * + * The response headers can be adjusted using the mfs_httpheader() macro. Any + * file type can be returned, including binary files such as zip or xls. + * + * This behaviour differs for POST requests, in which case the reponse is + * always JSON. + * + * @summary Execute Stored Program, return raw _webout content. * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file" */ @@ -68,11 +78,26 @@ export class STPController { } /** - * Trigger a SAS program using it's location in the _program parameter. - * Enable debugging using the _debug parameter. + * Trigger a SAS program using it's location in the _program URL parameter. + * Enable debugging using the _debug URL parameter. In any case, the log is + * always returned in the log object. + * * Additional URL parameters are turned into SAS macro variables. - * Any files provided are placed into the session and - * corresponding _WEBIN_XXX variables are created. + * + * Any files provided in the request body are placed into the SAS session with + * corresponding _WEBIN_XXX variables created. + * + * The response will be a JSON object with the following root attributes: log, + * webout, headers. + * + * The webout will be a nested JSON object ONLY if the response-header + * contains a content-type of application/json AND it is valid JSON. + * Otherwise it will be a stringified version of the webout content. + * + * Response headers from the mfs_httpheader macro are simply listed in the + * headers object, for POST requests they have no effect on the actual + * response header. + * * @summary Execute Stored Program, return JSON * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file" From da375b808662ac4c690aea8adcf2a563bda7d1a6 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sat, 26 Feb 2022 02:41:55 +0500 Subject: [PATCH 3/3] chore: lint fixes --- api/src/controllers/stp.ts | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/api/src/controllers/stp.ts b/api/src/controllers/stp.ts index 28dd288..c29b432 100644 --- a/api/src/controllers/stp.ts +++ b/api/src/controllers/stp.ts @@ -53,18 +53,18 @@ export class STPController { * Trigger a SAS program using it's location in the _program URL parameter. * Enable debugging using the _debug URL parameter. Setting _debug=131 will * cause the log to be streamed in the output. - * + * * Additional URL parameters are turned into SAS macro variables. - * + * * Any files provided in the request body are placed into the SAS session with * corresponding _WEBIN_XXX variables created. - * + * * The response headers can be adjusted using the mfs_httpheader() macro. Any - * file type can be returned, including binary files such as zip or xls. - * - * This behaviour differs for POST requests, in which case the reponse is + * file type can be returned, including binary files such as zip or xls. + * + * This behaviour differs for POST requests, in which case the reponse is * always JSON. - * + * * @summary Execute Stored Program, return raw _webout content. * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file" @@ -81,23 +81,23 @@ export class STPController { * Trigger a SAS program using it's location in the _program URL parameter. * Enable debugging using the _debug URL parameter. In any case, the log is * always returned in the log object. - * + * * Additional URL parameters are turned into SAS macro variables. - * + * * Any files provided in the request body are placed into the SAS session with * corresponding _WEBIN_XXX variables created. - * + * * The response will be a JSON object with the following root attributes: log, - * webout, headers. - * - * The webout will be a nested JSON object ONLY if the response-header - * contains a content-type of application/json AND it is valid JSON. + * webout, headers. + * + * The webout will be a nested JSON object ONLY if the response-header + * contains a content-type of application/json AND it is valid JSON. * Otherwise it will be a stringified version of the webout content. - * - * Response headers from the mfs_httpheader macro are simply listed in the - * headers object, for POST requests they have no effect on the actual - * response header. - * + * + * Response headers from the mfs_httpheader macro are simply listed in the + * headers object, for POST requests they have no effect on the actual + * response header. + * * @summary Execute Stored Program, return JSON * @param _program Location of SAS program * @example _program "/Public/somefolder/some.file"