At the CLi I can do
aws lambda list-functions
and get all the functions detail
Also I can do
aws lambda list-functions --query 'Functions[*].[FunctionName]' --output text
and get a simple list of just the function names.
How can I do that in a lambda using the SDK?
I tried
exports.handler = function (event) {
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda({ apiVersion: '2015-03-31' });
var lambs = lambda.listFunctions();
console.log(lambs);
};
and I have aws lambda full access role
But i get the output below
e,
s3DisableBodySigning: true,
computeChecksums: true,
convertResponseTypes: true,
correctClockSkew: false,
customUserAgent: null,
dynamoDbCrc32: true,
systemClockOffset: 0,
signatureVersion: 'v4',
signatureCache: true,
retryDelayOptions: {},
useAccelerateEndpoint: false,
clientSideMonitoring: false,
endpointDiscoveryEnabled: false,
endpointCacheSize: 1000,
hostPrefixEnabled: true,
stsRegionalEndpoints: null
},
isGlobalEndpoint: false,
endpoint: Endpoint {
protocol: 'https:',
host: 'lambda.us-east-2.amazonaws.com',
port: 443,
hostname: 'lambda.us-east-2.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://lambda.us-east-2.amazonaws.com/'
},
_events: { apiCallAttempt: [Array], apiCall: [Array] },
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
operation: 'listFunctions',
params: {},
httpRequest: HttpRequest {
method: 'POST',
path: '/',
headers: {
'User-Agent': 'aws-sdk-nodejs/2.536.0 linux/v12.13.0 exec-env/AWS_Lambda_nodejs12.x'
},
body: '',
endpoint: Endpoint {
protocol: 'https:',
host: 'lambda.us-east-2.amazonaws.com',
port: 443,
hostname: 'lambda.us-east-2.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://lambda.us-east-2.amazonaws.com/',
constructor: [Function]
},
region: 'us-east-2',
_userAgent: 'aws-sdk-nodejs/2.536.0 linux/v12.13.0 exec-env/AWS_Lambda_nodejs12.x'
},
startTime: 2019-12-04T20:30:18.812Z,
response: Response {
request: [Circular],
data: null,
error: null,
retryCount: 0,
redirectCount: 0,
httpResponse: HttpResponse {
statusCode: undefined,
headers: {},
body: undefined,
streaming: false,
stream: null
},
maxRetries: 3,
maxRedirects: 10
},
_asm: AcceptorStateMachine {
currentState: 'validate',
states: {
validate: [Object],
build: [Object],
afterBuild: [Object],
sign: [Object],
retry: [Object],
afterRetry: [Object],
send: [Object],
validateResponse: [Object],
extractError: [Object],
extractData: [Object],
restart: [Object],
success: [Object],
error: [Object],
complete: [Object]
}
},
_haltHandlersOnError: false,
_events: {
validate: [
[Function],
[Function],
[Function: VALIDATE_REGION],
[Function: BUILD_IDEMPOTENCY_TOKENS],
[Function: VALIDATE_PARAMETERS]
],
afterBuild: [
[Function],
[Function: SET_CONTENT_LENGTH],
[Function: SET_HTTP_HOST]
],
restart: [ [Function: RESTART] ],
sign: [ [Function], [Function], [Function] ],
validateResponse: [ [Function: VALIDATE_RESPONSE], [Function] ],
send: [ [Function] ],
httpHeaders: [ [Function: HTTP_HEADERS] ],
httpData: [ [Function: HTTP_DATA] ],
httpDone: [ [Function: HTTP_DONE] ],
retry: [
[Function: FINALIZE_ERROR],
[Function: INVALIDATE_CREDENTIALS],
[Function: EXPIRED_SIGNATURE],
[Function: CLOCK_SKEWED],
[Function: REDIRECT],
[Function: RETRY_CHECK],
[Function: API_CALL_ATTEMPT_RETRY]
],
afterRetry: [ [Function] ],
build: [ [Function: buildRequest] ],
extractData: [ [Function: extractData], [Function: extractRequestId] ],
extractError: [ [Function: extractError], [Function: extractRequestId] ],
httpError: [ [Function: ENOTFOUND_ERROR] ],
success: [ [Function: API_CALL_ATTEMPT] ],
complete: [ [Function: API_CALL] ]
},
emit: [Function: emit],
API_CALL_ATTEMPT: [Function: API_CALL_ATTEMPT],
API_CALL_ATTEMPT_RETRY: [Function: API_CALL_ATTEMPT_RETRY],
API_CALL: [Function: API_CALL]
}END RequestId: dc9caa5c-42b1-47e9-8136-80c3fbdddbc5
REPORT RequestId: dc9caa5c-42b1-47e9-8136-80c3fbdddbc5 Duration: 45.81 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 86 MB
AWS SDK calls return an AWS.Request object, not the response to the actual API call, which typically arrives asynchronously.
You need to add a callback handler like so:
lambda.listFunctions((err, data) => {
if (err) {
console.err(err);
} else {
data.Functions.forEach(func => console.log(func.FunctionName));
}
});
Or simply use async/await, like so (note that the enclosing function must be async):
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();
exports.handler = async (event) => {
const funcs = await lambda.listFunctions().promise();
funcs.Functions.forEach(func => console.log(func.FunctionName));
}
The data/funcs returned to you will be a JavaScript object including an array of functions. See the SDK reference for specifics.
Ideally, use the async/await form. It's simpler, less prone to error, and more modern.
Related
const { v4: uuidv4 } = require("uuid");
const k8s = require("#kubernetes/client-node");
const kc = new k8s.KubeConfig();
kc.loadFromDefault()
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
let USER_ID=Date.now(), LEVEL=1, DIFFICULTY="start", DRONE="dr1", RESET=false
const definition = {
apiVersion: "v1",
kind: "Pod",
metadata: {
annotations: {
key1: "value1",
key2: "value2",
},
name: USER_ID,
labels: { app: "simulator-app", name: USER_ID },
},
spec: {
containers: [
{
name: "simulator-app",
image:
".....dkr.ecr.eu-central-1.amazonaws.com/simulator:latest",
ports: [{ containerPort: 8080 }, { containerPort: 9090 }],
tty: true,
stdin: true,
imagePullPolicy: "IfNotPresent",
command: ["/bin/bash", "-c"],
args: [
'echo START....;LEVEL=%s;DIFFICULTY=%s;DRONE=%s;echo "LEVEL=${LEVEL}";echo "DIFFICULTY=${DIFFICULTY}";echo "DRONE=${DRONE}";cd /home/;source ~/.bashrc;echo "Bashrc Sourced";pwd;ls;echo "Starting simulator with ${LEVEL} level, ${DRONE} vehicle and ${DIFFICULTY} difficulty";source "/opt/ros/foxy/setup.bash";source "/home/rossimulator/install/setup.bash";ros2 launch simulator_bringup sim_nodes.launch.py level:=${LEVEL} drone_type:=${DRONE} difficulty:=${DIFFICULTY};echo Done;' %
(LEVEL, DIFFICULTY, DRONE),
],
},
],
},
};
k8sApi.createNamespacedPod("Default", definition)
.then(console.log)
.catch(console.log);
Getting the below error on the console
{
response: {
statusCode: 401,
body: {
kind: "Status",
apiVersion: "v1",
metadata: {},
status: "Failure",
message: "Unauthorized",
reason: "Unauthorized",
code: 401,
},
headers: {
"audit-id": "07eba07d-6121-492f-9993-ece3fa8827c5",
"cache-control": "no-cache, private",
"content-type": "application/json",
date: "Mon, 28 Mar 2022 02:48:59 GMT",
"content-length": "129",
connection: "close",
},
request: {
uri: {
protocol: "https:",
slashes: true,
auth: null,
host: ".....gr7.eu-central-1.eks.amazonaws.com",
port: 443,
hostname: "......gr7.eu-central-1.eks.amazonaws.com",
hash: null,
search: null,
query: null,
pathname: "/api/v1/namespaces/Default/pods",
path: "/api/v1/namespaces/Default/pods",
href: "https://..................eu-central-1.eks.amazonaws.com/api/v1/namespaces/Default/pods",
},
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Bearer k8s-aws-v1.....",
"content-type": "application/json",
"content-length": 506,
},
},
},
body: {
kind: "Status",
apiVersion: "v1",
metadata: {},
status: "Failure",
message: "Unauthorized",
reason: "Unauthorized",
code: 401,
},
statusCode: 401,
name: "HttpError",
};
What could be the possible reason for getting this error?
While the it works in the pythong this way
from flask import Flask, jsonify
import time
from kubernetes import client, config
import uuid
from kubernetes.client.rest import ApiException
app = Flask(__name__)
config.load_kube_config(
context="arn:aws:eks:eu-central-1:9010......:cluster/sim-cluster"
)
v1 = client.CoreV1Api()
# definition - same as above
v1.create_namespaced_pod(body=definition, namespace="default")
I did not found load_kube_config equivalent method in the library
I am sending request to API Gateway from Slack. The request is then sent to lambda to process it. I would like to filter out invalid requests before hitting lambda, at the API Gateway level itself. The "entire" payload sent by slack is like below;
{
resource: '/',
path: '/',
httpMethod: 'POST',
headers: {
Accept: 'application/json,*/*',
'Accept-Encoding': 'gzip,deflate',
'Content-Type': 'application/x-www-form-urlencoded',
Host: 'qweehhy6xd.execute-api.us-east-1.amazonaws.com',
'User-Agent': 'Slackbot 1.0 (+https://api.slack.com/robots)',
'X-Amzn-Trace-Id': 'Root=1-6204af65-03e4d5b23ec5f79e0ehgfdc',
'X-Forwarded-For': '133.237.255.123',
'X-Forwarded-Port': '443',
'X-Forwarded-Proto': 'https',
'X-Slack-Request-Timestamp': '1644474213',
'X-Slack-Signature': 'v0=c56tghyt30c8a8ec9228a73d3849de4de9055164a3d72a1793786f8d04617ecd7'
},
multiValueHeaders: {
Accept: [ 'application/json,*/*' ],
'Accept-Encoding': [ 'gzip,deflate' ],
'Content-Type': [ 'application/x-www-form-urlencoded' ],
Host: [ 'qweehhy6xd.execute-api.us-east-1.amazonaws.com' ],
'User-Agent': [ 'Slackbot 1.0 (+https://api.slack.com/robots)' ],
'X-Amzn-Trace-Id': [ 'Root=1-6204af65-03e4d5b87ec5f79e0ee0c632' ],
'X-Forwarded-For': [ '133.237.255.123' ],
'X-Forwarded-Port': [ '443' ],
'X-Forwarded-Proto': [ 'https' ],
'X-Slack-Request-Timestamp': [ '1644474213' ],
'X-Slack-Signature': [
'v0=c56tghyt30c8a8ec9228a73d3849de4de9055164a3d72a1793786f8d04617ecd7'
]
},
queryStringParameters: null,
multiValueQueryStringParameters: null,
pathParameters: null,
stageVariables: null,
requestContext: {
resourceId: 's7q8swr5fr',
resourcePath: '/',
httpMethod: 'POST',
extendedRequestId: 'SPYX4GyfIAMFX2A=',
requestTime: '10/Feb/2022:06:23:33 +0000',
path: '/qwerty',
accountId: '592976962544',
protocol: 'HTTP/1.1',
stage: 'qwerty',
domainPrefix: 'qweehhy6xd',
requestTimeEpoch: 1644474213489,
requestId: 'vtg02b44-a456-4gt0-abe4-499146d32b5b',
identity: {
cognitoIdentityPoolId: null,
accountId: null,
cognitoIdentityId: null,
caller: null,
sourceIp: '133.237.255.123',
principalOrgId: null,
accessKey: null,
cognitoAuthenticationType: null,
cognitoAuthenticationProvider: null,
userArn: null,
userAgent: 'Slackbot 1.0 (+https://api.slack.com/robots)',
user: null
},
domainName: 'qweehhy6xd.execute-api.us-east-1.amazonaws.com',
apiId: 'qweehhy6xd'
},
body: 'parama=valuea¶mb=value_b¶m_c=valuec',
isBase64Encoded: false
}
Now, I would like to validate this string at the API Gateway level. Say, requestContext.resourceId is s7q8swr5fr in the request payload. I would like to terminate all requests where resourceId is not s7q8swr5fr. Something to note here is Content-Type is application/x-www-form-urlencoded.
Somebody please tell me how to achieve this?
Thank you.
EDIT
I used the model below;
{
"$schema": "http://json-schema.org/draft-04/schema# ",
"title": "TestModel",
"type": "object",
"properties": {
"requestContext": {
"type": "object",
"required": ["resourceId", "accountId", "domainPrefix"],
"properties": {
"resourceId": { "type": "string", "pattern": "s7q8swr5fr" },
"accountId": { "type": "string", "pattern": "592976962544" },
"domainPrefix": { "type": "string", "pattern": "qweehhy6xd" }
}
}
}
}
The model is then saved and mentioned under the method request configuration, like below;
I am testing a fass (function as a service ) using AWS lambda
I am getting following error on testing the api after serverless deploy
query-error: UnknownEndpoint: Inaccessible host: 'localhost' at port `8008'. This service may not be available in the 'eu-west-1' region.","status":"error"}"
but when running in the local using serverless offline everything works as expected
what could be the reason for this error?
also in the server validation error works if wrong params are passed, this error shows up when query is being executed
serveless.ts
/* eslint no-use-before-define: 0 */
import type { AWS } from "#serverless/typescript";
// DynamoDB
import dynamoDbTables from "./resources/dynamodb-tables";
// Functions
import functions from "./resources/functions";
const serverlessConfiguration: AWS = {
service: "lead-management-app",
frameworkVersion: "2",
custom: {
region: "${opt:region, self:provider.region}",
stage: "${opt:stage, self:provider.stage}",
prefix: "${self:service}-${self:custom.stage}",
lead_table: "${self:service}-leads-${opt:stage, self:provider.stage}",
interest_table:
"${self:service}-interests-${opt:stage, self:provider.stage}",
table_throughputs: {
prod: 5,
default: 1,
},
table_throughput:
"${self:custom.table_throughputs.${self:custom.stage}, self:custom.table_throughputs.default}",
dynamodb: {
stages: ["dev"],
start: {
port: 8008,
inMemory: true,
heapInitial: "200m",
heapMax: "1g",
migrate: true,
seed: true,
convertEmptyValues: true,
// Uncomment only if you already have a DynamoDB running locally
// noStart: true
},
},
["serverless-offline"]: {
httpPort: 3000,
babelOptions: {
presets: ["env"],
},
},
profile: {
prod: "prodAccount",
dev: "devAccount",
},
},
plugins: [
"serverless-bundle",
"serverless-dynamodb-local",
"serverless-offline",
"serverless-dotenv-plugin",
],
provider: {
name: "aws",
runtime: "nodejs14.x",
stage: "dev",
region: "eu-west-1",
apiGateway: {
minimumCompressionSize: 1024,
shouldStartNameWithService: true,
},
environment: {
AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1",
NODE_OPTIONS: "--enable-source-maps --stack-trace-limit=1000",
REGION: "${self:custom.region}",
STAGE: "${self:custom.stage}",
LEADS_TABLE: "${self:custom.lead_table}",
INTERESTS_TABLE: "${self:custom.interest_table}",
},
iamRoleStatements: [
{
Effect: "Allow",
Action: [
"dynamodb:DescribeTable",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
],
Resource: [
{ "Fn::GetAtt": ["LeadsTable", "Arn"] },
{ "Fn::GetAtt": ["InterestsTable", "Arn"] },
],
},
],
profile: "${self:custom.profile.${self:custom.stage}}",
lambdaHashingVersion: "20201221",
},
// import the function via paths
functions,
package: { individually: true },
resources: {
Resources: dynamoDbTables,
},
};
module.exports = serverlessConfiguration;
Finally found the culprit , it was the env variable that i set in local
I've got an AWS lambda (as node.js) that is triggered by cron every 3 minutes. it purpose is to monitor some of our API's services, so it is sends http requests. Issue is, in 20% of the cases the http request times out. when I run it locally, or manually (by using the Test feature on AWS console) everything works ok. I tried to increase the timeout option but with no success.
Error Im getting is:
timeout of 5000ms exceeded at createError (/var/task/node_modules/axios/lib/core/createError.js
Error Details:
2021-08-30T09:06:08.029Z 841332b5-d8c1-49dc-8caa-f57215ed5440 ERROR PortalApiSql_Error Error: timeout of 5000ms exceeded
at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)
at RedirectableRequest.handleRequestTimeout (/var/task/node_modules/axios/lib/adapters/http.js:280:16)
at RedirectableRequest.emit (events.js:400:28)
at Timeout._onTimeout (/var/task/node_modules/follow-redirects/index.js:166:12)
at listOnTimeout (internal/timers.js:557:17)
at processTimers (internal/timers.js:500:7) {
config: {
url: '/health/sql',
method: 'get',
headers: {
Accept: 'application/json, text/plain, /',
ApiToken: '---',
'User-Agent': 'axios/0.21.1'
},
baseURL: 'https://apidev.myportal.com/v1',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 5000,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
data: undefined
},
code: 'ECONNABORTED',
request: <ref 1> Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false
},
_events: [Object: null prototype] {
response: [Array],
error: [Array],
socket: [Function: destroyOnTimeout]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: 10485760,
protocol: 'https:',
path: '/v1/health/sql',
method: 'GET',
headers: [Object],
agent: undefined,
agents: [Object],
auth: undefined,
hostname: 'apidev.myportal.com',
port: null,
nativeProtocols: [Object],
pathname: '/v1/health/sql'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [TLSSocket],
_header: 'GET /v1/health/sql HTTP/1.1\r\n' +
'Accept: application/json, text/plain, /\r\n' +
'ApiToken: ----\r\n' +
'User-Agent: axios/0.21.1\r\n' +
'Host: apidev.myportal.com\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '/v1/health/sql',
_ended: false,
res: null,
aborted: true,
timeoutCb: null,
upgradeOrConnect: false,
parser: [HTTPParser],
maxHeadersCount: null,
reusedSocket: false,
host: 'apidev.myportal.com',
protocol: 'https:',
_redirectable: [Circular *1],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype]
},
_currentUrl: 'https://apidev.myportal.com/v1/health/sql',
_timeout: Timeout {
_idleTimeout: 5000,
_idlePrev: null,
_idleNext: null,
_idleStart: 149306,
_onTimeout: [Function (anonymous)],
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: true,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 63,
[Symbol(triggerId)]: 59
},
[Symbol(kCapture)]: false
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
}
I've simplified the code (simplified code also gets the timeout error),
exports.handler = async (event, context) => {
const axiosInstance = axios.create({
baseURL: PortalApiUrl,
timeout: AxiosTimeout,
headers: { ApiToken: PortalApiToken },
});
try {
console.log("before req ");
console.log(WATCHERS_CONFIGURATION.PortalApiSql.Path);
const response = await axiosInstance.get(WATCHERS_CONFIGURATION.PortalApiSql.Path);
console.log(`recieved ${response}`);
return {
statusCode: 200,
};
} catch (error) {
console.error("Error: ", error);
return {
statusCode: 500,
};
}
};
I tried to test an action creator that returns a promise, using also redux mock store.
import promiseMiddleware from 'redux-promise-middleware';
import nock from 'nock';
import configureStore from 'redux-mock-store';
import { domain, port } from '../../config/environment';
import { GET_ITEMS_START,
GET_ITEMS_SUCCESS } from '../../constants/items';
import { getItems } from './items';
const promise = promiseMiddleware({
promiseTypeSuffixes: ['START', 'SUCCESS', 'ERROR']
});
describe('Get Items', () => {
it('should create GET_ITEMS_SUCCESS action after successfully getting items', (done) => {
nock(`${domain}:${port}`)
.get('/api/items')
.reply(200, {
_id: '1',
text: 'Make Eggs',
completed: false
});
const expectedActions = [
{ type: GET_ITEMS_START },
{ type: GET_ITEMS_SUCCESS, payload: {
data: { _id: '1', text: 'Make Eggs', completed: false }
}}
];
const store = mockStore({}, expectedActions, done);
store.dispatch(getItems());
});
});
and here is my action creator code
export function getItems() {
return {
type: GET_ITEMS,
payload: {
promise: axios.get(`${domain}:${port}/api/items`)
}
};
}
but the result is mismatch because the promise resolved a deep nested objects
Error: Expected { payload: { config: { headers: {}, method: 'get', timeout: 0, transformRequest: [ [Function] ], transformResponse: [ [Function] ], url: 'http://localhost:3000/api/items', withCredentials: undefined }, data: { _id: '1', completed: false, text: 'Make Eggs' }, headers: {}, status: 200, statusText: 'OK' }, type: 'GET_ITEMS_SUCCESS' } to equal { payload: { data: { _id: '1', completed: false, text: 'Make Eggs' } }, type: 'GET_ITEMS_SUCCESS' }
+ expected - actual
{
"payload": {
- "config": {
- "headers": {}
- "method": "get"
- "timeout": 0
- "transformRequest": [
- [Function]
- ]
- "transformResponse": [
- [Function]
- ]
- "url": "http://localhost:3000/api/items"
- "withCredentials": [undefined]
- }
"data": {
"_id": "1"
"completed": false
"text": "Make Eggs"
}
- "headers": {}
- "status": 200
- "statusText": "OK"
}
"type": "GET_ITEMS_SUCCESS"
}
I obviously don't want to copy all of those deep nested properties into my test suite.
Is there a better way of doing this?
If you're writing a unit test, you probably don't need to call the actual REST API. Instead you can mock axios and make it return some fake data which won't be so deep.