Skip to content

Commit 174b276

Browse files
committed
updates
1 parent aa4fbf9 commit 174b276

File tree

1 file changed

+69
-60
lines changed

1 file changed

+69
-60
lines changed

modules/ROOT/pages/security/securing-a-graphql-api.adoc

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -357,21 +357,40 @@ query {
357357
}
358358
----
359359

360-
This can be achieved with a package such as link:https://www.npmjs.com/package/graphql-depth-limit[graphql-depth-limit]:
360+
This can be achieved with link:https://escape.tech/graphql-armor/docs/plugins/max-depth/[GraphQL Armor]:
361361

362362
[source, typescript, indent=0]
363363
----
364-
import depthLimit from 'graphql-depth-limit'
365-
import express from 'express'
366-
import graphqlHTTP from 'express-graphql'
367-
import schema from './schema'
368-
369-
const app = express()
370-
371-
app.use('/graphql', graphqlHTTP((req, res) => ({
372-
schema,
373-
validationRules: [ depthLimit(10) ]
374-
})))
364+
import { ApolloServer } from '@apollo/server';
365+
import { startStandaloneServer } from '@apollo/server/standalone';
366+
import { ApolloArmor } from '@escape.tech/graphql-armor';
367+
import { readFileSync } from 'fs';
368+
369+
// Assume you have your schema definition in a string or file.
370+
const typeDefs = readFileSync('./your-schema.graphql', 'utf-8');
371+
const resolvers = { /* Your resolvers here. */ };
372+
// Instantiate GraphQL Armor and configure the maxDepth plugin.
373+
const armor = new ApolloArmor({
374+
maxDepth: {
375+
enabled: true,
376+
n: 5, // Sets the maximum allowed query depth to 5.
377+
},
378+
});
379+
380+
// Get the security plugins provided by Armor.
381+
const plugins = armor.protect();
382+
383+
const server = new ApolloServer({
384+
typeDefs,
385+
resolvers,
386+
plugins: [...plugins], // Add the armor plugins to Apollo Server.
387+
});
388+
389+
const { url } = await startStandaloneServer(server, {
390+
listen: { port: 4000 },
391+
});
392+
393+
console.log(`🚀 Server ready at ${url}`);
375394
----
376395

377396

@@ -393,46 +412,45 @@ query {
393412
}
394413
----
395414

396-
To avoid this, you can cap the input number directly in your resolvers, for example like this:
415+
You can prevent denial of service attacks based on queries such as this by paginating query results.
416+
417+
A server-side pagination solution based on type definitions could look like this:
397418

398419
[source, graphql, indent=0]
399420
----
400-
// example
401-
----
421+
type PageInfo {
422+
startCursor: String
423+
endCursor: String
424+
hasNextPage: Boolean!
425+
hasPreviousPage: Boolean!
426+
}
402427
403-
Alternatively, use a library such as link:https://github.com/joonhocho/graphql-input-number[graphql-input-number]:
428+
// Connection types for nested data (Products within an Order)
429+
type ProductEdge {
430+
node: Product!
431+
cursor: String!
432+
}
404433
405-
[source, typescript, indent=0]
406-
----
407-
import {
408-
GraphQLInputInt,
409-
GraphQLInputFloat,
410-
} from 'graphql-input-number';
411-
412-
const argType = GraphQLInputInt({
413-
name: 'OneToNineInt',
414-
min: 1,
415-
max: 9,
416-
});
434+
type ProductConnection {
435+
edges: [ProductEdge!]!
436+
pageInfo: PageInfo!
437+
}
417438
418-
new GraphQLObjectType({
419-
name: 'Query',
420-
fields: {
421-
input: {
422-
type: GraphQLInt,
423-
args: {
424-
number: {
425-
type: argType,
426-
},
427-
},
428-
resolve: (_, {number}) => {
429-
430-
// 'number' IS AN INT BETWEEN 1 to 9.
431-
432-
};
433-
},
434-
},
435-
});
439+
// Connection types for root-level data (Orders list)
440+
type OrderEdge {
441+
node: Order!
442+
cursor: String!
443+
}
444+
445+
type OrderConnection {
446+
edges: [OrderEdge!]!
447+
pageInfo: PageInfo!
448+
}
449+
450+
// The root query that is targeted
451+
type Query {
452+
orders(first: Int, after: String, last: Int, before: String): OrderConnection
453+
}
436454
----
437455

438456

@@ -443,30 +461,21 @@ There is more than one approach.
443461
Several are outlined in the following sections.
444462

445463

446-
==== Rate limit scores
447-
448-
Refer to GitHub's link:https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#primary-rate-limit-for-authenticated-users[Rate limits for the REST API].
449-
450-
451464
==== Query cost points
452465

453-
The link:https://shopify.dev/docs/api/usage/limits#the-leaky-bucket-algorithm[leaky bucket algorithm].
466+
The link:https://shopify.dev/docs/api/usage/limits#the-leaky-bucket-algorithm[leaky bucket algorithm] represents an algorithmic solution to slow down the processing of multiple requests at once.
454467

455-
==== Query cost analysis
456468

457-
link:https://github.com/pa-bru/graphql-cost-analysis[graphql-cost-analysis]
469+
==== Query cost analysis
458470

471+
link:https://escape.tech/graphql-armor/docs/plugins/cost-limit/[GraphQL Armor] offers a way to limit the cost of GraphQL queries.
459472

460473
=== Use timeouts
461474

462475
To prevent the API from not responding or falling victim to denial of service attacks, it is feasible to make use of timeouts.
463-
This way, subsequent queries will not be blocked by a long-running previous query.
464-
465-
There are many ways and places to use timeouts.
466-
Here are a few examples.
467-
468-
// examples
476+
This way, subsequent queries aren't blocked by a long-running previous query.
469477

478+
You can set a timeout via the GraphQL Library driver, see xref:driver-configuration.adoc#_transaction_configuration_in_context[Transaction configuration in context].
470479

471480

472481
== Further reading

0 commit comments

Comments
 (0)