mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-05 19:50:06 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50710ee1df | ||
| 85e5ade93a | |||
| 4a61fb8f7f | |||
| 5347aeba09 | |||
|
|
7ac7c5e52b | ||
| 5098342dfe | |||
| c69be8ffc3 | |||
| 69999d8e8b |
@@ -1,4 +1,4 @@
|
|||||||
import { isUrl } from './utils'
|
import { isUrl, getValidJson, parseSasViyaDebugResponse } from './utils'
|
||||||
import { UploadFile } from './types/UploadFile'
|
import { UploadFile } from './types/UploadFile'
|
||||||
import { ErrorResponse, LoginRequiredError } from './types/errors'
|
import { ErrorResponse, LoginRequiredError } from './types/errors'
|
||||||
import { RequestClient } from './request/RequestClient'
|
import { RequestClient } from './request/RequestClient'
|
||||||
@@ -63,13 +63,28 @@ export class FileUploader {
|
|||||||
|
|
||||||
return this.requestClient
|
return this.requestClient
|
||||||
.post(uploadUrl, formData, undefined, 'application/json', headers)
|
.post(uploadUrl, formData, undefined, 'application/json', headers)
|
||||||
.then((res) => {
|
.then(async (res) => {
|
||||||
let result
|
// for web approach on Viya
|
||||||
|
if (
|
||||||
|
this.sasjsConfig.debug &&
|
||||||
|
(this.sasjsConfig.useComputeApi === null ||
|
||||||
|
this.sasjsConfig.useComputeApi === undefined) &&
|
||||||
|
this.sasjsConfig.serverType === ServerType.SasViya
|
||||||
|
) {
|
||||||
|
const jsonResponse = await parseSasViyaDebugResponse(
|
||||||
|
res.result as string,
|
||||||
|
this.requestClient,
|
||||||
|
this.sasjsConfig.serverUrl
|
||||||
|
)
|
||||||
|
return typeof jsonResponse === 'string'
|
||||||
|
? getValidJson(jsonResponse)
|
||||||
|
: jsonResponse
|
||||||
|
}
|
||||||
|
|
||||||
result =
|
return typeof res.result === 'string'
|
||||||
typeof res.result === 'string' ? JSON.parse(res.result) : res.result
|
? getValidJson(res.result)
|
||||||
|
: res.result
|
||||||
|
|
||||||
return result
|
|
||||||
//TODO: append to SASjs requests
|
//TODO: append to SASjs requests
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
|
|||||||
19
src/SASjs.ts
19
src/SASjs.ts
@@ -544,11 +544,22 @@ export default class SASjs {
|
|||||||
* Process). Is prepended at runtime with the value of `appLoc`.
|
* Process). Is prepended at runtime with the value of `appLoc`.
|
||||||
* @param files - array of files to be uploaded, including File object and file name.
|
* @param files - array of files to be uploaded, including File object and file name.
|
||||||
* @param params - request URL parameters.
|
* @param params - request URL parameters.
|
||||||
|
* @param overrideSasjsConfig - object to override existing config (optional)
|
||||||
*/
|
*/
|
||||||
public uploadFile(sasJob: string, files: UploadFile[], params: any) {
|
public uploadFile(
|
||||||
const fileUploader =
|
sasJob: string,
|
||||||
this.fileUploader ||
|
files: UploadFile[],
|
||||||
new FileUploader(this.sasjsConfig, this.jobsPath, this.requestClient!)
|
params: any,
|
||||||
|
overrideSasjsConfig?: any
|
||||||
|
) {
|
||||||
|
const fileUploader = overrideSasjsConfig
|
||||||
|
? new FileUploader(
|
||||||
|
{ ...this.sasjsConfig, ...overrideSasjsConfig },
|
||||||
|
this.jobsPath,
|
||||||
|
this.requestClient!
|
||||||
|
)
|
||||||
|
: this.fileUploader ||
|
||||||
|
new FileUploader(this.sasjsConfig, this.jobsPath, this.requestClient!)
|
||||||
|
|
||||||
return fileUploader.uploadFile(sasJob, files, params)
|
return fileUploader.uploadFile(sasJob, files, params)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
|||||||
import { generateTableUploadForm } from '../file/generateTableUploadForm'
|
import { generateTableUploadForm } from '../file/generateTableUploadForm'
|
||||||
import { RequestClient } from '../request/RequestClient'
|
import { RequestClient } from '../request/RequestClient'
|
||||||
import { SASViyaApiClient } from '../SASViyaApiClient'
|
import { SASViyaApiClient } from '../SASViyaApiClient'
|
||||||
import { isRelativePath, isValidJson } from '../utils'
|
import {
|
||||||
|
isRelativePath,
|
||||||
|
getValidJson,
|
||||||
|
parseSasViyaDebugResponse
|
||||||
|
} from '../utils'
|
||||||
import { BaseJobExecutor } from './JobExecutor'
|
import { BaseJobExecutor } from './JobExecutor'
|
||||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||||
|
|
||||||
@@ -95,8 +99,10 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|||||||
this.requestClient!.post(apiUrl, formData, undefined)
|
this.requestClient!.post(apiUrl, formData, undefined)
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||||
const jsonResponse = await this.parseSasViyaDebugResponse(
|
const jsonResponse = await parseSasViyaDebugResponse(
|
||||||
res.result as string
|
res.result as string,
|
||||||
|
this.requestClient,
|
||||||
|
this.serverUrl
|
||||||
)
|
)
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
resolve(jsonResponse)
|
resolve(jsonResponse)
|
||||||
@@ -109,11 +115,11 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidJson(jsonResponse)
|
getValidJson(jsonResponse)
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
resolve(res.result)
|
resolve(res.result)
|
||||||
}
|
}
|
||||||
isValidJson(res.result as string)
|
getValidJson(res.result as string)
|
||||||
this.appendRequest(res, sasJob, config.debug)
|
this.appendRequest(res, sasJob, config.debug)
|
||||||
resolve(res.result)
|
resolve(res.result)
|
||||||
})
|
})
|
||||||
@@ -151,20 +157,6 @@ export class WebJobExecutor extends BaseJobExecutor {
|
|||||||
return requestPromise
|
return requestPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseSasViyaDebugResponse = async (response: string) => {
|
|
||||||
const iframeStart = response.split(
|
|
||||||
'<iframe style="width: 99%; height: 500px" src="'
|
|
||||||
)[1]
|
|
||||||
const jsonUrl = iframeStart ? iframeStart.split('"></iframe>')[0] : null
|
|
||||||
if (!jsonUrl) {
|
|
||||||
throw new Error('Unable to find webout file URL.')
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.requestClient
|
|
||||||
.get(this.serverUrl + jsonUrl, undefined)
|
|
||||||
.then((res) => res.result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getJobUri(sasJob: string) {
|
private async getJobUri(sasJob: string) {
|
||||||
if (!this.sasViyaApiClient) return ''
|
if (!this.sasViyaApiClient) return ''
|
||||||
let uri = ''
|
let uri = ''
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||||
import { prefixMessage } from '@sasjs/utils/error'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
import { SAS9AuthError } from '../types/errors/SAS9AuthError'
|
import { SAS9AuthError } from '../types/errors/SAS9AuthError'
|
||||||
import { isValidJson } from '../utils'
|
import { getValidJson } from '../utils'
|
||||||
|
|
||||||
export interface HttpClient {
|
export interface HttpClient {
|
||||||
get<T>(
|
get<T>(
|
||||||
@@ -434,7 +434,7 @@ export class RequestClient implements HttpClient {
|
|||||||
throw new Error('Valid JSON could not be extracted from response.')
|
throw new Error('Valid JSON could not be extracted from response.')
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonResponse = isValidJson(weboutResponse)
|
const jsonResponse = getValidJson(weboutResponse)
|
||||||
parsedResponse = jsonResponse
|
parsedResponse = jsonResponse
|
||||||
} catch {
|
} catch {
|
||||||
parsedResponse = response.data
|
parsedResponse = response.data
|
||||||
|
|||||||
41
src/test/utils/getValidJson.spec.ts
Normal file
41
src/test/utils/getValidJson.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { getValidJson } from '../../utils'
|
||||||
|
|
||||||
|
describe('jsonValidator', () => {
|
||||||
|
it('should not throw an error with a valid json', () => {
|
||||||
|
const json = {
|
||||||
|
test: 'test'
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(getValidJson(json)).toBe(json)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not throw an error with a valid json string', () => {
|
||||||
|
const json = {
|
||||||
|
test: 'test'
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(getValidJson(JSON.stringify(json))).toStrictEqual(json)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error with an invalid json', () => {
|
||||||
|
const json = `{\"test\":\"test\"\"test2\":\"test\"}`
|
||||||
|
let errorThrown = false
|
||||||
|
try {
|
||||||
|
getValidJson(json)
|
||||||
|
} catch (error) {
|
||||||
|
errorThrown = true
|
||||||
|
}
|
||||||
|
expect(errorThrown).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error when an array is passed', () => {
|
||||||
|
const array = ['hello', 'world']
|
||||||
|
let errorThrown = false
|
||||||
|
try {
|
||||||
|
getValidJson(array)
|
||||||
|
} catch (error) {
|
||||||
|
errorThrown = true
|
||||||
|
}
|
||||||
|
expect(errorThrown).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import { isValidJson } from '../../utils'
|
|
||||||
|
|
||||||
describe('jsonValidator', () => {
|
|
||||||
it('should not throw an error with an valid json', () => {
|
|
||||||
const json = {
|
|
||||||
test: 'test'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(isValidJson(json)).toBe(json)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not throw an error with an valid json string', () => {
|
|
||||||
const json = {
|
|
||||||
test: 'test'
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(isValidJson(JSON.stringify(json))).toStrictEqual(json)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should throw an error with an invalid json', () => {
|
|
||||||
const json = `{\"test\":\"test\"\"test2\":\"test\"}`
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
try {
|
|
||||||
isValidJson(json)
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error()
|
|
||||||
}
|
|
||||||
}).toThrowError
|
|
||||||
})
|
|
||||||
})
|
|
||||||
16
src/utils/getValidJson.ts
Normal file
16
src/utils/getValidJson.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* if string passed then parse the string to json else if throw error for all other types unless it is not a valid json object.
|
||||||
|
* @param str - string to check.
|
||||||
|
*/
|
||||||
|
export const getValidJson = (str: string | object) => {
|
||||||
|
try {
|
||||||
|
if (Array.isArray(str)) {
|
||||||
|
throw new Error('Can not parse array object to json.')
|
||||||
|
}
|
||||||
|
if (typeof str === 'object') return str
|
||||||
|
|
||||||
|
return JSON.parse(str)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Invalid JSON response.')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,4 +12,5 @@ export * from './serialize'
|
|||||||
export * from './splitChunks'
|
export * from './splitChunks'
|
||||||
export * from './parseWeboutResponse'
|
export * from './parseWeboutResponse'
|
||||||
export * from './fetchLogByChunks'
|
export * from './fetchLogByChunks'
|
||||||
export * from './isValidJson'
|
export * from './getValidJson'
|
||||||
|
export * from './parseViyaDebugResponse'
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Checks if string is in valid JSON format else throw error.
|
|
||||||
* @param str - string to check.
|
|
||||||
*/
|
|
||||||
export const isValidJson = (str: string | object) => {
|
|
||||||
try {
|
|
||||||
if (typeof str === 'object') return str
|
|
||||||
|
|
||||||
return JSON.parse(str)
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('Invalid JSON response.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/utils/parseViyaDebugResponse.ts
Normal file
29
src/utils/parseViyaDebugResponse.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { RequestClient } from '../request/RequestClient'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When querying a Viya job using the Web approach (as opposed to using the APIs) with _DEBUG enabled,
|
||||||
|
* the first response contains the log with the content in an iframe. Therefore when debug is enabled,
|
||||||
|
* and the serverType is VIYA, and useComputeApi is null (WEB), we call this function to extract the
|
||||||
|
* (_webout) content from the iframe.
|
||||||
|
* @param response - first response from viya job
|
||||||
|
* @param requestClient
|
||||||
|
* @param serverUrl
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const parseSasViyaDebugResponse = async (
|
||||||
|
response: string,
|
||||||
|
requestClient: RequestClient,
|
||||||
|
serverUrl: string
|
||||||
|
) => {
|
||||||
|
const iframeStart = response.split(
|
||||||
|
'<iframe style="width: 99%; height: 500px" src="'
|
||||||
|
)[1]
|
||||||
|
const jsonUrl = iframeStart ? iframeStart.split('"></iframe>')[0] : null
|
||||||
|
if (!jsonUrl) {
|
||||||
|
throw new Error('Unable to find webout file URL.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestClient
|
||||||
|
.get(serverUrl + jsonUrl, undefined)
|
||||||
|
.then((res) => res.result)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user