mock-config-server
Advanced tools
Comparing version 3.2.0 to 3.3.0
@@ -1,1 +0,2 @@ | ||
export declare const isDescriptorValueValid: (checkMode: unknown, value: unknown, entityName?: unknown) => boolean; | ||
import type { CheckMode } from '../../../../src/utils/types'; | ||
export declare const isDescriptorValueValid: (checkMode: CheckMode, value: unknown) => boolean | undefined; |
@@ -8,14 +8,37 @@ "use strict"; | ||
var _constants = require("../../../../src/utils/constants"); | ||
const isDescriptorValueValid = (checkMode, value, entityName) => { | ||
if (_constants.CHECK_ACTUAL_VALUE_CHECK_MODES.includes(checkMode)) return typeof value === 'undefined'; | ||
if (_constants.COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES.includes(checkMode)) { | ||
if (entityName === 'body' || entityName === 'variables') { | ||
return typeof value === 'object' && value !== null && typeof value !== 'function' && !(value instanceof RegExp); | ||
var _helpers = require("../../../../src/utils/helpers"); | ||
// ✅ important: | ||
// should validate all properties over nesting | ||
const isObjectOrArrayValid = value => { | ||
if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string' || value === null) { | ||
return true; | ||
} | ||
if (Array.isArray(value)) { | ||
return value.every(isObjectOrArrayValid); | ||
} | ||
if ((0, _helpers.isPlainObject)(value)) { | ||
for (const key in value) { | ||
if (!isObjectOrArrayValid(value[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
return false; | ||
}; | ||
const isDescriptorValueValid = (checkMode, value) => { | ||
if (_constants.CHECK_ACTUAL_VALUE_CHECK_MODES.includes(checkMode)) { | ||
return typeof value === 'undefined'; | ||
} | ||
if (_constants.COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES.includes(checkMode)) { | ||
const isValueObjectOrArray = (0, _helpers.isPlainObject)(value) || Array.isArray(value); | ||
if (isValueObjectOrArray) return isObjectOrArrayValid(value); | ||
return typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string' || value === null; | ||
} | ||
if (_constants.COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES.includes(checkMode)) { | ||
return typeof value === 'boolean' || typeof value === 'number' || typeof value === 'string'; | ||
} | ||
if (checkMode === 'function') return typeof value === 'function'; | ||
if (checkMode === 'function') return typeof value === 'function' && value.length <= 2; | ||
if (checkMode === 'regExp') return value instanceof RegExp; | ||
throw new Error('Invalid checkMode'); | ||
}; | ||
exports.isDescriptorValueValid = isDescriptorValueValid; |
@@ -17,11 +17,17 @@ "use strict"; | ||
operationType, | ||
operationName | ||
operationName, | ||
query | ||
} = config; | ||
if (typeof operationName === 'undefined' && typeof query === 'undefined') { | ||
throw new Error(`configs[${index}]`); | ||
} | ||
if (operationType !== 'query' && operationType !== 'mutation') { | ||
throw new Error(`configs[${index}].operationType`); | ||
} | ||
const isOperationNameStringOrRegExp = typeof operationName === 'string' || operationName instanceof RegExp; | ||
if (!isOperationNameStringOrRegExp) { | ||
if (typeof operationName !== 'undefined' && typeof operationName !== 'string' && !(operationName instanceof RegExp)) { | ||
throw new Error(`configs[${index}].operationName`); | ||
} | ||
if (typeof query !== 'undefined' && typeof query !== 'string') { | ||
throw new Error(`configs[${index}].query`); | ||
} | ||
try { | ||
@@ -28,0 +34,0 @@ (0, _validateRoutes.validateRoutes)(config.routes, operationType); |
@@ -10,2 +10,4 @@ "use strict"; | ||
var _validateInterceptors = require("../../validateInterceptors/validateInterceptors"); | ||
var _validateQueue = require("../../validateQueue/validateQueue"); | ||
var _validateSettings = require("../../validateSettings/validateSettings"); | ||
const ALLOWED_ENTITIES_BY_OPERATION_TYPE = { | ||
@@ -16,21 +18,33 @@ query: ['headers', 'cookies', 'query', 'variables'], | ||
const validateEntity = (entity, entityName) => { | ||
const { | ||
checkMode: topLevelCheckMode, | ||
value: topLevelValue | ||
} = (0, _helpers.convertToEntityDescriptor)(entity); | ||
const isVariables = entityName === 'variables'; | ||
const isTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity); | ||
if (isTopLevelDescriptor && isVariables) { | ||
if (!(0, _helpers2.isCheckModeValid)(topLevelCheckMode, 'variables')) { | ||
const isEntityTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity); | ||
if (isEntityTopLevelDescriptor) { | ||
if (!isVariables) { | ||
throw new Error(entityName); | ||
} | ||
if (!(0, _helpers2.isCheckModeValid)(entity.checkMode, 'variables')) { | ||
throw new Error('variables.checkMode'); | ||
} | ||
if (!(0, _helpers2.isDescriptorValueValid)(topLevelCheckMode, topLevelValue, 'variables')) { | ||
const errorMessage = 'variables.value'; | ||
throw new Error(errorMessage); | ||
const isDescriptorValueObjectOrArray = (0, _helpers.isPlainObject)(entity.value) || Array.isArray(entity.value); | ||
if (!isDescriptorValueObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(entity.checkMode, entity.value)) { | ||
throw new Error('variables.value'); | ||
} | ||
return; | ||
} | ||
const isEntityObject = (0, _helpers.isPlainObject)(entity) && !(entity instanceof RegExp); | ||
const isEntityArray = Array.isArray(entity) && isVariables; | ||
if (isEntityObject || isEntityArray) { | ||
Object.entries(topLevelValue).forEach(([key, valueOrDescriptor]) => { | ||
const isEntityArray = Array.isArray(entity); | ||
if (isEntityArray) { | ||
if (!isVariables) { | ||
throw new Error(entityName); | ||
} | ||
entity.forEach((entityElement, index) => { | ||
const isEntityElementObjectOrArray = (0, _helpers.isPlainObject)(entityElement) || Array.isArray(entityElement); | ||
if (!isEntityElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)('equals', entityElement)) { | ||
throw new Error(`${entityName}[${index}]`); | ||
} | ||
}); | ||
return; | ||
} | ||
const isEntityObject = (0, _helpers.isPlainObject)(entity); | ||
if (isEntityObject) { | ||
Object.entries(entity).forEach(([key, valueOrDescriptor]) => { | ||
const { | ||
@@ -46,13 +60,23 @@ checkMode, | ||
const isValueArray = Array.isArray(value); | ||
if (isValueArray && !isVariables) { | ||
if (isValueArray) { | ||
value.forEach((element, index) => { | ||
if (!(0, _helpers2.isDescriptorValueValid)(checkMode, element)) { | ||
if (isVariables) { | ||
if ((0, _helpers2.isDescriptorValueValid)(checkMode, element)) return; | ||
throw new Error(`${errorMessage}[${index}]`); | ||
} | ||
const isElementObjectOrArray = (0, _helpers.isPlainObject)(element) || Array.isArray(element); | ||
if (isElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(checkMode, element)) { | ||
throw new Error(`${errorMessage}[${index}]`); | ||
} | ||
}); | ||
return; | ||
} | ||
if (!(0, _helpers2.isDescriptorValueValid)(checkMode, value)) { | ||
if (isVariables) { | ||
if ((0, _helpers2.isDescriptorValueValid)(checkMode, value)) return; | ||
throw new Error(errorMessage); | ||
} | ||
const isValueObject = (0, _helpers.isPlainObject)(value); | ||
if (isValueObject || !(0, _helpers2.isDescriptorValueValid)(checkMode, value)) { | ||
throw new Error(errorMessage); | ||
} | ||
}); | ||
@@ -90,6 +114,31 @@ return; | ||
const isRouteHasDataProperty = ('data' in route); | ||
if (!isRouteHasDataProperty) { | ||
const isRouteHasQueueProperty = ('queue' in route); | ||
if (!isRouteHasDataProperty && !isRouteHasQueueProperty) { | ||
throw new Error(`routes[${index}]`); | ||
} | ||
if (isRouteHasDataProperty && isRouteHasQueueProperty) { | ||
throw new Error(`routes[${index}]`); | ||
} | ||
const { | ||
settings | ||
} = route; | ||
const isRouteSettingsObject = (0, _helpers.isPlainObject)(settings); | ||
if (isRouteHasQueueProperty) { | ||
try { | ||
(0, _validateQueue.validateQueue)(route.queue); | ||
if (!isRouteSettingsObject) { | ||
throw new Error('settings'); | ||
} | ||
if (!(isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling)) { | ||
throw new Error('settings.polling'); | ||
} | ||
} catch (error) { | ||
throw new Error(`routes[${index}].${error.message}`); | ||
} | ||
} | ||
if (isRouteHasDataProperty && isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling) { | ||
throw new Error(`routes[${index}].settings.polling`); | ||
} | ||
try { | ||
(0, _validateSettings.validateSettings)(route.settings); | ||
validateEntities(route.entities, operationType); | ||
@@ -96,0 +145,0 @@ (0, _validateInterceptors.validateInterceptors)(route.interceptors); |
@@ -10,2 +10,4 @@ "use strict"; | ||
var _validateInterceptors = require("../../validateInterceptors/validateInterceptors"); | ||
var _validateQueue = require("../../validateQueue/validateQueue"); | ||
var _validateSettings = require("../../validateSettings/validateSettings"); | ||
const ALLOWED_ENTITIES_BY_METHOD = { | ||
@@ -20,21 +22,33 @@ get: ['headers', 'cookies', 'query', 'params'], | ||
const validateEntity = (entity, entityName) => { | ||
const { | ||
checkMode: topLevelCheckMode, | ||
value: topLevelValue | ||
} = (0, _helpers.convertToEntityDescriptor)(entity); | ||
const isBody = entityName === 'body'; | ||
const isTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity); | ||
if (isTopLevelDescriptor && isBody) { | ||
if (!(0, _helpers2.isCheckModeValid)(topLevelCheckMode, 'body')) { | ||
const isEntityTopLevelDescriptor = (0, _helpers.isEntityDescriptor)(entity); | ||
if (isEntityTopLevelDescriptor) { | ||
if (!isBody) { | ||
throw new Error(entityName); | ||
} | ||
if (!(0, _helpers2.isCheckModeValid)(entity.checkMode, 'body')) { | ||
throw new Error('body.checkMode'); | ||
} | ||
if (!(0, _helpers2.isDescriptorValueValid)(topLevelCheckMode, topLevelValue, 'body')) { | ||
const errorMessage = 'body.value'; | ||
throw new Error(errorMessage); | ||
const isDescriptorValueObjectOrArray = (0, _helpers.isPlainObject)(entity.value) || Array.isArray(entity.value); | ||
if (!isDescriptorValueObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(entity.checkMode, entity.value)) { | ||
throw new Error('body.value'); | ||
} | ||
return; | ||
} | ||
const isEntityObject = (0, _helpers.isPlainObject)(entity) && !(entity instanceof RegExp); | ||
const isEntityArray = Array.isArray(entity) && isBody; | ||
if (isEntityObject || isEntityArray) { | ||
Object.entries(topLevelValue).forEach(([key, valueOrDescriptor]) => { | ||
const isEntityArray = Array.isArray(entity); | ||
if (isEntityArray) { | ||
if (!isBody) { | ||
throw new Error(entityName); | ||
} | ||
entity.forEach((entityElement, index) => { | ||
const isEntityElementObjectOrArray = (0, _helpers.isPlainObject)(entityElement) || Array.isArray(entityElement); | ||
if (!isEntityElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)('equals', entityElement)) { | ||
throw new Error(`${entityName}[${index}]`); | ||
} | ||
}); | ||
return; | ||
} | ||
const isEntityObject = (0, _helpers.isPlainObject)(entity); | ||
if (isEntityObject) { | ||
Object.entries(entity).forEach(([key, valueOrDescriptor]) => { | ||
const { | ||
@@ -50,13 +64,23 @@ checkMode, | ||
const isValueArray = Array.isArray(value); | ||
if (isValueArray && !isBody) { | ||
if (isValueArray) { | ||
value.forEach((element, index) => { | ||
if (!(0, _helpers2.isDescriptorValueValid)(checkMode, element)) { | ||
if (isBody) { | ||
if ((0, _helpers2.isDescriptorValueValid)(checkMode, element)) return; | ||
throw new Error(`${errorMessage}[${index}]`); | ||
} | ||
const isElementObjectOrArray = (0, _helpers.isPlainObject)(element) || Array.isArray(element); | ||
if (isElementObjectOrArray || !(0, _helpers2.isDescriptorValueValid)(checkMode, element)) { | ||
throw new Error(`${errorMessage}[${index}]`); | ||
} | ||
}); | ||
return; | ||
} | ||
if (!(0, _helpers2.isDescriptorValueValid)(checkMode, value)) { | ||
if (isBody) { | ||
if ((0, _helpers2.isDescriptorValueValid)(checkMode, value)) return; | ||
throw new Error(errorMessage); | ||
} | ||
const isValueObject = (0, _helpers.isPlainObject)(value); | ||
if (isValueObject || !(0, _helpers2.isDescriptorValueValid)(checkMode, value)) { | ||
throw new Error(errorMessage); | ||
} | ||
}); | ||
@@ -94,6 +118,31 @@ return; | ||
const isRouteHasDataProperty = ('data' in route); | ||
if (!isRouteHasDataProperty) { | ||
const isRouteHasQueueProperty = ('queue' in route); | ||
if (!isRouteHasDataProperty && !isRouteHasQueueProperty) { | ||
throw new Error(`routes[${index}]`); | ||
} | ||
if (isRouteHasDataProperty && isRouteHasQueueProperty) { | ||
throw new Error(`routes[${index}]`); | ||
} | ||
const { | ||
settings | ||
} = route; | ||
const isRouteSettingsObject = (0, _helpers.isPlainObject)(settings); | ||
if (isRouteHasQueueProperty) { | ||
try { | ||
(0, _validateQueue.validateQueue)(route.queue); | ||
if (!isRouteSettingsObject) { | ||
throw new Error('settings'); | ||
} | ||
if (!(isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling)) { | ||
throw new Error('settings.polling'); | ||
} | ||
} catch (error) { | ||
throw new Error(`routes[${index}].${error.message}`); | ||
} | ||
} | ||
if (isRouteHasDataProperty && isRouteSettingsObject && settings !== null && settings !== void 0 && settings.polling) { | ||
throw new Error(`routes[${index}].settings.polling`); | ||
} | ||
try { | ||
(0, _validateSettings.validateSettings)(route.settings); | ||
validateEntities(route.entities, method); | ||
@@ -100,0 +149,0 @@ (0, _validateInterceptors.validateInterceptors)(route.interceptors); |
@@ -9,2 +9,4 @@ "use strict"; | ||
var _filter = require("../filter/filter"); | ||
var _pagination = require("../pagination/pagination"); | ||
var _sort2 = require("../sort/sort"); | ||
const createNestedDatabaseRoutes = (router, database, storage) => { | ||
@@ -15,7 +17,48 @@ Object.keys(database).forEach(key => { | ||
router.route(collectionPath).get((request, response) => { | ||
var _request$query; | ||
let data = storage.read(key); | ||
if (request.query && Object.keys(request.query).length) { | ||
data = (0, _filter.filter)(data, request.query); | ||
const { | ||
_page, | ||
_limit, | ||
_begin, | ||
_end, | ||
_sort, | ||
_order, | ||
...filters | ||
} = request.query; | ||
data = (0, _filter.filter)(data, filters); | ||
} | ||
if ((_request$query = request.query) !== null && _request$query !== void 0 && _request$query._page) { | ||
data = (0, _pagination.pagination)(data, request.query); | ||
if (data._link) { | ||
const links = {}; | ||
const fullUrl = `${request.protocol}://${request.get('host')}${request.originalUrl}`; | ||
if (data._link.first) { | ||
links.first = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.first}`); | ||
} | ||
if (data._link.prev) { | ||
links.prev = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.prev}`); | ||
} | ||
if (data._link.next) { | ||
links.next = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.next}`); | ||
} | ||
if (data._link.last) { | ||
links.last = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.last}`); | ||
} | ||
data._link = { | ||
...data._link, | ||
...links | ||
}; | ||
response.links(links); | ||
} | ||
} | ||
if (request.query && request.query._sort) { | ||
data = (0, _sort2.sort)(data, request.query); | ||
} | ||
if (request.query._begin || request.query._end) { | ||
var _request$query$_begin; | ||
data = data.slice((_request$query$_begin = request.query._begin) !== null && _request$query$_begin !== void 0 ? _request$query$_begin : 0, request.query._end); | ||
response.set('X-Total-Count', data.length); | ||
} | ||
// ✅ important: | ||
@@ -22,0 +65,0 @@ // set 'Cache-Control' header for explicit browsers response revalidate |
@@ -1,1 +0,2 @@ | ||
export declare const filter: (array: any[], filters: Record<string, string | string[]>) => any[]; | ||
import type { ParsedUrlQuery } from 'node:querystring'; | ||
export declare const filter: (array: any[], filters: ParsedUrlQuery) => any[]; |
import type { IRouter } from 'express'; | ||
import type { GraphqlConfig, Interceptors } from '../../../utils/types'; | ||
export declare const createGraphQLRoutes: (router: IRouter, graphqlConfig: GraphqlConfig, serverResponseInterceptors?: Interceptors['response']) => IRouter; | ||
interface CreateGraphQLRoutesParams { | ||
router: IRouter; | ||
graphqlConfig: GraphqlConfig; | ||
serverResponseInterceptor?: Interceptors['response']; | ||
} | ||
export declare const createGraphQLRoutes: ({ router, graphqlConfig, serverResponseInterceptor }: CreateGraphQLRoutesParams) => IRouter; | ||
export {}; |
@@ -10,8 +10,12 @@ "use strict"; | ||
var _helpers2 = require("./helpers"); | ||
const createGraphQLRoutes = (router, graphqlConfig, serverResponseInterceptors) => { | ||
const createGraphQLRoutes = ({ | ||
router, | ||
graphqlConfig, | ||
serverResponseInterceptor | ||
}) => { | ||
const preparedGraphQLRequestConfig = (0, _helpers2.prepareGraphQLRequestConfigs)(graphqlConfig.configs); | ||
const graphqlMiddleware = async (request, response, next) => { | ||
var _matchedRequestConfig, _matchedRouteConfig$e, _matchedRouteConfig$i, _matchedRequestConfig2, _graphqlConfig$interc; | ||
var _matchedRequestConfig, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$i, _matchedRequestConfig2, _graphqlConfig$interc; | ||
const graphQLInput = (0, _helpers.getGraphQLInput)(request); | ||
if (!graphQLInput || !graphQLInput.query) { | ||
if (!graphQLInput.query) { | ||
return response.status(400).json({ | ||
@@ -27,12 +31,12 @@ message: 'Query is missing, you must pass a valid GraphQL query' | ||
} | ||
if (!query.operationName || !query.operationType) { | ||
return response.status(400).json({ | ||
message: `You should to specify operationName and operationType for ${request.method}:${request.baseUrl}${request.path}` | ||
}); | ||
} | ||
const matchedRequestConfig = preparedGraphQLRequestConfig.find(requestConfig => { | ||
if (requestConfig.operationName instanceof RegExp) { | ||
return new RegExp(requestConfig.operationName).test(query.operationName) && requestConfig.operationType === query.operationType; | ||
var _graphQLInput$query; | ||
if (requestConfig.operationType !== query.operationType) return false; | ||
if ('query' in requestConfig && requestConfig.query.replace(/\s+/gi, ' ') !== ((_graphQLInput$query = graphQLInput.query) === null || _graphQLInput$query === void 0 ? void 0 : _graphQLInput$query.replace(/\s+/gi, ' '))) return false; | ||
if ('operationName' in requestConfig) { | ||
if (!query.operationName) return false; | ||
if (requestConfig.operationName instanceof RegExp) return new RegExp(requestConfig.operationName).test(query.operationName); | ||
return requestConfig.operationName === query.operationName; | ||
} | ||
return requestConfig.operationName === query.operationName && requestConfig.operationType === query.operationType; | ||
return true; | ||
}); | ||
@@ -54,21 +58,25 @@ if (!matchedRequestConfig) { | ||
const entries = Object.entries(entities); | ||
return entries.every(([entityName, valueOrDescriptor]) => { | ||
return entries.every(([entityName, entityDescriptorOrValue]) => { | ||
const { | ||
checkMode, | ||
value: descriptorValue | ||
} = (0, _helpers.convertToEntityDescriptor)(valueOrDescriptor); | ||
value: entityDescriptorValue | ||
} = (0, _helpers.convertToEntityDescriptor)(entityDescriptorOrValue); | ||
// ✅ important: check whole variables as plain value strictly if descriptor used for variables | ||
const isVariablesPlain = entityName === 'variables' && (0, _helpers.isEntityDescriptor)(valueOrDescriptor); | ||
if (isVariablesPlain) { | ||
// ✅ important: getGraphQLInput returns empty object if variables not sent or invalid, so count {} as undefined | ||
return (0, _helpers.resolveEntityValues)(checkMode, Object.keys(graphQLInput.variables).length ? graphQLInput.variables : undefined, descriptorValue); | ||
const isEntityVariablesByTopLevelDescriptor = entityName === 'variables' && (0, _helpers.isEntityDescriptor)(entityDescriptorOrValue); | ||
if (isEntityVariablesByTopLevelDescriptor) { | ||
return (0, _helpers.resolveEntityValues)(checkMode, graphQLInput.variables, entityDescriptorValue); | ||
} | ||
const mappedEntityDescriptors = Object.entries(valueOrDescriptor); | ||
return mappedEntityDescriptors.every(([entityKey, mappedEntityDescriptor]) => { | ||
const isEntityVariablesByTopLevelArray = entityName === 'variables' && Array.isArray(entityDescriptorOrValue); | ||
if (isEntityVariablesByTopLevelArray) { | ||
return entityDescriptorOrValue.some(entityDescriptorOrValueElement => (0, _helpers.resolveEntityValues)(checkMode, graphQLInput.variables, entityDescriptorOrValueElement)); | ||
} | ||
const recordOrArrayEntries = Object.entries(entityDescriptorOrValue); | ||
return recordOrArrayEntries.every(([entityKey, entityValue]) => { | ||
const { | ||
checkMode, | ||
value: descriptorValue | ||
} = (0, _helpers.convertToEntityDescriptor)(mappedEntityDescriptor); | ||
} = (0, _helpers.convertToEntityDescriptor)(entityValue); | ||
const flattenEntity = (0, _flat.flatten)(entityName === 'variables' ? graphQLInput.variables : request[entityName]); | ||
// ✅ important: transform header keys to lower case because browsers send headers in lowercase | ||
@@ -82,5 +90,38 @@ return (0, _helpers.resolveEntityValues)(checkMode, flattenEntity[entityName === 'headers' ? entityKey.toLowerCase() : entityKey], descriptorValue); | ||
} | ||
const matchedRouteConfigData = typeof matchedRouteConfig.data === 'function' ? await matchedRouteConfig.data(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfig.data; | ||
let matchedRouteConfigData = null; | ||
if ((_matchedRouteConfig$s = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s !== void 0 && _matchedRouteConfig$s.polling && 'queue' in matchedRouteConfig) { | ||
var _shallowMatchedRouteC; | ||
if (!matchedRouteConfig.queue.length) return next(); | ||
const shallowMatchedRouteConfig = matchedRouteConfig; | ||
let index = (_shallowMatchedRouteC = shallowMatchedRouteConfig.__pollingIndex) !== null && _shallowMatchedRouteC !== void 0 ? _shallowMatchedRouteC : 0; | ||
const { | ||
time, | ||
data | ||
} = matchedRouteConfig.queue[index]; | ||
const updateIndex = () => { | ||
if (matchedRouteConfig.queue.length - 1 === index) { | ||
index = 0; | ||
} else { | ||
index += 1; | ||
} | ||
shallowMatchedRouteConfig.__pollingIndex = index; | ||
}; | ||
if (time && !shallowMatchedRouteConfig.__timeoutInProgress) { | ||
shallowMatchedRouteConfig.__timeoutInProgress = true; | ||
setTimeout(() => { | ||
shallowMatchedRouteConfig.__timeoutInProgress = false; | ||
updateIndex(); | ||
}, time); | ||
} | ||
if (!time && !shallowMatchedRouteConfig.__timeoutInProgress) { | ||
updateIndex(); | ||
} | ||
matchedRouteConfigData = data; | ||
} | ||
if ('data' in matchedRouteConfig) { | ||
matchedRouteConfigData = matchedRouteConfig.data; | ||
} | ||
const resolvedData = typeof matchedRouteConfigData === 'function' ? await matchedRouteConfigData(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfigData; | ||
const data = await (0, _helpers.callResponseInterceptors)({ | ||
data: matchedRouteConfigData, | ||
data: resolvedData, | ||
request, | ||
@@ -92,3 +133,3 @@ response, | ||
apiInterceptor: (_graphqlConfig$interc = graphqlConfig.interceptors) === null || _graphqlConfig$interc === void 0 ? void 0 : _graphqlConfig$interc.response, | ||
serverInterceptor: serverResponseInterceptors | ||
serverInterceptor: serverResponseInterceptor | ||
} | ||
@@ -95,0 +136,0 @@ }); |
@@ -25,5 +25,3 @@ "use strict"; | ||
})) !== null && _rest$configs$filter$ !== void 0 ? _rest$configs$filter$ : []; | ||
const graphqlRequestConfigs = (_graphql$configs$filt = graphql === null || graphql === void 0 ? void 0 : graphql.configs.filter(({ | ||
operationName | ||
}) => !(operationName instanceof RegExp)).map(request => { | ||
const graphqlRequestConfigs = (_graphql$configs$filt = graphql === null || graphql === void 0 ? void 0 : graphql.configs.filter(request => 'operationName' in request && !(request.operationName instanceof RegExp)).map(request => { | ||
var _graphql$baseUrl; | ||
@@ -30,0 +28,0 @@ return { |
import type { Express } from 'express'; | ||
import type { RequestInterceptor } from '../../../utils/types'; | ||
export declare const requestInterceptorMiddleware: (server: Express, interceptor: RequestInterceptor) => void; | ||
interface RequestInterceptorMiddlewareParams { | ||
server: Express; | ||
path?: string; | ||
interceptor: RequestInterceptor; | ||
} | ||
export declare const requestInterceptorMiddleware: ({ server, path, interceptor }: RequestInterceptorMiddlewareParams) => void; | ||
export {}; |
@@ -8,4 +8,8 @@ "use strict"; | ||
var _helpers = require("../../../utils/helpers"); | ||
const requestInterceptorMiddleware = (server, interceptor) => { | ||
server.use((0, _helpers.asyncHandler)(async (request, _response, next) => { | ||
const requestInterceptorMiddleware = ({ | ||
server, | ||
path = '*', | ||
interceptor | ||
}) => { | ||
server.use(path, (0, _helpers.asyncHandler)(async (request, _response, next) => { | ||
await (0, _helpers.callRequestInterceptor)({ | ||
@@ -12,0 +16,0 @@ request, |
import type { IRouter } from 'express'; | ||
import type { Interceptors, RestConfig } from '../../../utils/types'; | ||
export declare const createRestRoutes: (router: IRouter, restConfig: RestConfig, serverResponseInterceptors?: Interceptors['response']) => IRouter; | ||
interface CreateRestRoutesParams { | ||
router: IRouter; | ||
restConfig: RestConfig; | ||
serverResponseInterceptor?: Interceptors['response']; | ||
} | ||
export declare const createRestRoutes: ({ router, restConfig, serverResponseInterceptor }: CreateRestRoutesParams) => IRouter; | ||
export {}; |
@@ -10,6 +10,10 @@ "use strict"; | ||
var _helpers2 = require("./helpers"); | ||
const createRestRoutes = (router, restConfig, serverResponseInterceptors) => { | ||
const createRestRoutes = ({ | ||
router, | ||
restConfig, | ||
serverResponseInterceptor | ||
}) => { | ||
(0, _helpers2.prepareRestRequestConfigs)(restConfig.configs).forEach(requestConfig => { | ||
router.route(requestConfig.path)[requestConfig.method]((0, _helpers.asyncHandler)(async (request, response, next) => { | ||
var _requestConfig$interc, _matchedRouteConfig$e, _matchedRouteConfig$i, _requestConfig$interc2, _restConfig$intercept; | ||
var _requestConfig$interc, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$i, _requestConfig$interc2, _restConfig$intercept; | ||
const requestInterceptor = (_requestConfig$interc = requestConfig.interceptors) === null || _requestConfig$interc === void 0 ? void 0 : _requestConfig$interc.request; | ||
@@ -27,16 +31,22 @@ if (requestInterceptor) { | ||
const entries = Object.entries(entities); | ||
return entries.every(([entityName, valueOrDescriptor]) => { | ||
return entries.every(([entityName, entityDescriptorOrValue]) => { | ||
const { | ||
checkMode, | ||
value: descriptorValue | ||
} = (0, _helpers.convertToEntityDescriptor)(valueOrDescriptor); | ||
} = (0, _helpers.convertToEntityDescriptor)(entityDescriptorOrValue); | ||
// ✅ important: check whole body as plain value strictly if descriptor used for body | ||
const isBodyPlain = entityName === 'body' && (0, _helpers.isEntityDescriptor)(valueOrDescriptor); | ||
if (isBodyPlain) { | ||
// ✅ important: bodyParser sets body to empty object if body not sent or invalid, so count {} as undefined | ||
const isEntityBodyByTopLevelDescriptor = entityName === 'body' && (0, _helpers.isEntityDescriptor)(entityDescriptorOrValue); | ||
if (isEntityBodyByTopLevelDescriptor) { | ||
// ✅ important: bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
return (0, _helpers.resolveEntityValues)(checkMode, Object.keys(request.body).length ? request.body : undefined, descriptorValue); | ||
} | ||
const mappedEntityDescriptors = Object.entries(valueOrDescriptor); | ||
return mappedEntityDescriptors.every(([entityKey, mappedEntityDescriptor]) => { | ||
const isEntityBodyByTopLevelArray = entityName === 'body' && Array.isArray(entityDescriptorOrValue); | ||
if (isEntityBodyByTopLevelArray) { | ||
return entityDescriptorOrValue.some(entityDescriptorOrValueElement => | ||
// ✅ important: bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
(0, _helpers.resolveEntityValues)(checkMode, Object.keys(request.body).length ? request.body : undefined, entityDescriptorOrValueElement)); | ||
} | ||
const recordOrArrayEntries = Object.entries(entityDescriptorOrValue); | ||
return recordOrArrayEntries.every(([entityKey, mappedEntityDescriptor]) => { | ||
const { | ||
@@ -55,5 +65,38 @@ checkMode, | ||
} | ||
const matchedRouteConfigData = typeof matchedRouteConfig.data === 'function' ? await matchedRouteConfig.data(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfig.data; | ||
let matchedRouteConfigData = null; | ||
if ((_matchedRouteConfig$s = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s !== void 0 && _matchedRouteConfig$s.polling && 'queue' in matchedRouteConfig) { | ||
var _shallowMatchedRouteC; | ||
if (!matchedRouteConfig.queue.length) return next(); | ||
const shallowMatchedRouteConfig = matchedRouteConfig; | ||
let index = (_shallowMatchedRouteC = shallowMatchedRouteConfig.__pollingIndex) !== null && _shallowMatchedRouteC !== void 0 ? _shallowMatchedRouteC : 0; | ||
const { | ||
time, | ||
data | ||
} = matchedRouteConfig.queue[index]; | ||
const updateIndex = () => { | ||
if (matchedRouteConfig.queue.length - 1 === index) { | ||
index = 0; | ||
} else { | ||
index += 1; | ||
} | ||
shallowMatchedRouteConfig.__pollingIndex = index; | ||
}; | ||
if (time && !shallowMatchedRouteConfig.__timeoutInProgress) { | ||
shallowMatchedRouteConfig.__timeoutInProgress = true; | ||
setTimeout(() => { | ||
shallowMatchedRouteConfig.__timeoutInProgress = false; | ||
updateIndex(); | ||
}, time); | ||
} | ||
if (!time && !shallowMatchedRouteConfig.__timeoutInProgress) { | ||
updateIndex(); | ||
} | ||
matchedRouteConfigData = data; | ||
} | ||
if ('data' in matchedRouteConfig) { | ||
matchedRouteConfigData = matchedRouteConfig.data; | ||
} | ||
const resolvedData = typeof matchedRouteConfigData === 'function' ? await matchedRouteConfigData(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfigData; | ||
const data = await (0, _helpers.callResponseInterceptors)({ | ||
data: matchedRouteConfigData, | ||
data: resolvedData, | ||
request, | ||
@@ -65,3 +108,3 @@ response, | ||
apiInterceptor: (_restConfig$intercept = restConfig.interceptors) === null || _restConfig$intercept === void 0 ? void 0 : _restConfig$intercept.response, | ||
serverInterceptor: serverResponseInterceptors | ||
serverInterceptor: serverResponseInterceptor | ||
} | ||
@@ -68,0 +111,0 @@ }); |
@@ -35,3 +35,6 @@ "use strict"; | ||
if (serverRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, serverRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
interceptor: serverRequestInterceptor | ||
}); | ||
} | ||
@@ -38,0 +41,0 @@ const baseUrl = (_databaseMockServerCo2 = databaseMockServerConfig.baseUrl) !== null && _databaseMockServerCo2 !== void 0 ? _databaseMockServerCo2 : '/'; |
@@ -37,3 +37,6 @@ "use strict"; | ||
if (serverRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, serverRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
interceptor: serverRequestInterceptor | ||
}); | ||
} | ||
@@ -49,5 +52,9 @@ const baseUrl = (_graphqlMockServerCon2 = graphqlMockServerConfig.baseUrl) !== null && _graphqlMockServerCon2 !== void 0 ? _graphqlMockServerCon2 : '/'; | ||
} | ||
const routerWithGraphqlRoutes = (0, _graphql.createGraphQLRoutes)(_express.default.Router(), { | ||
configs | ||
}, interceptors === null || interceptors === void 0 ? void 0 : interceptors.response); | ||
const routerWithGraphqlRoutes = (0, _graphql.createGraphQLRoutes)({ | ||
router: _express.default.Router(), | ||
graphqlConfig: { | ||
configs | ||
}, | ||
serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response | ||
}); | ||
server.use(baseUrl, routerWithGraphqlRoutes); | ||
@@ -54,0 +61,0 @@ if (database) { |
@@ -39,3 +39,6 @@ "use strict"; | ||
if (serverRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, serverRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
interceptor: serverRequestInterceptor | ||
}); | ||
} | ||
@@ -52,19 +55,35 @@ const baseUrl = (_mockServerConfig$bas = mockServerConfig.baseUrl) !== null && _mockServerConfig$bas !== void 0 ? _mockServerConfig$bas : '/'; | ||
if (rest) { | ||
var _rest$interceptors, _rest$baseUrl; | ||
const routerWithRestRoutes = (0, _rest.createRestRoutes)(_express.default.Router(), rest, interceptors === null || interceptors === void 0 ? void 0 : interceptors.response); | ||
var _rest$baseUrl, _rest$interceptors; | ||
const routerWithRestRoutes = (0, _rest.createRestRoutes)({ | ||
router: _express.default.Router(), | ||
restConfig: rest, | ||
serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response | ||
}); | ||
const restBaseUrl = (0, _helpers.urlJoin)(baseUrl, (_rest$baseUrl = rest.baseUrl) !== null && _rest$baseUrl !== void 0 ? _rest$baseUrl : '/'); | ||
const apiRequestInterceptor = (_rest$interceptors = rest.interceptors) === null || _rest$interceptors === void 0 ? void 0 : _rest$interceptors.request; | ||
if (apiRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, apiRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
path: restBaseUrl, | ||
interceptor: apiRequestInterceptor | ||
}); | ||
} | ||
const restBaseUrl = (0, _helpers.urlJoin)(baseUrl, (_rest$baseUrl = rest.baseUrl) !== null && _rest$baseUrl !== void 0 ? _rest$baseUrl : '/'); | ||
server.use(restBaseUrl, routerWithRestRoutes); | ||
} | ||
if (graphql) { | ||
var _graphql$interceptors, _graphql$baseUrl; | ||
const routerWithGraphQLRoutes = (0, _graphql.createGraphQLRoutes)(_express.default.Router(), graphql, interceptors === null || interceptors === void 0 ? void 0 : interceptors.response); | ||
var _graphql$baseUrl, _graphql$interceptors; | ||
const routerWithGraphQLRoutes = (0, _graphql.createGraphQLRoutes)({ | ||
router: _express.default.Router(), | ||
graphqlConfig: graphql, | ||
serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response | ||
}); | ||
const graphqlBaseUrl = (0, _helpers.urlJoin)(baseUrl, (_graphql$baseUrl = graphql.baseUrl) !== null && _graphql$baseUrl !== void 0 ? _graphql$baseUrl : '/'); | ||
const apiRequestInterceptor = (_graphql$interceptors = graphql.interceptors) === null || _graphql$interceptors === void 0 ? void 0 : _graphql$interceptors.request; | ||
if (apiRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, apiRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
path: graphqlBaseUrl, | ||
interceptor: apiRequestInterceptor | ||
}); | ||
} | ||
const graphqlBaseUrl = (0, _helpers.urlJoin)(baseUrl, (_graphql$baseUrl = graphql.baseUrl) !== null && _graphql$baseUrl !== void 0 ? _graphql$baseUrl : '/'); | ||
server.use(graphqlBaseUrl, routerWithGraphQLRoutes); | ||
@@ -71,0 +90,0 @@ } |
@@ -37,3 +37,6 @@ "use strict"; | ||
if (serverRequestInterceptor) { | ||
(0, _middlewares.requestInterceptorMiddleware)(server, serverRequestInterceptor); | ||
(0, _middlewares.requestInterceptorMiddleware)({ | ||
server, | ||
interceptor: serverRequestInterceptor | ||
}); | ||
} | ||
@@ -49,5 +52,9 @@ const baseUrl = (_restMockServerConfig2 = restMockServerConfig.baseUrl) !== null && _restMockServerConfig2 !== void 0 ? _restMockServerConfig2 : '/'; | ||
} | ||
const routerWithRestRoutes = (0, _rest.createRestRoutes)(_express.default.Router(), { | ||
configs | ||
}, interceptors === null || interceptors === void 0 ? void 0 : interceptors.response); | ||
const routerWithRestRoutes = (0, _rest.createRestRoutes)({ | ||
router: _express.default.Router(), | ||
restConfig: { | ||
configs | ||
}, | ||
serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response | ||
}); | ||
server.use(baseUrl, routerWithRestRoutes); | ||
@@ -54,0 +61,0 @@ if (database) { |
@@ -0,8 +1,8 @@ | ||
export * from './createDatabaseMockServer/createDatabaseMockServer'; | ||
export * from './createGraphQLMockServer/createGraphQLMockServer'; | ||
export * from './createMockServer/createMockServer'; | ||
export * from './createRestMockServer/createRestMockServer'; | ||
export * from './createGraphQLMockServer/createGraphQLMockServer'; | ||
export * from './createDatabaseMockServer/createDatabaseMockServer'; | ||
export * from './startRestMockServer/startRestMockServer'; | ||
export * from './startDatabaseMockServer/startDatabaseMockServer'; | ||
export * from './startGraphQLMockServer/startGraphQLMockServer'; | ||
export * from './startMockServer/startMockServer'; | ||
export * from './startRestMockServer/startRestMockServer'; |
@@ -6,24 +6,13 @@ "use strict"; | ||
}); | ||
var _createMockServer = require("./createMockServer/createMockServer"); | ||
Object.keys(_createMockServer).forEach(function (key) { | ||
var _createDatabaseMockServer = require("./createDatabaseMockServer/createDatabaseMockServer"); | ||
Object.keys(_createDatabaseMockServer).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _createMockServer[key]) return; | ||
if (key in exports && exports[key] === _createDatabaseMockServer[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _createMockServer[key]; | ||
return _createDatabaseMockServer[key]; | ||
} | ||
}); | ||
}); | ||
var _createRestMockServer = require("./createRestMockServer/createRestMockServer"); | ||
Object.keys(_createRestMockServer).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _createRestMockServer[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _createRestMockServer[key]; | ||
} | ||
}); | ||
}); | ||
var _createGraphQLMockServer = require("./createGraphQLMockServer/createGraphQLMockServer"); | ||
@@ -40,21 +29,21 @@ Object.keys(_createGraphQLMockServer).forEach(function (key) { | ||
}); | ||
var _createDatabaseMockServer = require("./createDatabaseMockServer/createDatabaseMockServer"); | ||
Object.keys(_createDatabaseMockServer).forEach(function (key) { | ||
var _createMockServer = require("./createMockServer/createMockServer"); | ||
Object.keys(_createMockServer).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _createDatabaseMockServer[key]) return; | ||
if (key in exports && exports[key] === _createMockServer[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _createDatabaseMockServer[key]; | ||
return _createMockServer[key]; | ||
} | ||
}); | ||
}); | ||
var _startRestMockServer = require("./startRestMockServer/startRestMockServer"); | ||
Object.keys(_startRestMockServer).forEach(function (key) { | ||
var _createRestMockServer = require("./createRestMockServer/createRestMockServer"); | ||
Object.keys(_createRestMockServer).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _startRestMockServer[key]) return; | ||
if (key in exports && exports[key] === _createRestMockServer[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _startRestMockServer[key]; | ||
return _createRestMockServer[key]; | ||
} | ||
@@ -95,2 +84,13 @@ }); | ||
}); | ||
}); | ||
var _startRestMockServer = require("./startRestMockServer/startRestMockServer"); | ||
Object.keys(_startRestMockServer).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _startRestMockServer[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _startRestMockServer[key]; | ||
} | ||
}); | ||
}); |
document.getElementById('scheme_switcher').addEventListener('click', () => window.switchScheme()); |
@@ -22,3 +22,3 @@ const lightStyles = document.querySelector( | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
// eslint-disable-next-line no-unused-vars | ||
function switchScheme() { | ||
@@ -25,0 +25,0 @@ setScheme(getSavedScheme() === 'light' ? 'dark' : 'light'); |
@@ -0,0 +0,0 @@ function switchTab(activeTabId) { |
@@ -1,1 +0,2 @@ | ||
export declare const isEntityDescriptor: (value: any) => boolean; | ||
import type { EntityDescriptor } from '../../../types'; | ||
export declare const isEntityDescriptor: (value: any) => value is EntityDescriptor; |
import type { Request } from 'express'; | ||
import type { GraphQLInput } from '../../../types'; | ||
export declare const getGraphQLInput: (request: Request) => GraphQLInput; | ||
import type { PlainObject } from '../../../types'; | ||
interface GetGraphQLInputResult { | ||
query: string | undefined; | ||
variables: PlainObject | undefined; | ||
} | ||
export declare const getGraphQLInput: (request: Request) => GetGraphQLInputResult; | ||
export {}; |
@@ -9,3 +9,2 @@ "use strict"; | ||
if (request.method === 'GET') { | ||
var _ref; | ||
const { | ||
@@ -15,5 +14,8 @@ query, | ||
} = request.query; | ||
// ✅ important: | ||
// if 'variables' was sent as encoded uri component then it already decoded into object and we do not need to use JSON.parse | ||
return { | ||
query: query === null || query === void 0 ? void 0 : query.toString(), | ||
variables: JSON.parse((_ref = variables) !== null && _ref !== void 0 ? _ref : '{}') | ||
variables: typeof variables === 'string' ? JSON.parse(variables) : variables | ||
}; | ||
@@ -28,7 +30,7 @@ } | ||
query, | ||
variables: variables !== null && variables !== void 0 ? variables : {} | ||
variables | ||
}; | ||
} | ||
throw new Error('Not allowed request method for graphql request'); | ||
throw new Error(`Not allowed request method ${request.method} for graphql request`); | ||
}; | ||
exports.getGraphQLInput = getGraphQLInput; |
import type { OperationTypeNode } from 'graphql'; | ||
interface ParseDocumentNodeResult { | ||
operationType: OperationTypeNode; | ||
operationName: string; | ||
operationName: string | undefined; | ||
} | ||
export declare const parseQuery: (query: string) => ParseDocumentNodeResult | null; | ||
export {}; |
@@ -13,3 +13,3 @@ "use strict"; | ||
operationType: operationDefinition.operation, | ||
operationName: (_operationDefinition$ = (_operationDefinition$2 = operationDefinition.name) === null || _operationDefinition$2 === void 0 ? void 0 : _operationDefinition$2.value) !== null && _operationDefinition$ !== void 0 ? _operationDefinition$ : '' | ||
operationName: (_operationDefinition$ = (_operationDefinition$2 = operationDefinition.name) === null || _operationDefinition$2 === void 0 ? void 0 : _operationDefinition$2.value) !== null && _operationDefinition$ !== void 0 ? _operationDefinition$ : undefined | ||
}; | ||
@@ -16,0 +16,0 @@ }; |
@@ -17,17 +17,26 @@ "use strict"; | ||
const getHeaders = () => response.getHeaders(); | ||
const getCookie = name => request.cookies[name]; | ||
const setHeader = (field, value) => { | ||
response.set(field, value); | ||
}; | ||
const appendHeader = (field, value) => { | ||
response.append(field, value); | ||
}; | ||
const setStatusCode = statusCode => { | ||
response.statusCode = statusCode; | ||
}; | ||
const setHeader = (field, value) => response.set(field, value); | ||
const appendHeader = (field, value) => response.append(field, value); | ||
const getCookie = name => request.cookies[name]; | ||
const setCookie = (name, value, options) => { | ||
if (options) { | ||
response.cookie(name, value, options); | ||
return; | ||
} | ||
response.cookie(name, value); | ||
}; | ||
const clearCookie = (name, options) => response.clearCookie(name, options); | ||
const attachment = filename => response.attachment(filename); | ||
const ResponseInterceptorParams = { | ||
const clearCookie = (name, options) => { | ||
response.clearCookie(name, options); | ||
}; | ||
const attachment = filename => { | ||
response.attachment(filename); | ||
}; | ||
const responseInterceptorParams = { | ||
request, | ||
@@ -48,12 +57,12 @@ response, | ||
if (interceptors !== null && interceptors !== void 0 && interceptors.routeInterceptor) { | ||
updatedData = await interceptors.routeInterceptor(updatedData, ResponseInterceptorParams); | ||
updatedData = await interceptors.routeInterceptor(updatedData, responseInterceptorParams); | ||
} | ||
if (interceptors !== null && interceptors !== void 0 && interceptors.requestInterceptor) { | ||
updatedData = await interceptors.requestInterceptor(updatedData, ResponseInterceptorParams); | ||
updatedData = await interceptors.requestInterceptor(updatedData, responseInterceptorParams); | ||
} | ||
if (interceptors !== null && interceptors !== void 0 && interceptors.apiInterceptor) { | ||
updatedData = await interceptors.apiInterceptor(updatedData, ResponseInterceptorParams); | ||
updatedData = await interceptors.apiInterceptor(updatedData, responseInterceptorParams); | ||
} | ||
if (interceptors !== null && interceptors !== void 0 && interceptors.serverInterceptor) { | ||
updatedData = await interceptors.serverInterceptor(updatedData, ResponseInterceptorParams); | ||
updatedData = await interceptors.serverInterceptor(updatedData, responseInterceptorParams); | ||
} | ||
@@ -60,0 +69,0 @@ return updatedData; |
import type { Request } from 'express'; | ||
import type { CalculateByDescriptorValueCheckMode, CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { Interceptors } from './interceptors'; | ||
import type { Data, Primitive } from './values'; | ||
import type { NestedObjectOrArray } from './utils'; | ||
import type { Data } from './values'; | ||
export type GraphQLEntityName = 'headers' | 'cookies' | 'query' | 'variables'; | ||
export type GraphQLMappedEntityName = string; | ||
type GraphQLPlainEntityValue = string | number | boolean | null; | ||
type GraphQLMappedEntityValue = string | number | boolean; | ||
type GraphQLPlainEntityInnerValue = { | ||
checkMode?: undefined; | ||
call?: undefined; | ||
dotAll?: undefined; | ||
[key: string]: Primitive | GraphQLPlainEntityInnerValue; | ||
}; | ||
type GraphQLPlainEntityValue = { | ||
checkMode?: undefined; | ||
call?: undefined; | ||
forEach?: undefined; | ||
dotAll?: undefined; | ||
[key: string]: GraphQLPlainEntityInnerValue | Primitive | GraphQLEntityDescriptor; | ||
}; | ||
export type GraphQLOperationType = 'query' | 'mutation'; | ||
type GraphQLOperationName = string | RegExp; | ||
interface GraphQLQuery { | ||
operationType: GraphQLOperationType; | ||
operationName: GraphQLOperationName; | ||
} | ||
type GraphQLVariables = Record<string, any>; | ||
export interface GraphQLInput { | ||
query?: string; | ||
variables: GraphQLVariables; | ||
} | ||
type GraphQLEntityValue<EntityName = GraphQLEntityName> = EntityName extends 'variables' ? GraphQLPlainEntityValue : GraphQLMappedEntityValue; | ||
type GraphQLEntityValueOrValues<EntityName = GraphQLEntityName> = GraphQLEntityValue<EntityName> | GraphQLEntityValue<EntityName>[]; | ||
type GraphQLEntityDescriptor<EntityName extends GraphQLEntityName = GraphQLEntityName, Check extends CheckMode = CheckMode> = EntityName extends 'variables' ? Check extends Extract<CalculateByDescriptorValueCheckMode, 'function'> ? { | ||
export type GraphQLTopLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: any, checkFunction: CheckFunction) => boolean; | ||
value: (actualValue: NestedObjectOrArray<GraphQLPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: GraphQLEntityValueOrValues<EntityName>; | ||
value: NestedObjectOrArray<GraphQLPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: undefined; | ||
} : never : Check extends Extract<CalculateByDescriptorValueCheckMode, 'function'> ? { | ||
value: never; | ||
} : never; | ||
type GraphQLPropertyLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: any, checkFunction: CheckFunction) => boolean; | ||
} : Check extends Extract<CalculateByDescriptorValueCheckMode, 'regExp'> ? { | ||
value: (actualValue: GraphQLPlainEntityValue | NestedObjectOrArray<GraphQLPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: GraphQLPlainEntityValue | NestedObjectOrArray<GraphQLPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value: never; | ||
} : never; | ||
type GraphQLMappedEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: GraphQLMappedEntityValue, checkFunction: CheckFunction) => boolean; | ||
} : Check extends 'regExp' ? { | ||
checkMode: Check; | ||
value: RegExp | RegExp[]; | ||
} : Check extends CompareWithDescriptorValueCheckMode ? { | ||
checkMode: Check; | ||
value: GraphQLEntityValueOrValues<EntityName>; | ||
value: GraphQLMappedEntityValue | GraphQLMappedEntityValue[]; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: undefined; | ||
value: never; | ||
} : never; | ||
export type GraphQLEntityDescriptorOrValue<EntityName extends GraphQLEntityName = GraphQLEntityName> = EntityName extends 'variables' ? GraphQLEntityDescriptor<EntityName> | GraphQLEntityValue<EntityName> : Record<GraphQLMappedEntityName, GraphQLEntityDescriptor<EntityName> | GraphQLEntityValueOrValues<EntityName>>; | ||
export type GraphQLEntityDescriptorOnly<EntityName extends GraphQLEntityName = GraphQLEntityName> = EntityName extends 'variables' ? GraphQLEntityDescriptor<EntityName> : Record<GraphQLMappedEntityName, GraphQLEntityDescriptor<EntityName>>; | ||
export interface GraphQLEntityNamesByOperationType { | ||
query: GraphQLEntityName; | ||
mutation: GraphQLEntityName; | ||
} | ||
type GraphQLEntityByEntityName<OperationType extends GraphQLOperationType> = { | ||
[EntityName in GraphQLEntityNamesByOperationType[OperationType]]?: GraphQLEntityDescriptorOrValue<EntityName>; | ||
export type GraphQLEntityDescriptorOrValue<EntityName extends GraphQLEntityName = GraphQLEntityName> = EntityName extends 'variables' ? GraphQLTopLevelPlainEntityDescriptor | Record<string, GraphQLPropertyLevelPlainEntityDescriptor> | NestedObjectOrArray<GraphQLPlainEntityValue> : Record<string, GraphQLMappedEntityDescriptor | GraphQLMappedEntityValue | GraphQLMappedEntityValue[]>; | ||
export type GraphQLOperationType = 'query' | 'mutation'; | ||
export type GraphQLOperationName = string | RegExp; | ||
export type GraphQLEntityNamesByOperationType = { | ||
[operationType in GraphQLOperationType]: GraphQLEntityName; | ||
}; | ||
export interface GraphQLRouteConfig<OperationType extends GraphQLOperationType = GraphQLOperationType, Entities extends GraphQLEntityByEntityName<OperationType> = GraphQLEntityByEntityName<OperationType>> { | ||
entities?: Entities; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
export type GraphQLEntitiesByEntityName = { | ||
[EntityName in GraphQLEntityName]?: GraphQLEntityDescriptorOrValue<EntityName>; | ||
}; | ||
type GraphQLSettings = { | ||
readonly polling: boolean; | ||
}; | ||
export type GraphQLRouteConfig<Settings extends GraphQLSettings = GraphQLSettings> = ({ | ||
settings: Settings & { | ||
polling: true; | ||
}; | ||
queue: Array<{ | ||
time?: number; | ||
data: ((request: Request, entities: GraphQLEntitiesByEntityName) => Data | Promise<Data>) | Data; | ||
}>; | ||
} | { | ||
settings?: Settings & { | ||
polling?: false; | ||
}; | ||
data: ((request: Request, entities: GraphQLEntitiesByEntityName) => Data | Promise<Data>) | Data; | ||
}) & { | ||
entities?: GraphQLEntitiesByEntityName; | ||
interceptors?: Pick<Interceptors, 'response'>; | ||
} | ||
export interface GraphQLRequestConfig extends GraphQLQuery { | ||
}; | ||
interface BaseGraphQLRequestConfig { | ||
operationType: GraphQLOperationType; | ||
routes: GraphQLRouteConfig[]; | ||
interceptors?: Interceptors; | ||
} | ||
export interface OperationNameGraphQLRequestConfig extends BaseGraphQLRequestConfig { | ||
operationName: GraphQLOperationName; | ||
} | ||
interface QueryGraphQLRequestConfig extends BaseGraphQLRequestConfig { | ||
query: string; | ||
} | ||
export type GraphQLRequestConfig = OperationNameGraphQLRequestConfig | QueryGraphQLRequestConfig; | ||
export {}; |
@@ -7,2 +7,3 @@ export * from './checkModes'; | ||
export * from './server'; | ||
export * from './utils'; | ||
export * from './values'; |
@@ -72,2 +72,13 @@ "use strict"; | ||
}); | ||
var _utils = require("./utils"); | ||
Object.keys(_utils).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _utils[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _utils[key]; | ||
} | ||
}); | ||
}); | ||
var _values = require("./values"); | ||
@@ -74,0 +85,0 @@ Object.keys(_values).forEach(function (key) { |
@@ -11,3 +11,3 @@ import type { CookieOptions, Request, Response } from 'express'; | ||
} | ||
export type RequestInterceptor = (params: RequestInterceptorParams) => void; | ||
export type RequestInterceptor = (params: RequestInterceptorParams) => void | Promise<void>; | ||
export interface ResponseInterceptorParams { | ||
@@ -14,0 +14,0 @@ request: Request; |
import type { Request } from 'express'; | ||
import type { CalculateByDescriptorValueCheckMode, CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { Interceptors } from './interceptors'; | ||
import type { Data, Primitive } from './values'; | ||
import type { NestedObjectOrArray } from './utils'; | ||
import type { Data } from './values'; | ||
export type RestMethod = 'get' | 'post' | 'delete' | 'put' | 'patch' | 'options'; | ||
export type RestEntityName = 'headers' | 'cookies' | 'query' | 'params' | 'body'; | ||
export type RestMappedEntityKey = string; | ||
type RestPlainEntityValue = string | number | boolean | null; | ||
type RestMappedEntityValue = string | number | boolean; | ||
type RestPlainEntityInnerValue = { | ||
checkMode?: undefined; | ||
call?: undefined; | ||
dotAll?: undefined; | ||
[key: string]: Primitive | RestPlainEntityInnerValue; | ||
}; | ||
type RestPlainEntityValue = { | ||
checkMode?: undefined; | ||
call?: undefined; | ||
dotAll?: undefined; | ||
[key: string]: RestPlainEntityInnerValue | Primitive | RestEntityDescriptor; | ||
} | (RestPlainEntityInnerValue | Primitive | RestEntityDescriptor)[]; | ||
type RestEntityValue<EntityName = RestEntityName> = EntityName extends 'body' ? RestPlainEntityValue : RestMappedEntityValue; | ||
type RestEntityValueOrValues<EntityName = RestEntityName> = RestEntityValue<EntityName> | RestEntityValue<EntityName>[]; | ||
type RestEntityDescriptor<EntityName extends RestEntityName = RestEntityName, Check extends CheckMode = CheckMode> = EntityName extends 'body' ? Check extends Extract<CalculateByDescriptorValueCheckMode, 'function'> ? { | ||
export type RestTopLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: any, checkFunction: CheckFunction) => boolean; | ||
value: (actualValue: NestedObjectOrArray<RestPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: RestEntityValueOrValues<EntityName>; | ||
value: NestedObjectOrArray<RestPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: undefined; | ||
} : never : Check extends Extract<CalculateByDescriptorValueCheckMode, 'function'> ? { | ||
value: never; | ||
} : never; | ||
type RestPropertyLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: any, checkFunction: CheckFunction) => boolean; | ||
} : Check extends Extract<CalculateByDescriptorValueCheckMode, 'regExp'> ? { | ||
value: (actualValue: RestPlainEntityValue | NestedObjectOrArray<RestPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: RestPlainEntityValue | NestedObjectOrArray<RestPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value: never; | ||
} : never; | ||
type RestMappedEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: RestMappedEntityValue, checkFunction: CheckFunction) => boolean; | ||
} : Check extends 'regExp' ? { | ||
checkMode: Check; | ||
value: RegExp | RegExp[]; | ||
} : Check extends CompareWithDescriptorValueCheckMode ? { | ||
checkMode: Check; | ||
value: RestEntityValueOrValues<EntityName>; | ||
value: RestMappedEntityValue | RestMappedEntityValue[]; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: undefined; | ||
value: never; | ||
} : never; | ||
export type RestEntityDescriptorOrValue<EntityName extends RestEntityName = RestEntityName> = EntityName extends 'body' ? RestEntityDescriptor<EntityName> | RestEntityValue<EntityName> : Record<RestMappedEntityKey, RestEntityDescriptor<EntityName> | RestEntityValueOrValues<EntityName>>; | ||
export type RestEntityDescriptorOnly<EntityName extends RestEntityName = RestEntityName> = EntityName extends 'body' ? RestEntityDescriptor<EntityName> : Record<RestMappedEntityKey, RestEntityDescriptor<EntityName>>; | ||
export interface RestEntityNamesByMethod { | ||
get: Exclude<RestEntityName, 'body'>; | ||
delete: Exclude<RestEntityName, 'body'>; | ||
post: RestEntityName; | ||
put: RestEntityName; | ||
patch: RestEntityName; | ||
options: Exclude<RestEntityName, 'body'>; | ||
} | ||
export type RestEntityByEntityName<Method extends RestMethod> = { | ||
export type RestEntityDescriptorOrValue<EntityName extends RestEntityName = RestEntityName> = EntityName extends 'body' ? RestTopLevelPlainEntityDescriptor | Record<string, RestPropertyLevelPlainEntityDescriptor> | NestedObjectOrArray<RestPlainEntityValue> : Record<string, RestMappedEntityDescriptor | RestMappedEntityValue | RestMappedEntityValue[]>; | ||
export type RestEntityNamesByMethod = { | ||
[key in RestMethod]: key extends 'get' | 'delete' | 'options' ? Exclude<RestEntityName, 'body'> : RestEntityName; | ||
}; | ||
export type RestEntitiesByEntityName<Method extends RestMethod = RestMethod> = { | ||
[EntityName in RestEntityNamesByMethod[Method]]?: RestEntityDescriptorOrValue<EntityName>; | ||
}; | ||
export interface RestRouteConfig<Method extends RestMethod, Entities extends RestEntityByEntityName<Method> = RestEntityByEntityName<Method>> { | ||
interface RestSettings { | ||
readonly polling?: boolean; | ||
} | ||
export type RestRouteConfig<Method extends RestMethod, Entities extends RestEntitiesByEntityName<Method> = RestEntitiesByEntityName<Method>, Settings extends RestSettings = RestSettings> = ({ | ||
settings: Settings & { | ||
polling: true; | ||
}; | ||
queue: Array<{ | ||
time?: number; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
}>; | ||
} | { | ||
settings?: Settings & { | ||
polling: false; | ||
}; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
}) & { | ||
entities?: Entities; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
interceptors?: Pick<Interceptors, 'response'>; | ||
} | ||
}; | ||
export type RestPathString = `/${string}`; | ||
@@ -64,0 +71,0 @@ interface BaseRestRequestConfig<Method extends RestMethod> { |
export type PlainObject = Record<string, any>; | ||
export type PlainFunction = (...args: any[]) => any; | ||
export type Primitive = boolean | number | bigint | string | null | undefined | symbol; | ||
export type Data = boolean | number | string | any[] | Record<any, any> | null | undefined; |
{ | ||
"name": "mock-config-server", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "Tool that easily and quickly imitates server operation, create full fake api in few steps", | ||
@@ -5,0 +5,0 @@ "author": { |
156
README.md
@@ -76,3 +76,3 @@ # 🎉 Mock Config Server | ||
- `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors) | ||
- `database?` Database config for mock requests [read](#Database) | ||
- `database?` Database config for mock requests [read](#database) | ||
- `data` {Object | string} initial data for database | ||
@@ -103,3 +103,4 @@ - `routes?` {Object | string} map of custom routes for database | ||
- `operationType` {query | mutation} graphql operation type | ||
- `operationName` {string} graphql operation name | ||
- `operationName?` {string | RegExp} graphql operation name | ||
- `query?`: {string} graphql query as string | ||
- `routes` {GraphQLRouteConfig[]} request routes | ||
@@ -111,2 +112,4 @@ - `data` {any} mock data of request | ||
> Every graphql config should contain `operationName` or `query` or both of them | ||
##### Rest example | ||
@@ -276,2 +279,31 @@ | ||
Also you can use array as value for REST body and GraphQL variables entities: in this case mock-config-server will iterate | ||
over array until `checkMode=equals` finds a match or return 404 | ||
```javascript | ||
/** @type {import('mock-config-server').MockServerConfig} */ | ||
const mockServerConfig = { | ||
rest: { | ||
baseUrl: '/api', | ||
configs: [ | ||
{ | ||
path: '/user', | ||
method: 'post', | ||
routes: [ | ||
{ | ||
entities: { | ||
// if body equals to { key1: 'value1' } or ['value1'] then mock-config-server return data | ||
body: [{ key1: 'value1' }, ['value1']] | ||
}, | ||
data: 'Some user data' | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
module.exports = mockServerConfig; | ||
``` | ||
`function checkMode` is the most powerful way to describe your `entities` logic, but in most cases you will be fine using other `checkModes`. | ||
@@ -388,2 +420,62 @@ | ||
#### Polling | ||
Routes support polling for data. To add polling for data, you must specify the `polling setting` and change `data` property to `queue`. | ||
> After receiving the last value from polling, the queue is reset and the next request will return the first value from the queue. | ||
```javascript | ||
/** @type {import('mock-config-server').MockServerConfig} */ | ||
const mockServerConfig = { | ||
rest: { | ||
baseUrl: '/api', | ||
configs: [ | ||
{ | ||
path: '/user', | ||
method: 'get', | ||
routes: [ | ||
{ | ||
settings: { polling: true }, | ||
queue: [ | ||
{ data: { emoji: '🦁', name: 'Nursultan' } }, | ||
{ data: { emoji: '☄', name: 'Dmitriy' } } | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
export default mockServerConfig; | ||
``` | ||
Using the additional `time` properties in milliseconds, you can specify how much time certain data should be returned | ||
```javascript | ||
/** @type {import('mock-config-server').MockServerConfig} */ | ||
const mockServerConfig = { | ||
rest: { | ||
baseUrl: '/api', | ||
configs: [ | ||
{ | ||
path: '/user', | ||
method: 'get', | ||
routes: [ | ||
{ | ||
settings: { polling: true }, | ||
queue: [ | ||
{ time: 5000, data: { emoji: '🦁', name: 'Nursultan' } }, | ||
{ data: { emoji: '☄', name: 'Dmitriy' } } | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
export default mockServerConfig; | ||
``` | ||
#### Static Path | ||
@@ -555,2 +647,60 @@ | ||
### Pagination | ||
> Use \_page and optionally \_limit to paginate returned data. | ||
``` | ||
GET /users?_page=1 | ||
GET /users?_page=1&_limit=5 | ||
``` | ||
> **\_limit** is 10 by default | ||
The returned data has the format: | ||
``` | ||
{ | ||
_link: Link, | ||
results: Data[] | ||
} | ||
``` | ||
In the **Link** header you'll get **count**, **pages**, **next** and **prev** links. | ||
#### Link | ||
- `count` {number} total count of elements | ||
- `pages` {number} count of pages | ||
- `next` {string | null} query string for next link | ||
- `prev` {string | null} query string for prev link | ||
### Sort | ||
> Use \_sort and \_order, use . to access deep properties | ||
``` | ||
GET /users?_sort=name | ||
GET /users/1/transfers?_sort=id&_order=asc | ||
GET /users?_sort=address.city&_order=desc | ||
``` | ||
> **\_order** is 'asc' by default | ||
For multiple fields: | ||
``` | ||
GET /users?_sort=id&_order=desc&_sort=name&_order=asc | ||
``` | ||
### Slice | ||
> X-Total-Count header is included in the response | ||
``` | ||
GET /users?_begin=20 | ||
GET /users?_begin=20&_end=30 | ||
``` | ||
Works exactly as [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice), \_begin and \_end are optional | ||
### File example | ||
@@ -610,3 +760,3 @@ | ||
</a> | ||
</td> | ||
</td> | ||
<td align="center" style="word-wrap: break-word; width: 100.0; height: 100.0"> | ||
@@ -613,0 +763,0 @@ <a href="https://github.com/RiceWithMeat"> |
260740
262
4884
775