mock-config-server
Advanced tools
Comparing version 2.3.0 to 2.4.0
@@ -11,13 +11,17 @@ "use strict"; | ||
if (!graphQLInput || !graphQLInput.query) { | ||
return response.status(400).json('Query is missing, you must pass a valid GraphQL query'); | ||
return response | ||
.status(400) | ||
.json({ message: 'Query is missing, you must pass a valid GraphQL query' }); | ||
} | ||
const query = (0, helpers_1.parseQuery)(graphQLInput.query); | ||
if (!query) { | ||
return response.status(400).json('Query is invalid, you must use a valid GraphQL query'); | ||
} | ||
if (!query.operationName || !query.operationType) { | ||
return response | ||
.status(400) | ||
.json(`You should to specify operationName and operationType for ${request.method}:${request.baseUrl}${request.path}`); | ||
.json({ message: 'Query is invalid, you must use 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) => { | ||
@@ -24,0 +28,0 @@ if (requestConfig.operationName instanceof RegExp) { |
@@ -0,6 +1,11 @@ | ||
import type { GraphQLOperationType } from '../../../../../utils/types'; | ||
export type GraphqlRequestSuggestionConfigs = { | ||
operationType: GraphQLOperationType; | ||
operationName: string; | ||
}[]; | ||
interface GetGraphqlUrlSuggestionsParams { | ||
url: URL; | ||
graphqlPatternUrlMeaningfulStrings: string[]; | ||
requestConfigs: GraphqlRequestSuggestionConfigs; | ||
} | ||
export declare const getGraphqlUrlSuggestions: ({ url, graphqlPatternUrlMeaningfulStrings }: GetGraphqlUrlSuggestionsParams) => string[]; | ||
export declare const getGraphqlUrlSuggestions: ({ url, requestConfigs }: GetGraphqlUrlSuggestionsParams) => GraphqlRequestSuggestionConfigs; | ||
export {}; |
@@ -5,11 +5,12 @@ "use strict"; | ||
const getLevenshteinDistance_1 = require("../getLevenshteinDistance/getLevenshteinDistance"); | ||
const getGraphqlUrlSuggestions = ({ url, graphqlPatternUrlMeaningfulStrings }) => { | ||
const getGraphqlUrlSuggestions = ({ url, requestConfigs }) => { | ||
// ✅ important: operationName is always second word in 'query' query param | ||
const operationName = url.searchParams.get('query')?.split(' ')[1]; | ||
const actualUrlMeaningfulString = `${url.pathname}/${operationName}`; | ||
const graphqlUrlSuggestions = graphqlPatternUrlMeaningfulStrings.reduce((acc, patternUrlMeaningfulString) => { | ||
const distance = (0, getLevenshteinDistance_1.getLevenshteinDistance)(actualUrlMeaningfulString, patternUrlMeaningfulString); | ||
const tolerance = Math.floor(patternUrlMeaningfulString.length / 2); | ||
const actualOperationName = url.searchParams.get('query')?.split(' ')[1]; | ||
const actualUrlMeaningful = `${url.pathname}/${actualOperationName}`; | ||
const graphqlUrlSuggestions = requestConfigs.reduce((acc, requestConfig) => { | ||
const { operationName } = requestConfig; | ||
const distance = (0, getLevenshteinDistance_1.getLevenshteinDistance)(actualUrlMeaningful, operationName); | ||
const tolerance = Math.floor(operationName.length / 2); | ||
if (distance <= tolerance) | ||
acc.push(patternUrlMeaningfulString); | ||
acc.push(requestConfig); | ||
return acc; | ||
@@ -16,0 +17,0 @@ }, []); |
@@ -0,6 +1,11 @@ | ||
import type { RestMethod, RestPathString } from '../../../../../utils/types'; | ||
export type RestRequestSuggestionConfigs = { | ||
method: RestMethod; | ||
path: RestPathString; | ||
}[]; | ||
interface GetRestUrlSuggestionsParams { | ||
url: URL; | ||
patternUrls: string[]; | ||
requestConfigs: RestRequestSuggestionConfigs; | ||
} | ||
export declare const getRestUrlSuggestions: ({ url, patternUrls }: GetRestUrlSuggestionsParams) => string[]; | ||
export declare const getRestUrlSuggestions: ({ url, requestConfigs }: GetRestUrlSuggestionsParams) => RestRequestSuggestionConfigs; | ||
export {}; |
@@ -7,6 +7,6 @@ "use strict"; | ||
const helpers_2 = require("./helpers"); | ||
const getRestUrlSuggestions = ({ url, patternUrls }) => { | ||
const getRestUrlSuggestions = ({ url, requestConfigs }) => { | ||
const actualUrlParts = (0, helpers_1.getUrlParts)(url.pathname); | ||
const restUrlSuggestions = patternUrls.reduce((acc, patternUrl) => { | ||
const patternUrlParts = (0, helpers_1.getUrlParts)(patternUrl); | ||
const restUrlSuggestions = requestConfigs.reduce((acc, requestConfig) => { | ||
const patternUrlParts = (0, helpers_1.getUrlParts)(requestConfig.path); | ||
// ✅ important: ignore patterns with different amount of parts | ||
@@ -29,3 +29,3 @@ if (patternUrlParts.length !== actualUrlParts.length) | ||
const suggestionWithQueryParams = `/${urlSuggestion}${url.search}`; | ||
acc.push(suggestionWithQueryParams); | ||
acc.push({ ...requestConfig, path: suggestionWithQueryParams }); | ||
} | ||
@@ -32,0 +32,0 @@ return acc; |
@@ -8,38 +8,44 @@ "use strict"; | ||
const { baseUrl: serverBaseUrl, rest, graphql } = mockServerConfig; | ||
const operationNames = graphql?.configs.map(({ operationName }) => operationName) ?? []; | ||
const graphqlPatternUrlMeaningfulStrings = Array.from(operationNames.reduce((acc, operationName) => { | ||
if (typeof operationName === 'string') | ||
acc.add(`${serverBaseUrl ?? ''}${graphql?.baseUrl ?? ''}/${operationName}`); | ||
return acc; | ||
}, new Set())); | ||
const restPaths = rest?.configs.map(({ path }) => path) ?? []; | ||
const patternUrls = Array.from(restPaths.reduce((acc, patternPath) => { | ||
if (typeof patternPath === 'string') | ||
acc.add(`${serverBaseUrl ?? ''}${rest?.baseUrl ?? ''}${patternPath}`); | ||
return acc; | ||
}, new Set())); | ||
const restRequestConfigs = rest?.configs | ||
.filter(({ path }) => !(path instanceof RegExp)) | ||
.map((request) => ({ | ||
method: request.method, | ||
path: `${serverBaseUrl ?? ''}${rest?.baseUrl ?? ''}${request.path}` | ||
})) ?? []; | ||
const graphqlRequestConfigs = graphql?.configs | ||
.filter(({ operationName }) => !(operationName instanceof RegExp)) | ||
.map((request) => ({ | ||
operationType: request.operationType, | ||
operationName: `${serverBaseUrl ?? ''}${graphql?.baseUrl ?? ''} ${request.operationName}` | ||
})) ?? []; | ||
server.use((request, response) => { | ||
const url = new URL(`${request.protocol}://${request.get('host')}${request.originalUrl}`); | ||
let graphqlUrlSuggestions = []; | ||
if (graphql) { | ||
const graphqlQuery = (0, helpers_1.parseGraphQLRequest)(request); | ||
if (graphqlQuery) { | ||
graphqlUrlSuggestions = (0, helpers_2.getGraphqlUrlSuggestions)({ | ||
url, | ||
graphqlPatternUrlMeaningfulStrings | ||
}); | ||
} | ||
} | ||
let restUrlSuggestions = []; | ||
let restRequestSuggestions = []; | ||
if (rest) { | ||
restUrlSuggestions = (0, helpers_2.getRestUrlSuggestions)({ | ||
restRequestSuggestions = (0, helpers_2.getRestUrlSuggestions)({ | ||
url, | ||
patternUrls | ||
requestConfigs: restRequestConfigs | ||
}); | ||
} | ||
response.status(404).render('notFound', { | ||
requestMethod: request.method, | ||
url: `${url.pathname}${url.search}`, | ||
restUrlSuggestions, | ||
graphqlUrlSuggestions | ||
let graphqlRequestSuggestions = []; | ||
if (graphql && (0, helpers_1.parseGraphQLRequest)(request)) { | ||
graphqlRequestSuggestions = (0, helpers_2.getGraphqlUrlSuggestions)({ | ||
url, | ||
requestConfigs: graphqlRequestConfigs | ||
}); | ||
} | ||
const isRequestSupportHtml = request.headers.accept?.includes('text/html') || request.headers.accept?.includes('*/*'); | ||
if (isRequestSupportHtml) { | ||
response.status(404).render('pages/404', { | ||
restRequestSuggestions, | ||
graphqlRequestSuggestions | ||
}); | ||
return; | ||
} | ||
response.status(404).json({ | ||
message: 'Request or page not found. Similar requests in data', | ||
data: { | ||
restRequestSuggestions, | ||
graphqlRequestSuggestions | ||
} | ||
}); | ||
@@ -46,0 +52,0 @@ }); |
@@ -16,4 +16,5 @@ "use strict"; | ||
const server = (0, express_1.default)(); | ||
server.set('view engine', 'ejs'); | ||
server.set('views', (0, helpers_1.urlJoin)(__dirname, '../../static/views')); | ||
server.set('view engine', 'ejs'); | ||
server.use(express_1.default.static((0, helpers_1.urlJoin)(__dirname, '../../static/views'))); | ||
server.use(body_parser_1.default.urlencoded({ extended: false })); | ||
@@ -20,0 +21,0 @@ server.use(body_parser_1.default.json({ limit: '10mb' })); |
@@ -26,4 +26,5 @@ import type { Request } from 'express'; | ||
export type RestMethod = 'get' | 'post' | 'delete' | 'put' | 'patch' | 'options'; | ||
export type RestPathString = `/${string}`; | ||
export interface BaseRestRequestConfig<Method extends RestMethod> { | ||
path: `/${string}` | RegExp; | ||
path: RestPathString | RegExp; | ||
method: Method; | ||
@@ -30,0 +31,0 @@ routes: RestRouteConfig<Method>[]; |
{ | ||
"name": "mock-config-server", | ||
"version": "2.3.0", | ||
"version": "2.4.0", | ||
"description": "Tool that easily and quickly imitates server operation, create full fake api in few steps", | ||
@@ -44,2 +44,3 @@ "author": { | ||
"lint": "eslint . --ext ts --no-error-on-unmatched-pattern", | ||
"stylelint": "stylelint \"src/static/**/*.css\"", | ||
"format": "prettier --write {src,bin}/**/*.ts", | ||
@@ -49,2 +50,3 @@ "pretty": "yarn type && yarn format && yarn lint --fix" | ||
"lint-staged": { | ||
"*.css": "yarn stylelint", | ||
"*.js": "yarn format", | ||
@@ -60,3 +62,3 @@ "*.ts": "yarn pretty" | ||
"body-parser": "^1.20.0", | ||
"ejs": "^3.1.8", | ||
"ejs": "^3.1.9", | ||
"esbuild": "^0.17.8", | ||
@@ -82,2 +84,7 @@ "express": "^4.18.1", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"style-loader": "^3.3.2", | ||
"stylelint": "^15.6.1", | ||
"stylelint-config-prettier": "^9.0.5", | ||
"stylelint-config-standard": "^32.0.0", | ||
"stylelint-order": "^6.0.3", | ||
"husky": "^8.0.1", | ||
@@ -84,0 +91,0 @@ "jest": "^29.4.2", |
@@ -218,3 +218,3 @@ # 🎉 Mock Config Server | ||
- `origin` {string | RegExp | Array<string | RegExp> | Function | Promise } available origins from which requests can be made | ||
- `methods?` {Array<GET | POST | DELETE | PUT | PATCH>} available methods (default: `*`) | ||
- `methods?` {Array<GET | POST | DELETE | PUT | PATCH>} available methods (default: `GET,OPTIONS,PUT,PATCH,POST,DELETE`) | ||
- `allowedHeaders?` {Array<string>} allowed headers (default: `*`) | ||
@@ -221,0 +221,0 @@ - `exposedHeaders?` {Array<string>} exposed headers (default: `*`) |
278913
177
2542
25
Updatedejs@^3.1.9