mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 17:34:34 +00:00
Compare commits
29 Commits
v2.10.2
...
debug-sasj
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c6198ae25 | |||
| 73f50c0435 | |||
| 5ee57f3d07 | |||
|
|
ed72c5c48c | ||
| 146b0715bf | |||
| dfc1d567a5 | |||
| 779200f5fc | |||
| cf4c4cfca9 | |||
|
|
ad4eead4ca | ||
|
|
aa9383a483 | ||
|
|
ba105f609c | ||
|
|
b831b93133 | ||
|
|
0c3aab673a | ||
| 33e7564e8f | |||
| 77c4c473c1 | |||
| 47ff1a2293 | |||
|
|
ffae344476 | ||
|
|
4f62cd0148 | ||
| bd92c1925e | |||
|
|
6c29d7823b | ||
| 3c9f133374 | |||
| e72195ca5d | |||
| 3e7ddf59b4 | |||
| cd67fb38dc | |||
| 78149e6c54 | |||
| 63e220c5be | |||
| 8464e506e0 | |||
| 0bc69401e5 | |||
| 47fe7686cb |
@@ -1,4 +1,5 @@
|
||||
sasjs-tests/
|
||||
docs/
|
||||
.github/
|
||||
CONTRIBUTING.md
|
||||
*.md
|
||||
*.spec.ts
|
||||
|
||||
16
checkNodeVersion.js
Normal file
16
checkNodeVersion.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const result = process.versions
|
||||
if (result && result.node) {
|
||||
if (parseInt(result.node) < 14) {
|
||||
console.log(
|
||||
'\x1b[31m%s\x1b[0m',
|
||||
`❌ Process failed due to Node Version,\nPlease install and use Node Version >= 14\nYour current Node Version is: ${result.node}`
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'\x1b[31m%s\x1b[0m',
|
||||
'Something went wrong while checking Node version'
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
18429
package-lock.json
generated
18429
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -3,8 +3,10 @@
|
||||
"description": "JavaScript adapter for SAS",
|
||||
"homepage": "https://adapter.sasjs.io",
|
||||
"scripts": {
|
||||
"preinstall": "node checkNodeVersion",
|
||||
"prebuild": "node checkNodeVersion",
|
||||
"build": "rimraf build && rimraf node && mkdir node && copyfiles -u 1 \"./src/**/*\" ./node && webpack && rimraf build/src && rimraf node",
|
||||
"package:lib": "npm run build && copyfiles ./package.json build && cd build && npm version \"5.0.0\" && npm pack",
|
||||
"package:lib": "npm run build && copyfiles ./package.json ./checkNodeVersion.js build && cd build && npm version \"5.0.0\" && npm pack",
|
||||
"publish:lib": "npm run build && cd build && npm publish",
|
||||
"lint:fix": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}\" && npx prettier --write \"sasjs-tests/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}\"",
|
||||
"lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}\" && npx prettier --check \"sasjs-tests/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,json,yml,md,graphql}\"",
|
||||
@@ -40,41 +42,38 @@
|
||||
"devDependencies": {
|
||||
"@types/axios": "^0.14.0",
|
||||
"@types/form-data": "^2.5.0",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/mime": "^2.0.3",
|
||||
"@types/tough-cookie": "^4.0.1",
|
||||
"copyfiles": "^2.4.1",
|
||||
"cp": "^0.2.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"jest": "^27.1.0",
|
||||
"jest-extended": "^0.11.5",
|
||||
"node-polyfill-webpack-plugin": "^1.1.4",
|
||||
"path": "^0.12.7",
|
||||
"process": "^0.11.10",
|
||||
"rimraf": "^3.0.2",
|
||||
"semantic-release": "^17.4.4",
|
||||
"terser-webpack-plugin": "^5.1.4",
|
||||
"semantic-release": "^17.4.7",
|
||||
"terser-webpack-plugin": "^5.2.0",
|
||||
"ts-jest": "^27.0.3",
|
||||
"ts-loader": "^9.2.2",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typedoc": "^0.21.4",
|
||||
"typedoc": "^0.21.9",
|
||||
"typedoc-neo-theme": "^1.1.1",
|
||||
"typedoc-plugin-external-module-name": "^4.0.6",
|
||||
"typescript": "^4.3.5",
|
||||
"typescript": "4.3.5",
|
||||
"webpack": "^5.44.0",
|
||||
"webpack-cli": "^4.7.2"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@sasjs/utils": "^2.27.1",
|
||||
"@sasjs/utils": "^2.30.0",
|
||||
"axios": "^0.21.1",
|
||||
"axios-cookiejar-support": "^1.0.1",
|
||||
"form-data": "^4.0.0",
|
||||
"https": "^1.0.0",
|
||||
"tough-cookie": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=15"
|
||||
}
|
||||
}
|
||||
|
||||
30314
sasjs-tests/package-lock.json
generated
30314
sasjs-tests/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"update:adapter": "cd .. && npm run package:lib && cd sasjs-tests && npm i ../build/sasjs-adapter-5.0.0.tgz",
|
||||
"deploy:tests": "rsync -avhe ssh ./build/* --delete $SSH_ACCOUNT:$DEPLOY_PATH || npm run deploy:tests-win",
|
||||
"deploy:tests": "rsync -avhe ssh ./build/* --delete sabhas@sas.analytium.co.uk:/var/www/html/sabhas/sasjs-test || npm run deploy:tests-win",
|
||||
"deploy:tests-win": "scp %DEPLOY_PATH% ./build/*",
|
||||
"deploy": "npm run update:adapter && npm run build && npm run deploy:tests"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"userName": "",
|
||||
"password": "",
|
||||
"sasJsConfig": {
|
||||
"serverUrl": "",
|
||||
"serverUrl": "https://sas.analytium.co.uk/",
|
||||
"appLoc": "/Public/app",
|
||||
"serverType": "SASVIYA",
|
||||
"debug": false,
|
||||
|
||||
@@ -14,16 +14,16 @@ const App = (): ReactElement<{}> => {
|
||||
useEffect(() => {
|
||||
if (adapter) {
|
||||
const testSuites = [
|
||||
basicTests(adapter, config.userName, config.password),
|
||||
sendArrTests(adapter),
|
||||
sendObjTests(adapter),
|
||||
specialCaseTests(adapter),
|
||||
// basicTests(adapter, config.userName, config.password),
|
||||
// sendArrTests(adapter),
|
||||
// sendObjTests(adapter),
|
||||
// specialCaseTests(adapter),
|
||||
sasjsRequestTests(adapter)
|
||||
]
|
||||
|
||||
if (adapter.getSasjsConfig().serverType === 'SASVIYA') {
|
||||
testSuites.push(computeTests(adapter))
|
||||
}
|
||||
// if (adapter.getSasjsConfig().serverType === 'SASVIYA') {
|
||||
// testSuites.push(computeTests(adapter))
|
||||
// }
|
||||
|
||||
setTestSuites(testSuites)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,16 @@ export class FileUploader {
|
||||
// currently only web approach is supported for file upload
|
||||
// therefore log is part of response with debug enabled and must be parsed
|
||||
return this.requestClient
|
||||
.post(uploadUrl, formData, undefined, 'application/json', headers)
|
||||
.post(
|
||||
uploadUrl,
|
||||
formData,
|
||||
undefined,
|
||||
'application/json',
|
||||
headers,
|
||||
this.sasjsConfig.debug,
|
||||
true,
|
||||
sasJob
|
||||
)
|
||||
.then(async (res) => {
|
||||
if (
|
||||
this.sasjsConfig.serverType === ServerType.SasViya &&
|
||||
@@ -75,9 +84,7 @@ export class FileUploader {
|
||||
this.requestClient,
|
||||
this.sasjsConfig.serverUrl
|
||||
)
|
||||
return typeof jsonResponse === 'string'
|
||||
? getValidJson(jsonResponse)
|
||||
: jsonResponse
|
||||
return jsonResponse
|
||||
}
|
||||
|
||||
return typeof res.result === 'string'
|
||||
|
||||
@@ -782,12 +782,24 @@ export class SASViyaApiClient {
|
||||
jobResult = await this.requestClient.get<any>(
|
||||
`${this.serverUrl}${resultLink}/content`,
|
||||
access_token,
|
||||
'text/plain'
|
||||
'text/plain',
|
||||
{},
|
||||
debug,
|
||||
true,
|
||||
sasJob
|
||||
)
|
||||
}
|
||||
if (debug && logLink) {
|
||||
log = await this.requestClient
|
||||
.get<any>(`${this.serverUrl}${logLink.href}/content`, access_token)
|
||||
.get<any>(
|
||||
`${this.serverUrl}${logLink.href}/content`,
|
||||
access_token,
|
||||
'application/json',
|
||||
{},
|
||||
debug,
|
||||
true,
|
||||
sasJob
|
||||
)
|
||||
.then((res: any) => res.result.items.map((i: any) => i.line).join('\n'))
|
||||
}
|
||||
if (jobStatus === 'failed') {
|
||||
|
||||
18
src/SASjs.ts
18
src/SASjs.ts
@@ -50,6 +50,7 @@ export default class SASjs {
|
||||
private sas9JobExecutor: JobExecutor | null = null
|
||||
|
||||
constructor(config?: any) {
|
||||
console.log('from SASjs constructor')
|
||||
this.sasjsConfig = {
|
||||
...defaultConfig,
|
||||
...config
|
||||
@@ -611,6 +612,7 @@ export default class SASjs {
|
||||
config.useComputeApi !== null
|
||||
) {
|
||||
if (config.useComputeApi) {
|
||||
console.log(615)
|
||||
return await this.computeJobExecutor!.execute(
|
||||
sasJob,
|
||||
data,
|
||||
@@ -878,20 +880,20 @@ export default class SASjs {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* this method returns an array of SASjsRequest
|
||||
* @returns SASjsRequest[]
|
||||
*/
|
||||
public getSasRequests() {
|
||||
const requests = [
|
||||
...this.webJobExecutor!.getRequests(),
|
||||
...this.computeJobExecutor!.getRequests(),
|
||||
...this.jesJobExecutor!.getRequests()
|
||||
]
|
||||
console.log('from getSASRequests')
|
||||
const requests = this.requestClient!.getRequests()
|
||||
const sortedRequests = requests.sort(compareTimestamps)
|
||||
console.log('sortedRequests', sortedRequests)
|
||||
return sortedRequests
|
||||
}
|
||||
|
||||
public clearSasRequests() {
|
||||
this.webJobExecutor!.clearRequests()
|
||||
this.computeJobExecutor!.clearRequests()
|
||||
this.jesJobExecutor!.clearRequests()
|
||||
this.requestClient!.clearRequests()
|
||||
}
|
||||
|
||||
private setupConfiguration() {
|
||||
|
||||
@@ -239,7 +239,15 @@ export async function executeScript(
|
||||
const resultLink = `/compute/sessions/${executionSessionId}/filerefs/_webout/content`
|
||||
|
||||
jobResult = await requestClient
|
||||
.get<any>(resultLink, access_token, 'text/plain')
|
||||
.get<any>(
|
||||
resultLink,
|
||||
access_token,
|
||||
'text/plain',
|
||||
{},
|
||||
debug,
|
||||
true,
|
||||
jobPath
|
||||
)
|
||||
.catch(async (e) => {
|
||||
if (e instanceof NotFoundError) {
|
||||
if (logLink) {
|
||||
|
||||
@@ -124,7 +124,8 @@ export class AuthManager {
|
||||
|
||||
if (!isLoggedIn) {
|
||||
//We will logout to make sure cookies are removed and login form is presented
|
||||
this.logOut()
|
||||
//Residue can happen in case of session expiration
|
||||
await this.logOut()
|
||||
|
||||
const { result: formResponse } = await this.requestClient.get<string>(
|
||||
this.loginUrl.replace('.do', ''),
|
||||
|
||||
@@ -35,14 +35,11 @@ export class ComputeJobExecutor extends BaseJobExecutor {
|
||||
expectWebout
|
||||
)
|
||||
.then((response) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
console.log('then block of compute job executor')
|
||||
resolve(response.result)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof ComputeJobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@ export class JesJobExecutor extends BaseJobExecutor {
|
||||
this.sasViyaApiClient
|
||||
?.executeJob(sasJob, config.contextName, config.debug, data, authConfig)
|
||||
.then((response: any) => {
|
||||
this.appendRequest(response, sasJob, config.debug)
|
||||
|
||||
let responseObject = {}
|
||||
|
||||
if (extraResponseAttributes && extraResponseAttributes.length > 0) {
|
||||
@@ -49,8 +47,6 @@ export class JesJobExecutor extends BaseJobExecutor {
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ export interface JobExecutor {
|
||||
extraResponseAttributes?: ExtraResponseAttributes[]
|
||||
) => Promise<any>
|
||||
resendWaitingRequests: () => Promise<void>
|
||||
getRequests: () => SASjsRequest[]
|
||||
clearRequests: () => void
|
||||
}
|
||||
|
||||
export abstract class BaseJobExecutor implements JobExecutor {
|
||||
@@ -46,54 +44,7 @@ export abstract class BaseJobExecutor implements JobExecutor {
|
||||
return
|
||||
}
|
||||
|
||||
getRequests = () => this.requests
|
||||
|
||||
clearRequests = () => {
|
||||
this.requests = []
|
||||
}
|
||||
|
||||
protected appendWaitingRequest(request: ExecuteFunction) {
|
||||
this.waitingRequests.push(request)
|
||||
}
|
||||
|
||||
protected appendRequest(response: any, program: string, debug: boolean) {
|
||||
let sourceCode = ''
|
||||
let generatedCode = ''
|
||||
let sasWork = null
|
||||
|
||||
if (debug) {
|
||||
if (response?.log) {
|
||||
sourceCode = parseSourceCode(response.log)
|
||||
generatedCode = parseGeneratedCode(response.log)
|
||||
|
||||
if (response?.result) {
|
||||
sasWork = response.result.WORK
|
||||
} else {
|
||||
sasWork = response.log
|
||||
}
|
||||
} else if (response?.result) {
|
||||
sourceCode = parseSourceCode(response.result)
|
||||
generatedCode = parseGeneratedCode(response.result)
|
||||
sasWork = response.result.WORK
|
||||
}
|
||||
}
|
||||
|
||||
const stringifiedResult =
|
||||
typeof response?.result === 'string'
|
||||
? response?.result
|
||||
: JSON.stringify(response?.result, null, 2)
|
||||
|
||||
this.requests.push({
|
||||
logFile: response?.log || stringifiedResult || response,
|
||||
serviceLink: program,
|
||||
timestamp: new Date(),
|
||||
sourceCode,
|
||||
generatedCode,
|
||||
SASWORK: sasWork
|
||||
})
|
||||
|
||||
if (this.requests.length > 20) {
|
||||
this.requests.splice(0, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ import { ServerType } from '@sasjs/utils/types'
|
||||
import {
|
||||
ErrorResponse,
|
||||
JobExecutionError,
|
||||
LoginRequiredError
|
||||
LoginRequiredError,
|
||||
WeboutResponseError
|
||||
} from '../types/errors'
|
||||
import { generateFileUploadForm } from '../file/generateFileUploadForm'
|
||||
import { generateTableUploadForm } from '../file/generateTableUploadForm'
|
||||
@@ -54,6 +55,15 @@ export class WebJobExecutor extends BaseJobExecutor {
|
||||
|
||||
apiUrl += jobUri.length > 0 ? '&_job=' + jobUri : ''
|
||||
|
||||
if (jobUri.length > 0) {
|
||||
apiUrl += '&_job=' + jobUri
|
||||
/**
|
||||
* Using both _job and _program parameters will cause a conflict in the JES web app, as it’s not clear whether or not the server should make the extra fetch for the job uri.
|
||||
* To handle this, we add the extra underscore and recreate the _program variable in the SAS side of the SASjs adapter so it remains available for backend developers.
|
||||
*/
|
||||
apiUrl = apiUrl.replace('_program=', '__program=')
|
||||
}
|
||||
|
||||
// if context name exists and is not blank string
|
||||
// then add _contextname variable in apiUrl
|
||||
apiUrl +=
|
||||
@@ -101,37 +111,38 @@ export class WebJobExecutor extends BaseJobExecutor {
|
||||
}
|
||||
|
||||
const requestPromise = new Promise((resolve, reject) => {
|
||||
this.requestClient!.post(apiUrl, formData, undefined)
|
||||
.then(async (res) => {
|
||||
this.requestClient!.post(
|
||||
apiUrl,
|
||||
formData,
|
||||
undefined,
|
||||
'application/json',
|
||||
{},
|
||||
config.debug,
|
||||
true,
|
||||
sasJob
|
||||
)
|
||||
.then(async (res: any) => {
|
||||
if (this.serverType === ServerType.SasViya && config.debug) {
|
||||
const jsonResponse = await parseSasViyaDebugResponse(
|
||||
res.result as string,
|
||||
res.result,
|
||||
this.requestClient,
|
||||
this.serverUrl
|
||||
)
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
resolve(jsonResponse)
|
||||
}
|
||||
if (this.serverType === ServerType.Sas9 && config.debug) {
|
||||
const jsonResponse = parseWeboutResponse(res.result as string)
|
||||
if (jsonResponse === '') {
|
||||
throw new Error(
|
||||
'Valid JSON could not be extracted from response.'
|
||||
)
|
||||
}
|
||||
let jsonResponse = res.result
|
||||
if (typeof res.result === 'string')
|
||||
jsonResponse = parseWeboutResponse(res.result, apiUrl)
|
||||
|
||||
getValidJson(jsonResponse)
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
resolve(res.result)
|
||||
}
|
||||
getValidJson(res.result as string)
|
||||
this.appendRequest(res, sasJob, config.debug)
|
||||
resolve(res.result)
|
||||
})
|
||||
.catch(async (e: Error) => {
|
||||
if (e instanceof JobExecutionError) {
|
||||
this.appendRequest(e, sasJob, config.debug)
|
||||
|
||||
reject(new ErrorResponse(e?.message, e))
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ import {
|
||||
InternalServerError,
|
||||
JobExecutionError
|
||||
} from '../types/errors'
|
||||
import { SASjsRequest } from '../types'
|
||||
import { parseWeboutResponse } from '../utils/parseWeboutResponse'
|
||||
import { prefixMessage } from '@sasjs/utils/error'
|
||||
import { SAS9AuthError } from '../types/errors/SAS9AuthError'
|
||||
import { getValidJson } from '../utils'
|
||||
import { parseGeneratedCode, parseSourceCode } from '../utils'
|
||||
|
||||
export interface HttpClient {
|
||||
get<T>(
|
||||
@@ -47,6 +48,8 @@ export interface HttpClient {
|
||||
}
|
||||
|
||||
export class RequestClient implements HttpClient {
|
||||
private requests: SASjsRequest[] = []
|
||||
|
||||
protected csrfToken: CsrfToken = { headerName: '', value: '' }
|
||||
protected fileUploadCsrfToken: CsrfToken | undefined
|
||||
protected httpClient: AxiosInstance
|
||||
@@ -83,12 +86,75 @@ export class RequestClient implements HttpClient {
|
||||
return this.httpClient.defaults.baseURL || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* this method returns all requests, an array of SASjsRequest type
|
||||
* @returns SASjsRequest[]
|
||||
*/
|
||||
public getRequests = () => this.requests
|
||||
|
||||
/**
|
||||
* this method clears the requests array, i.e set to empty
|
||||
*/
|
||||
public clearRequests = () => {
|
||||
this.requests = []
|
||||
}
|
||||
|
||||
/**
|
||||
* this method appends the response from sasjs request to requests array
|
||||
* @param response - response from sasjs request
|
||||
* @param program - name of program
|
||||
* @param debug - a boolean that indicates whether debug was enabled or not
|
||||
*/
|
||||
public appendRequest = (response: any, program: string, debug: boolean) => {
|
||||
console.log('from appendRequest')
|
||||
let sourceCode = ''
|
||||
let generatedCode = ''
|
||||
let sasWork = null
|
||||
|
||||
if (debug) {
|
||||
if (response?.log) {
|
||||
sourceCode = parseSourceCode(response.log)
|
||||
generatedCode = parseGeneratedCode(response.log)
|
||||
|
||||
if (response?.result) {
|
||||
sasWork = response.result.WORK
|
||||
} else {
|
||||
sasWork = response.log
|
||||
}
|
||||
} else if (response?.result) {
|
||||
sourceCode = parseSourceCode(response.result)
|
||||
generatedCode = parseGeneratedCode(response.result)
|
||||
sasWork = response.result.WORK
|
||||
}
|
||||
}
|
||||
|
||||
const stringifiedResult =
|
||||
typeof response?.result === 'string'
|
||||
? response?.result
|
||||
: JSON.stringify(response?.result, null, 2)
|
||||
|
||||
this.requests.push({
|
||||
logFile: response?.log || stringifiedResult || response,
|
||||
serviceLink: program,
|
||||
timestamp: new Date(),
|
||||
sourceCode,
|
||||
generatedCode,
|
||||
SASWORK: sasWork
|
||||
})
|
||||
|
||||
if (this.requests.length > 20) {
|
||||
this.requests.splice(0, 1)
|
||||
}
|
||||
}
|
||||
|
||||
public async get<T>(
|
||||
url: string,
|
||||
accessToken: string | undefined,
|
||||
contentType: string = 'application/json',
|
||||
overrideHeaders: { [key: string]: string | number } = {},
|
||||
debug: boolean = false
|
||||
debug: boolean = false,
|
||||
captureRequest: boolean = false,
|
||||
sasJob: string = ''
|
||||
): Promise<{ result: T; etag: string; status: number }> {
|
||||
const headers = {
|
||||
...this.getHeaders(accessToken, contentType),
|
||||
@@ -108,8 +174,11 @@ export class RequestClient implements HttpClient {
|
||||
.get<T>(url, requestConfig)
|
||||
.then((response) => {
|
||||
throwIfError(response)
|
||||
|
||||
return this.parseResponse<T>(response)
|
||||
const responseToReturn = this.parseResponse<T>(response)
|
||||
if (captureRequest) {
|
||||
this.appendRequest(responseToReturn, sasJob, debug)
|
||||
}
|
||||
return responseToReturn
|
||||
})
|
||||
.catch(async (e) => {
|
||||
return await this.handleError(
|
||||
@@ -135,7 +204,10 @@ export class RequestClient implements HttpClient {
|
||||
data: any,
|
||||
accessToken: string | undefined,
|
||||
contentType = 'application/json',
|
||||
overrideHeaders: { [key: string]: string | number } = {}
|
||||
overrideHeaders: { [key: string]: string | number } = {},
|
||||
debug: boolean = false,
|
||||
captureRequest: boolean = false,
|
||||
sasJob: string = ''
|
||||
): Promise<{ result: T; etag: string }> {
|
||||
const headers = {
|
||||
...this.getHeaders(accessToken, contentType),
|
||||
@@ -146,7 +218,11 @@ export class RequestClient implements HttpClient {
|
||||
.post<T>(url, data, { headers, withCredentials: true })
|
||||
.then((response) => {
|
||||
throwIfError(response)
|
||||
return this.parseResponse<T>(response)
|
||||
const responseToReturn = this.parseResponse<T>(response)
|
||||
if (captureRequest) {
|
||||
this.appendRequest(responseToReturn, sasJob, debug)
|
||||
}
|
||||
return responseToReturn
|
||||
})
|
||||
.catch(async (e) => {
|
||||
return await this.handleError(e, () =>
|
||||
@@ -429,13 +505,7 @@ export class RequestClient implements HttpClient {
|
||||
}
|
||||
} catch {
|
||||
try {
|
||||
const weboutResponse = parseWeboutResponse(response.data)
|
||||
if (weboutResponse === '') {
|
||||
throw new Error('Valid JSON could not be extracted from response.')
|
||||
}
|
||||
|
||||
const jsonResponse = getValidJson(weboutResponse)
|
||||
parsedResponse = jsonResponse
|
||||
parsedResponse = JSON.parse(parseWeboutResponse(response.data))
|
||||
} catch {
|
||||
parsedResponse = response.data
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ const prepareFilesAndParams = () => {
|
||||
describe('FileUploader', () => {
|
||||
const config: SASjsConfig = {
|
||||
...new SASjsConfig(),
|
||||
appLoc: '/sample/apploc'
|
||||
appLoc: '/sample/apploc',
|
||||
debug: false
|
||||
}
|
||||
|
||||
const fileUploader = new FileUploader(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getValidJson } from '../../utils'
|
||||
import { JsonParseArrayError, InvalidJsonError } from '../../types/errors'
|
||||
|
||||
describe('jsonValidator', () => {
|
||||
it('should not throw an error with a valid json', () => {
|
||||
@@ -19,23 +20,31 @@ describe('jsonValidator', () => {
|
||||
|
||||
it('should throw an error with an invalid json', () => {
|
||||
const json = `{\"test\":\"test\"\"test2\":\"test\"}`
|
||||
let errorThrown = false
|
||||
try {
|
||||
const test = () => {
|
||||
getValidJson(json)
|
||||
} catch (error) {
|
||||
errorThrown = true
|
||||
}
|
||||
expect(errorThrown).toBe(true)
|
||||
expect(test).toThrowError(InvalidJsonError)
|
||||
})
|
||||
|
||||
it('should throw an error when an array is passed', () => {
|
||||
const array = ['hello', 'world']
|
||||
let errorThrown = false
|
||||
try {
|
||||
const test = () => {
|
||||
getValidJson(array)
|
||||
} catch (error) {
|
||||
errorThrown = true
|
||||
}
|
||||
expect(errorThrown).toBe(true)
|
||||
expect(test).toThrow(JsonParseArrayError)
|
||||
})
|
||||
|
||||
it('should throw an error when null is passed', () => {
|
||||
const test = () => {
|
||||
getValidJson(null as any)
|
||||
}
|
||||
expect(test).toThrow(InvalidJsonError)
|
||||
})
|
||||
|
||||
it('should throw an error when undefined is passed', () => {
|
||||
const test = () => {
|
||||
getValidJson(undefined as any)
|
||||
}
|
||||
expect(test).toThrow(InvalidJsonError)
|
||||
})
|
||||
})
|
||||
|
||||
7
src/types/errors/InvalidJsonError.ts
Normal file
7
src/types/errors/InvalidJsonError.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class InvalidJsonError extends Error {
|
||||
constructor() {
|
||||
super('Error: invalid Json string')
|
||||
this.name = 'InvalidJsonError'
|
||||
Object.setPrototypeOf(this, InvalidJsonError.prototype)
|
||||
}
|
||||
}
|
||||
7
src/types/errors/JsonParseArrayError.ts
Normal file
7
src/types/errors/JsonParseArrayError.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class JsonParseArrayError extends Error {
|
||||
constructor() {
|
||||
super('Can not parse array object to json.')
|
||||
this.name = 'JsonParseArrayError'
|
||||
Object.setPrototypeOf(this, JsonParseArrayError.prototype)
|
||||
}
|
||||
}
|
||||
7
src/types/errors/WeboutResponseError.ts
Normal file
7
src/types/errors/WeboutResponseError.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class WeboutResponseError extends Error {
|
||||
constructor(public url: string) {
|
||||
super(`Error: error while parsing response from ${url}`)
|
||||
this.name = 'WeboutResponseError'
|
||||
Object.setPrototypeOf(this, WeboutResponseError.prototype)
|
||||
}
|
||||
}
|
||||
@@ -8,3 +8,6 @@ export * from './NotFoundError'
|
||||
export * from './ErrorResponse'
|
||||
export * from './NoSessionStateError'
|
||||
export * from './RootFolderNotFoundError'
|
||||
export * from './JsonParseArrayError'
|
||||
export * from './WeboutResponseError'
|
||||
export * from './InvalidJsonError'
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { JsonParseArrayError, InvalidJsonError } from '../types/errors'
|
||||
|
||||
/**
|
||||
* 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 (str === null || str === undefined) throw new InvalidJsonError()
|
||||
|
||||
if (Array.isArray(str)) throw new JsonParseArrayError()
|
||||
|
||||
if (typeof str === 'object') return str
|
||||
|
||||
return JSON.parse(str)
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON response.')
|
||||
if (e instanceof JsonParseArrayError) throw e
|
||||
throw new InvalidJsonError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { RequestClient } from '../request/RequestClient'
|
||||
import { getValidJson } from '../utils'
|
||||
|
||||
/**
|
||||
* When querying a Viya job using the Web approach (as opposed to using the APIs) with _DEBUG enabled,
|
||||
@@ -25,5 +26,5 @@ export const parseSasViyaDebugResponse = async (
|
||||
|
||||
return requestClient
|
||||
.get(serverUrl + jsonUrl, undefined)
|
||||
.then((res) => res.result)
|
||||
.then((res: any) => getValidJson(res.result))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export const parseWeboutResponse = (response: string) => {
|
||||
import { WeboutResponseError } from '../types/errors'
|
||||
|
||||
export const parseWeboutResponse = (response: string, url?: string) => {
|
||||
let sasResponse = ''
|
||||
|
||||
if (response.includes('>>weboutBEGIN<<')) {
|
||||
@@ -7,6 +9,7 @@ export const parseWeboutResponse = (response: string) => {
|
||||
.split('>>weboutBEGIN<<')[1]
|
||||
.split('>>weboutEND<<')[0]
|
||||
} catch (e) {
|
||||
if (url) throw new WeboutResponseError(url)
|
||||
sasResponse = ''
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user