在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):pa-bru/graphql-cost-analysis开源软件地址(OpenSource Url):https://github.com/pa-bru/graphql-cost-analysis开源编程语言(OpenSource Language):JavaScript 100.0%开源软件介绍(OpenSource Introduction):GraphQL Query Cost Analysis for graphql-jsA GraphQL request cost analyzer. This can be used to protect your GraphQL servers against DoS attacks, compute the data consumption per user and limit it. This package parses the request content and computes its cost with your GraphQL server cost configuration. Backend operations have different complexities and dynamic arguments (like a limit of items to retrieve). With this package you can define a cost setting on each GraphQL field/type with directives or a Type Map Object. Works with graphql-js reference implementation Type Map Object: An object containing types supported by your GraphQL server. InstallationInstall the package with npm $ npm install --save graphql-cost-analysis Simple SetupInit the cost analyzer import costAnalysis from 'graphql-cost-analysis'
const costAnalyzer = costAnalysis({
maximumCost: 1000,
}) Then add the validation rule to the GraphQL server (apollo-server, express-graphql...) Setup with express-graphql app.use(
'/graphql',
graphqlHTTP((req, res, graphQLParams) => ({
schema: MyGraphQLSchema,
graphiql: true,
validationRules: [
costAnalysis({
variables: graphQLParams.variables,
maximumCost: 1000,
}),
],
}))
) Setup with apollo-server-express app.use(
'/graphql',
graphqlExpress(req => {
return {
schema,
rootValue: null,
validationRules: [
costAnalysis({
variables: req.body.variables,
maximumCost: 1000,
}),
],
}
})
) costAnalysis ConfigurationThe
A Custom Cost for Each Field/TypeNow that your global configuration is set, you can define the cost calculation for each of your schema Field/Type. 2 Ways of defining Field/Type cost settings:
Cost Settings Arguments
Defining the Cost Settings via DirectivesTo define the cost settings of fields for which you want a custom cost calculation, just add a Example: # you can define a cost directive on a type
type TypeCost @cost(complexity: 3) {
string: String
int: Int
}
type Query {
# will have the default cost value
defaultCost: Int
# will have a cost of 2 because this field does not depend on its parent fields
customCost: Int @cost(useMultipliers: false, complexity: 2)
# complexity should be between 1 and 10
badComplexityArgument: Int @cost(complexity: 12)
# the cost will depend on the `limit` parameter passed to the field
# then the multiplier will be added to the `parent multipliers` array
customCostWithResolver(limit: Int): Int
@cost(multipliers: ["limit"], complexity: 4)
# for recursive cost
first(limit: Int): First
@cost(multipliers: ["limit"], useMultipliers: true, complexity: 2)
# you can override the cost setting defined directly on a type
overrideTypeCost: TypeCost @cost(complexity: 2)
getCostByType: TypeCost
# You can specify several field parameters in the `multipliers` array
# then the values of the corresponding parameters will be added together.
# here, the cost will be `parent multipliers` * (`first` + `last`) * `complexity
severalMultipliers(first: Int, last: Int): Int
@cost(multipliers: ["first", "last"])
}
type First {
# will have the default cost value
myString: String
# the cost will depend on the `limit` value passed to the field and the value of `complexity`
# and the parent multipliers args: here the `limit` value of the `Query.first` field
second(limit: Int): String @cost(multipliers: ["limit"], complexity: 2)
# the cost will be the value of the complexity arg even if you pass a `multipliers` array
# because `useMultipliers` is false
costWithoutMultipliers(limit: Int): Int
@cost(useMultipliers: false, multipliers: ["limit"])
} Defining the Cost Settings in a Type Map Object
Create a type Map Object representing your GraphQL schema and pass cost settings to each field for which you want a custom cost. Example: const myCostMap = {
Query: {
first: {
multipliers: ['limit'],
useMultipliers: true,
complexity: 3,
},
},
}
app.use(
'/graphql',
graphqlHTTP({
schema: MyGraphQLSchema,
validationRules: [
costAnalysis({
maximumCost: 1000,
costMap: myCostMap,
}),
],
})
) Using complex types (UnionType or InterfaceType)When using a UnionType or Interfaces, the highest of the nested fragments cost is used. Common interface fields outside of fragments are treated like regular fields. Given types: interface CommonType {
common: Int @cost(useMultipliers: false, complexity: 3)
}
type First implements CommonType {
common: Int
firstField: String @cost(useMultipliers: false, complexity: 5)
}
type Second implements CommonType {
common: Int
secondField: String @cost(useMultipliers: false, complexity: 8)
}
union FirstOrSecond = First | Second
type Query {
firstOrSecond: FirstOrSecond
commonType: CommonType
} and a query like query {
firstOrSecond {
... on First {
firstField
}
...secondFields
}
commonType {
common
...secondFields
}
}
fragment secondFields on Second {
secondField
} the complexity of the query will be
So the whole query has a complexity of 19 NoteIf you just need a simple query complexity analysis without the GraphQL Schema Language and without multipliers and/or depth of parent multipliers, I suggest you install graphql-query-complexity Licensegraphql-cost-analysis is MIT-licensed. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论