From 8a18884a85b5c6a2951c4aa4be69e2f3a1113ba2 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Fri, 4 Aug 2023 13:35:07 +0100 Subject: [PATCH 1/8] Small restructure of how-to guides, and improve Federation guide --- modules/ROOT/content-nav.adoc | 8 +- .../ROOT/pages/guides/apollo-federation.adoc | 175 ------------------ .../ROOT/pages/guides/frameworks/nextjs.adoc | 5 - modules/ROOT/pages/guides/index.adoc | 7 - .../pages/how-to-guides/create-project.adoc | 126 +++++++++++++ .../integrations/apollo-federation.adoc | 150 +++++++++++++++ .../how-to-guides/integrations/nextjs.adoc | 4 + 7 files changed, 285 insertions(+), 190 deletions(-) delete mode 100644 modules/ROOT/pages/guides/apollo-federation.adoc delete mode 100644 modules/ROOT/pages/guides/frameworks/nextjs.adoc delete mode 100644 modules/ROOT/pages/guides/index.adoc create mode 100644 modules/ROOT/pages/how-to-guides/create-project.adoc create mode 100644 modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc create mode 100644 modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index 95dc2d2e..0cb1417f 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -74,9 +74,11 @@ *** xref:reference/driver-configuration.adoc[] -** xref:guides/index.adoc[] -*** xref:guides/apollo-federation.adoc[] -*** xref:guides/frameworks/nextjs.adoc[] +** How-to guides +*** xref:how-to-guides/create-project.adoc[] +*** Integrations +**** xref:how-to-guides/integrations/apollo-federation.adoc[] +**** xref:how-to-guides/integrations/nextjs.adoc[] ** xref:troubleshooting.adoc[] diff --git a/modules/ROOT/pages/guides/apollo-federation.adoc b/modules/ROOT/pages/guides/apollo-federation.adoc deleted file mode 100644 index 6ce4c8c5..00000000 --- a/modules/ROOT/pages/guides/apollo-federation.adoc +++ /dev/null @@ -1,175 +0,0 @@ -[[apollo-federation]] -= Apollo Federation - beta - -WARNING: Apollo Federation is currently experimental. There will be missing functionality, and breaking changes may occur in patch and minor releases. It is not recommended to use it in a production environment. - -The Neo4j GraphQL Library can be used to generate a subgraph schema to be used as a part of a federated supergraph using https://www.apollographql.com/apollo-federation/[Apollo Federation]. - -== Usage - -This section will walk through setting up some example subgraphs using the Neo4j GraphQL Library, and composing them into a supergraph schema. - -=== Prerequisites - -Install Rover from Apollo by following their https://www.apollographql.com/docs/rover/getting-started[installation instructions]. - -The example subgraphs below assume that the database URI is stored in an environment variable "NEO4J_URI", and the password in "NEO4J_PASSWORD". - -Create a new directory, and within it, run the following commands to start a new npm project and install the dependencies: - -[source, bash, indent=0] ----- -npm init --yes -npm install @apollo/server @neo4j/graphql neo4j-driver ----- - -=== Example subgraphs - -NOTE: In the two subgraphs below, notice that `@shareable` has been applied to both of the `Location` definitions. -This is a necessary workaround because the Neo4j GraphQL Library generates identically named types for the `Location` definitions, which causes a collision when the Gateway stitches the two federated schemas. - -==== Locations - -Create a file `locations.js` with the following contents: - -[source, javascript, indent=0] ----- -import { ApolloServer } from '@apollo/server'; -import { startStandaloneServer } from '@apollo/server/standalone'; -import { Neo4jGraphQL } from "@neo4j/graphql"; -import neo4j from "neo4j-driver"; - -const typeDefs = `#graphql - extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0", - import: ["@key", "@shareable"]) - - type Location @key(fields: "id") @shareable { - id: ID! - "The name of the location" - name: String - "A short description about the location" - description: String - "The location's main photo as a URL" - photo: String - } -`; - -const driver = neo4j.driver( - process.env.NEO4J_URI, - neo4j.auth.basic("neo4j", process.env.NEO4J_PASSWORD) -); - -const neoSchema = new Neo4jGraphQL({ - typeDefs, - driver, -}); - -const schema = neoSchema.getSubgraphSchema(); - -const server = new ApolloServer({ - schema, -}); - -const { url } = startStandaloneServer(server, { listen: { port: 4001 } }); - -console.log(`🚀 Server ready at ${url}`); ----- - -Start this server by running `node locations.js`. - -==== Reviews - -Create a file `reviews.js` with the following contents: - -[source, javascript, indent=0] ----- -import { ApolloServer } from '@apollo/server'; -import { startStandaloneServer } from '@apollo/server/standalone'; -import { Neo4jGraphQL } from "@neo4j/graphql"; -import neo4j from "neo4j-driver"; - -const typeDefs = `#graphql - extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0", - import: ["@key", "@shareable"]) - - type Location @key(fields: "id") @shareable { - id: ID! - "The calculated overall rating based on all reviews" - overallRating: Float - "All submitted reviews about this location" - reviewsForLocation: [Review]! - } - - type Review { - id: ID! - "Written text" - comment: String - "A number from 1 - 5 with 1 being lowest and 5 being highest" - rating: Int - "The location the review is about" - location: Location! @relationship(type: "HAS_REVIEW", direction: IN) - } -`; - -const driver = neo4j.driver( - process.env.NEO4J_URI, - neo4j.auth.basic("neo4j", process.env.NEO4J_PASSWORD) -); - -const neoSchema = new Neo4jGraphQL({ - typeDefs, - driver, -}); - -const schema = neoSchema.getSubgraphSchema(); - -const server = new ApolloServer({ - schema, -}); - -const { url } = await startStandaloneServer(server, { listen: { port: 4002 } }); - -console.log(`🚀 Server ready at ${url}`); ----- - -Start this server by running `node reviews.js`. - -=== Supergraph composition - -Create a new file, `supergraph.yaml` - -[source, yaml, indent=0] ----- -federation_version: 2 -subgraphs: - locations: - routing_url: http://localhost:4001/ - schema: - subgraph_url: http://localhost:4001/ - reviews: - routing_url: http://localhost:4002/ - schema: - subgraph_url: http://localhost:4002/ ----- - -In the same directory, execute the following command to generate the supergraph schema: - -NOTE: The first time you run this command with a Federation 2 YAML configuration, Rover installs a separate plugin and prompts you to accept the terms and conditions of the ELv2 license. -Find more information in the https://www.apollographql.com/docs/federation/quickstart/local-composition/#2-perform-composition[Apollo Federation docs]. - -[source, bash, indent=0] ----- -rover supergraph compose --config supergraph.yaml > supergraph.graphql ----- - -Finally, execute the following commands to download Apollo Router and start the supergraph server: - -[source, bash, indent=0] ----- -curl -sSL https://router.apollo.dev/download/nix/latest | sh -./router --dev --supergraph supergraph.graphql ----- - -You should now be able to navigate to http://127.0.0.1:4000/ in a web browser to access Apollo Sandbox and query the supergraph. diff --git a/modules/ROOT/pages/guides/frameworks/nextjs.adoc b/modules/ROOT/pages/guides/frameworks/nextjs.adoc deleted file mode 100644 index 245632a0..00000000 --- a/modules/ROOT/pages/guides/frameworks/nextjs.adoc +++ /dev/null @@ -1,5 +0,0 @@ -[[usage-nextjs]] - -= Usage with Next.js - -We maintain an https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository on how to use `@neo4j/graphql` with Next. The example demonstrates how to use the Neo4j Movie Database with GraphQL and https://www.apollographql.com/docs/apollo-server/[Apollo Server 4]. diff --git a/modules/ROOT/pages/guides/index.adoc b/modules/ROOT/pages/guides/index.adoc deleted file mode 100644 index 42b00aa5..00000000 --- a/modules/ROOT/pages/guides/index.adoc +++ /dev/null @@ -1,7 +0,0 @@ -[[guides]] -= How-to Guides - -Here you can find a selection of guides to help you work with the Neo4j GraphQL Library. - -* xref::guides/apollo-federation.adoc[Apollo Federation (beta)] - guide on how to set up subgraphs using the Neo4j GraphQL Library. -* xref::guides/frameworks/nextjs.adoc[Usage with Next.js] - guide on how to use `@neo4j/graphql` with Next.js. \ No newline at end of file diff --git a/modules/ROOT/pages/how-to-guides/create-project.adoc b/modules/ROOT/pages/how-to-guides/create-project.adoc new file mode 100644 index 00000000..d74ace9d --- /dev/null +++ b/modules/ROOT/pages/how-to-guides/create-project.adoc @@ -0,0 +1,126 @@ += How to create a new project + +This guide shows you how to create a new project. + +This how-to guide assumes that you are familiar with the command line and JavaScript, and have https://nodejs.org/en[Node.js LTS] installed. The how-to guide contains options for both JavaScript and TypeScript. + +== 1. Create the project directory + +Create a directory for a new project and `cd` into it: + +[source, bash] +---- +mkdir neo4j-graphql-subgraph-example +cd neo4j-graphql-subgraph-example +---- + +== 2. Initialize the project + +Initialize a new Node.js project with `npm`: + +[source, bash] +---- +npm init --yes +npm pkg set type="module" +---- + +NOTE: This how-to guide sets up the project using ES Modules, which allows the usage of features such as top-level `await`. + +== 3. Language specific setup + +Follow the instructions below to set up with either TypeScript or JavaScript: + +.TypeScript +[%collapsible] +==== +. Create a `src` directory with an empty `index.ts` file to contain the entrypoint to your code for this project: ++ +[source, bash] +---- +mkdir src +touch src/index.ts +---- ++ +. Install the development dependencies required for working with a TypeScript project: ++ +[source, bash] +---- +npm install --save-dev typescript @types/node @tsconfig/node-lts +---- ++ +. Create an empty `tsconfig.json` file which will contain the compiler configuration for TypeScript: ++ +[source, bash] +---- +touch tsconfig.json +---- ++ +. Add the following configuration to the `tsconfig.json` file created above: ++ +[source, json] +---- +{ + "extends": "@tsconfig/node-lts/tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + } +} +---- ++ +NOTE: The configuration above extends the https://github.com/tsconfig/bases#node-lts-tsconfigjson[community base for Node.js LTS], provided by the `@tsconfig/node-lts` package installed above. For more information on the available options, see the https://www.typescriptlang.org/tsconfig[TypeScript Compiler docs]. ++ +. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: ++ +[source, json] +---- +{ + // ...etc. + "scripts": { + "compile": "tsc", + "start": "npm run compile && node ./dist/index.js" + } + // other dependencies +} +---- +==== + +.JavaScript +[%collapsible] +==== +. Create a `src` directory with an empty `index.js` file to contain the entrypoint to your code for this project: ++ +[source, bash] +---- +mkdir src +touch src/index.js +---- ++ +. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: ++ +[source, json] +---- +{ + // ...etc. + "scripts": { + "start": "node index.js" + } + // other dependencies +} +---- +==== + +== 4. Install dependencies + +The following dependencies are always required when using the Neo4j GraphQL Library: + +* `@neo4j/graphql` is the Neo4j GraphQL Library, which translates GraphQL into Cypher and returns the results. +* `graphql` is the reference implementation of the GraphQL specification. It is required for `@neo4j/graphql` to function. +* `neo4j-driver` is the library for the Neo4j driver, which is required to execute Cypher queries against the database. + +Install these dependencies by running the following command: + +[source, bash] +---- +npm install @neo4j/graphql graphql neo4j-driver +---- diff --git a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc new file mode 100644 index 00000000..66a1a931 --- /dev/null +++ b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc @@ -0,0 +1,150 @@ +[[apollo-federation]] += How to create a subgraph compatible with Apollo Federation + +This guide shows you how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. In this guide, the following monolithic schema will be converted into a subgraph schema for use behind a Federation gateway: + +[source, javascript] +---- +import { ApolloServer } from "@apollo/server"; +import { startStandaloneServer } from "@apollo/server/standalone"; +import { Neo4jGraphQL } from "@neo4j/graphql"; +import neo4j from "neo4j-driver"; + +const typeDefs = `#graphql + type User { + id: ID! + name: String! + } +`; + +const { + NEO4J_URI = "neo4j://localhost:7687/neo4j", + NEO4J_USERNAME = "neo4j", + NEO4J_PASSWORD = "password", +} = process.env; + +const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic(NEO4J_USERNAME, NEO4J_PASSWORD)); + +const neo4jgraphql = new Neo4jGraphQL({ + typeDefs, + driver, +}) + +const schema = await neo4jGraphQL.getSchema(); + +const server = new ApolloServer({ + schema, +}); + +const { url } = await startStandaloneServer(server); +console.log(`🚀 Server ready at ${url}`); +---- + +== 1. Create a new project + +Follow the steps in xref::how-to-guides/create-project.adoc. + +== 2. Install dependencies + +The core dependencies for a Neo4j GraphQL Library have already been installed in your new project. + +The final dependency to install is `@apollo/server`, the library for Apollo Server. It is used in this guide to host the subgraph. + +Run the following command to install this final package: + +[source, bash] +---- +npm install @apollo/server +---- + +== 3. Opt in to Federation + +For a set of type definitions to be usable as a subgraph for Federation, they must include the following schema extension: + +[source, javascript] +---- +const typeDefs = `#graphql + extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) + + type User { + id: ID! + name: String! + } +`; +---- + +NOTE: This example only includes the Federation `@key` directive. As you want to use more https://www.apollographql.com/docs/federation/federated-types/federated-directives[Federation directives], you will need to add them to the `import` array. + +== 4. Define an entity + +In order for other subgraphs to be able to contribute fields to the `Movie` type, we must define that type as an https://www.apollographql.com/docs/federation/entities/[entity]. You do this by using the `@key` directive to designate a field (or fields) as a key: + +[source, javascript] +---- +const typeDefs = `#graphql + extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) + + type User @key(fields: "id") { + id: ID! + name: String! + } +`; +---- + +NOTE: Whilst only the `@key` directive has been added in this example, you should consider using either the `@id` or `@unique` directive on the `id` field. The Federation gateway expects each key to resolve to one result, so it is good practice to ensure that these values are unique in the database. + +== 5. Generate a subgraph schema + +When using the Neo4j GraphQL Library, generating the subgraph schema is as simple as calling `getSubgraphSchema` instead of `getSchema`, so only the following line needs to be changed: + +[source, javascript] +---- +const schema = neo4jgraphql.getSubgraphSchema(); +---- + +== Complete example + +The above snippets are combined below: + +[source, javascript] +---- +import { ApolloServer } from "@apollo/server"; +import { startStandaloneServer } from "@apollo/server/standalone"; +import { Neo4jGraphQL } from "@neo4j/graphql"; + +const typeDefs = `#graphql + type User @key(fields: "id") { + id: ID! + name: String! + } +`; + +const { + NEO4J_URI = "neo4j://localhost:7687/neo4j", + NEO4J_USERNAME = "neo4j", + NEO4J_PASSWORD = "password", +} = process.env; + +const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic(NEO4J_USERNAME, NEO4J_PASSWORD)); + +const neo4jgraphql = new Neo4jGraphQL({ + typeDefs, + driver, +}) + +const schema = await neo4jGraphQL.getSubgraphSchema(); + +const server = new ApolloServer({ + schema, +}); + +const { url } = await startStandaloneServer(server); +console.log(`🚀 Server ready at ${url}`); +---- + +== Next steps + +The subgraph above can now be composed into a supergraph. The following guides from Apollo guide you through this: + +* https://www.apollographql.com/docs/federation/quickstart/studio-composition[Composition in Apollo Studio] +* https://www.apollographql.com/docs/federation/quickstart/local-composition[Local composition] diff --git a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc new file mode 100644 index 00000000..b0c4ec04 --- /dev/null +++ b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc @@ -0,0 +1,4 @@ += How to use the Neo4j GraphQL Library with Next.js + +We maintain an https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository on how to use the Neo4j GraphQL Library with Next.js. +The example demonstrates how to use Neo4j with https://neo4j.com/docs/getting-started/appendix/example-data/[the "Movies" example], the Neo4j GraphQL Library and https://www.apollographql.com/docs/apollo-server/[Apollo Server]. From 5af12cdb5068d80aacd7028b01051b8b78a8f574 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Fri, 4 Aug 2023 13:35:14 +0100 Subject: [PATCH 2/8] Fix incorrect code blocks --- .../pages/migration/v4-migration/index.adoc | 10 +- modules/ROOT/pages/subscriptions/engines.adoc | 25 +- modules/ROOT/pages/subscriptions/events.adoc | 276 ++++++++++++------ .../pages/subscriptions/getting-started.adoc | 29 +- modules/ROOT/pages/troubleshooting.adoc | 5 +- 5 files changed, 227 insertions(+), 118 deletions(-) diff --git a/modules/ROOT/pages/migration/v4-migration/index.adoc b/modules/ROOT/pages/migration/v4-migration/index.adoc index 72044213..e24c457d 100644 --- a/modules/ROOT/pages/migration/v4-migration/index.adoc +++ b/modules/ROOT/pages/migration/v4-migration/index.adoc @@ -49,25 +49,27 @@ Subscriptions are no longer configured as a plugin, but as a feature within the This means that, instead of: -```javascript +[source, javascript] +---- const neoSchema = new Neo4jGraphQL({ typeDefs, plugins: { subscriptions: plugin, }, }); -``` +---- Subscriptions are now defined as: -```javascript +[source, javascript] +---- const neoSchema = new Neo4jGraphQL({ typeDefs, features: { subscriptions: plugin, }, }); -``` +---- ==== Default subscriptions diff --git a/modules/ROOT/pages/subscriptions/engines.adoc b/modules/ROOT/pages/subscriptions/engines.adoc index e947c0e6..0a422593 100644 --- a/modules/ROOT/pages/subscriptions/engines.adoc +++ b/modules/ROOT/pages/subscriptions/engines.adoc @@ -7,7 +7,8 @@ There are different ways to how a GraphQL subscription may be set along with `@n == Default The default behavior is automatically set if the `subscriptions` feature is set to `true`, as described in xref::subscriptions/getting-started.adoc[Getting Started]: -```javascript +[source, javascript] +---- new Neo4jGraphQL({ typeDefs, driver, @@ -15,7 +16,7 @@ new Neo4jGraphQL({ subscriptions: true }, }); -``` +---- This behavior enables a simple subscription system that will work on a single instance, which is ideal for development, testing, and servers that do not require horizontal scaling. @@ -35,9 +36,10 @@ Some brokers supporting this protocol are: The plugin can be installed with `npm`: -```sh +[source, bash] +---- npm install @neo4j/graphql-amqp-subscriptions-engine -``` +---- NOTE: AMQP 1.0 is **not** supported by this plugin. @@ -46,7 +48,8 @@ NOTE: AMQP 1.0 is **not** supported by this plugin. The AMQP plugin should be instanced and passed to the `subscription` field in features. This will automatically enable the subscriptions with the AMQP broker as a message queue: -```javascript +[source, javascript] +---- const { Neo4jGraphQLAMQPSubscriptionsEngine } = require("@neo4j/graphql-amqp-subscriptions-engine"); const amqpSubscription = new Neo4jGraphQLAMQPSubscriptionsEngine({ @@ -64,7 +67,7 @@ const neoSchema = new Neo4jGraphQL({ subscriptions: amqpSubscription, }, }); -``` +---- === API The following options can be passed to the constructor: @@ -95,7 +98,8 @@ This is useful for setting up the connection to a broker. In case you want to handle subscriptions using link:https://redis.io/[redis]: -```javascript +[source, javascript] +---- // Note: This is an example of a custom subscription behavior and not a production ready redis implementation. class CustomRedisSubscriptionEngine { constructor(redisClient) { @@ -132,7 +136,7 @@ const neoSchema = new Neo4jGraphQL({ subscriptions: redisSubscriptions, }, }); -``` +---- Note that extra properties and methods are often needed to handle the connection to the broker. As long as the messages are sent to the broker in the `publish` method and that these messages are received and then emitted through the `events` property, the subscriptions will be properly handled. @@ -141,9 +145,10 @@ As long as the messages are sent to the broker in the `publish` method and that If using Typescript, you may import the interface `Neo4jGraphQLSubscriptionsEngine` to implement your own class. Ensure the API is correctly defined: -```typescript +[source, typescript] +---- class CustomRedisEngine implements Neo4jGraphQLSubscriptionsEngine {} -``` +---- [NOTE] ==== diff --git a/modules/ROOT/pages/subscriptions/events.adoc b/modules/ROOT/pages/subscriptions/events.adoc index 11a69c43..5d924fac 100644 --- a/modules/ROOT/pages/subscriptions/events.adoc +++ b/modules/ROOT/pages/subscriptions/events.adoc @@ -19,15 +19,19 @@ A subscription to a type can be made with the top-level subscription `[type]Crea ==== Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String } -``` +---- A subscription to any `Movie` created would look like: -```graphql + +[source, graphql] +---- subscription { movieCreated { createdMovie { @@ -38,7 +42,7 @@ subscription { timestamp } } -``` +---- [[update]] == Update Subscriptions @@ -59,15 +63,19 @@ A subscription to a type can be made with the top-level subscription `[type]Upda ==== Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String } -``` +---- A subscription to any `Movie` updated could look like: -```graphql + +[source, graphql] +---- subscription MovieUpdated { movieUpdated { event @@ -81,7 +89,7 @@ subscription MovieUpdated { timestamp } } -``` +---- [[delete]] == Delete Subscriptions @@ -91,6 +99,7 @@ Subscriptions to `DELETE` events will trigger on deleted nodes. NOTE: Only deleted nodes will trigger this event, deleted relationships will **not** trigger any event. === `DELETE` event + A subscription to a type can be made with the top-level subscription `[type]Deleted`. The subscription will contain the following fields: * `event`: The event triggering this subscription, in this case it will always be `"DELETE"`. @@ -99,15 +108,19 @@ A subscription to a type can be made with the top-level subscription `[type]Dele ==== Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String } -``` +---- A subscription to any deleted `Movie` would look like: -```graphql + +[source, graphql] +---- subscription { movieDeleted { deletedMovie { @@ -117,7 +130,7 @@ subscription { timestamp } } -``` +---- [[create_relationship]] == Create Relationship Subscriptions @@ -151,7 +164,9 @@ A subscription to a type can be made with the top-level subscription `[type]Rela NOTE: Irrespective of the relationship direction in the database, the `CREATE_RELATIONSHIP` event is bound to the type targeted for the subscription. The consequence is that - given a relationship between types A and B that is not reciprocal (that is, in the GraphQL schema type A defines a relationship to B but B does **not** define a relationship to A) and a GraphQL operation that creates the relationship between them - even though the two nodes will be connected in the database, the `CREATE_RELATIONSHIP` event will only be returned to the subscription to type A. Check out the xref:subscriptions/events.adoc#create-non-reciprocal-relationships[Non-reciprocal Relationships] section below for more details. For example, considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -175,10 +190,12 @@ type Reviewer { interface Reviewed @relationshipProperties { score: Int! } -``` +---- An ongoing subscription to created relationships on the `Movie` type, upon a mutation creating an `Actor` named `Tom Hardy` and a `Reviewer` named `Jane` to a `Movie` titled `Inception` would receive the following events: -```graphql + +[source, graphql] +---- { # 1 - relationship type `ACTED_IN` event: "CREATE_RELATIONSHIP", @@ -218,14 +235,16 @@ An ongoing subscription to created relationships on the `Movie` type, upon a mut } } } -``` +---- === Examples ==== Create Relationship with Standard Types For example, considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -239,10 +258,12 @@ type Actor { interface ActedIn @relationshipProperties { screenTime: Int! } -``` +---- A subscription to any `Movie` created relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipCreated { event @@ -262,7 +283,7 @@ subscription { } } } -``` +---- ==== Create Relationship with Abstract Types @@ -271,8 +292,11 @@ When using Abstract Types with relationships, you will need to specify one or mo These types are generated by the library and conform to the format `[type]EventPayload`, where `[type]` is a **Concrete Type**. ===== Union Example + Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -293,10 +317,12 @@ type Person { interface Directed @relationshipProperties { year: Int! } -``` +---- A subscription to any `Movie` created relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipCreated { event @@ -322,11 +348,13 @@ subscription { } } } -``` +---- ===== Interface Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -350,10 +378,12 @@ type Influencer implements Reviewer { interface Review @relationshipProperties { score: Int! } -``` +---- A subscription to any `Movie` created relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipCreated { event @@ -381,13 +411,15 @@ subscription { } } } -``` +---- [[create-non-reciprocal-relationships]] ==== Non-reciprocal relationships Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -414,7 +446,7 @@ interface ActedIn @relationshipProperties { interface Directed @relationshipProperties { year: Int! } -``` +---- The type definitions contain 2 relationships: types `ACTED_IN` and `DIRECTED`. @@ -425,7 +457,9 @@ It can be observed that the `ACTED_IN` relationship has a corresponding field de Let us now take a look at how we can subscribe to created relationships for the 3 types defined above: ===== Movie -```graphql + +[source, graphql] +---- subscription { movieRelationshipCreated { event @@ -457,14 +491,16 @@ subscription { } } } -``` +---- ==== Person As the `Person` type does not define any relationships, it is **not** possible to subscribe to `CREATE_RELATIONSHIP` events for this type. ===== Actor -```graphql + +[source, graphql] +---- subscription { actorRelationshipCreated { event @@ -485,12 +521,14 @@ subscription { } } } -``` +---- The presence of the `movie` field inside of `createdRelationship` for the `actorRelationshipCreated` subscription reflects the fact that the `ACTED_IN` typed relationship is reciprocal. Therefore, when a new relationship of this type is made, such as by running a mutation as follows: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -518,10 +556,12 @@ mutation { } } } -``` +---- Two events will be published (given that we subscribed to `CREATE_RELATIONSHIP` events on both types): -```graphql + +[source, graphql] +---- { # from `movieRelationshipCreated` event: "CREATE_RELATIONSHIP" @@ -559,10 +599,12 @@ Two events will be published (given that we subscribed to `CREATE_RELATIONSHIP` } } } -``` +---- Since the `DIRECTED` relationship between types `Movie` and `Director` is **not** reciprocal, executing a mutation as follows: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -605,10 +647,12 @@ mutation { } } } -``` +---- Two events will be published (given that we subscribed to `CREATE_RELATIONSHIP` events on the `Movie` type): -```graphql + +[source, graphql] +---- { # relationship 1 - from `movieRelationshipCreated` event: "CREATE_RELATIONSHIP" @@ -648,7 +692,7 @@ Two events will be published (given that we subscribed to `CREATE_RELATIONSHIP` } } } -``` +---- === Special Considerations @@ -661,7 +705,9 @@ This can be achieved using the `@node` directive, by specifying the `label` argu NOTE: While this section serves an informative purpose, it should be mentioned that, in the majority of cases, this is not the recommended approach of designing your API. Consider the following type definitions: -```graphql + +[source, graphql] +---- type Actor @node(label: "Person") { name: String movies: [Movie!]! @relationship(type: "PART_OF", direction: OUT) @@ -678,7 +724,7 @@ type Movie { people: [Person!]! @relationship(type: "PART_OF", direction: IN) actors: [Actor!]! @relationship(type: "PART_OF", direction: IN) } -``` +---- Although we have 3 GraphQL types, in Neo4j there will only ever be 2 types of nodes: labeled `Movie` or labeled `Person`. @@ -686,7 +732,8 @@ At the database level there is no distinction between `Actor` and `Person`. Ther Considering the following subscriptions: -```graphql +[source, graphql] +---- subscription { movieRelationshipCreated { event @@ -729,10 +776,12 @@ subscription { } } } -``` +---- Running a mutation as follows: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -766,10 +815,12 @@ mutation { } } } -``` +---- Results in the following events: -```graphql + +[source, graphql] +---- { # relationship 1 `people` - for GraphQL types `Movie`, `Person` event: "CREATE_RELATIONSHIP" @@ -876,10 +927,12 @@ Results in the following events: } } }, -``` +---- Had we subscribed to `Person` as well, we would have received two more events: -```graphql + +[source, graphql] +---- { # relationship 1 `movies` - for GraphQL types `Person`, `Movie` event: "CREATE_RELATIONSHIP" @@ -914,7 +967,7 @@ Had we subscribed to `Person` as well, we would have received two more events: } } }, -``` +---- [[delete_relationship]] == Delete Relationship Subscriptions @@ -948,7 +1001,9 @@ A subscription to a type can be made with the top-level subscription `[type]Rela NOTE: Irrespective of the relationship direction in the database, the `DELETE_RELATIONSHIP` event is bound to the type targeted for the subscription. The consequence is that - given a relationship between types A and B that is not reciprocal (that is, in the GraphQL schema type A defines a relationship to B but B does **not** define a relationship to A) and a GraphQL operation that deletes the relationship between them - even though the two nodes will be disconnected in the database, the `DELETE_RELATIONSHIP` event will only be returned to the subscription to type A. Check out the xref:subscriptions/events.adoc#delete-non-reciprocal-relationships[Non-reciprocal Relationships] section below for more details. For example, considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -972,10 +1027,12 @@ type Reviewer { interface Reviewed @relationshipProperties { score: Int! } -``` +---- An ongoing subscription to deleted relationships from the `Movie` type, upon a mutation deleting then `Actor` named `Tom Hardy` and the `Reviewer` named `Jane` from a `Movie` titled `Inception` would receive the following events: -```graphql + +[source, graphql] +---- { # 1 - relationship type `ACTED_IN` event: "DELETE_RELATIONSHIP", @@ -1015,14 +1072,16 @@ An ongoing subscription to deleted relationships from the `Movie` type, upon a m } } } -``` +---- === Examples ==== Delete Relationships with Standard Types For example, considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -1036,10 +1095,12 @@ type Actor { interface ActedIn @relationshipProperties { screenTime: Int! } -``` +---- A subscription to any `Movie` deleted relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipDeleted { event @@ -1059,7 +1120,7 @@ subscription { } } } -``` +---- ==== Delete Relationship with Abstract Types @@ -1069,7 +1130,9 @@ These types are generated by the library and conform to the format `[type]EventP ===== Union Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -1090,10 +1153,12 @@ type Person { interface Directed @relationshipProperties { year: Int! } -``` +---- A subscription to `Movie` deleted relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipDeleted { event @@ -1119,11 +1184,13 @@ subscription { } } } -``` +---- ===== Interface Example Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -1147,10 +1214,12 @@ type Influencer implements Reviewer { interface Review @relationshipProperties { score: Int! } -``` +---- A subscription to `Movie` deleted relationships would look like: -```graphql + +[source, graphql] +---- subscription { movieRelationshipDeleted { event @@ -1178,13 +1247,15 @@ subscription { } } } -``` +---- [[delete-non-reciprocal-relationships]] ==== Non-reciprocal relationships Considering the following type definitions: -```graphql + +[source, graphql] +---- type Movie { title: String genre: String @@ -1211,7 +1282,7 @@ interface ActedIn @relationshipProperties { interface Directed @relationshipProperties { year: Int! } -``` +---- The type definitions contain 2 relationships: types `ACTED_IN` and `DIRECTED`. @@ -1222,7 +1293,9 @@ It can be observed that the `ACTED_IN` relationship has a corresponding field de Let us now take a look at how we can subscribe to deleted relationships for the 3 types defined above: ===== Movie -```graphql + +[source, graphql] +---- subscription { movieRelationshipDeleted { event @@ -1254,14 +1327,16 @@ subscription { } } } -``` +---- ===== Person As the `Person` type does not define any relationships, it is **not** possible to subscribe to `DELETE_RELATIONSHIP` events for this type. ===== Actor -```graphql + +[source, graphql] +---- subscription { actorRelationshipDeleted { event @@ -1282,12 +1357,14 @@ subscription { } } } -``` +---- The presence of the `movie` field inside of `deletedRelationship` for the `actorRelationshipDeleted` subscription reflects the fact that the `ACTED_IN` typed relationship is reciprocal. Therefore, when a relationship of this type is deleted, such as by running the following mutations: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -1325,10 +1402,12 @@ mutation { nodesDeleted } } -``` +---- Two events will be published (given that we subscribed to `DELETE_RELATIONSHIP` events on both types): -```graphql + +[source, graphql] +---- { # from `movieRelationshipDeleted` event: "DELETE_RELATIONSHIP" @@ -1366,10 +1445,12 @@ Two events will be published (given that we subscribed to `DELETE_RELATIONSHIP` } } } -``` +---- Since the `DIRECTED` relationship between types `Movie` and `Director` is **not** reciprocal, executing the following mutations: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -1422,10 +1503,12 @@ mutation { nodesDeleted } } -``` +---- Two events will be published (given that we subscribed to `DELETE_RELATIONSHIP` events on the `Movie` type): -```graphql + +[source, graphql] +---- { # relationship 1 - from `movieRelationshipDeleted` event: "DELETE_RELATIONSHIP" @@ -1465,7 +1548,7 @@ Two events will be published (given that we subscribed to `DELETE_RELATIONSHIP` } } } -``` +---- === Special Considerations @@ -1477,7 +1560,9 @@ This can be achieved using the `@node` directive, by specifying the `label` argu NOTE: While this section serves an informative purpose, it should be mentioned that, in the majority of cases, this is not the recommended approach of designing your API. Consider the following type definitions: -```graphql + +[source, graphql] +---- type Actor @node(label: "Person") { name: String movies: [Movie!]! @relationship(type: "PART_OF", direction: OUT) @@ -1494,7 +1579,7 @@ type Movie { people: [Person!]! @relationship(type: "PART_OF", direction: IN) actors: [Actor!]! @relationship(type: "PART_OF", direction: IN) } -``` +---- Although we have 3 GraphQL types, in Neo4j there will only ever be 2 types of nodes: labeled `Movie` or labeled `Person`. @@ -1502,7 +1587,8 @@ At the database level there is no distinction between `Actor` and `Person`. Ther Considering the following subscriptions: -```graphql +[source, graphql] +---- subscription { movieRelationshipDeleted { event @@ -1545,10 +1631,12 @@ subscription { } } } -``` +---- Running the following mutations: -```graphql + +[source, graphql] +---- mutation { createMovies( input: [ @@ -1592,10 +1680,12 @@ mutation { nodesDeleted } } -``` +---- Result in the following events: -```graphql + +[source, graphql] +---- { # relationship 1 `people` - for GraphQL types `Movie`, `Person` event: "DELETE_RELATIONSHIP" @@ -1702,10 +1792,12 @@ Result in the following events: } } }, -``` +---- Had we subscribed to `Person` as well, we would have received two more events: -```graphql + +[source, graphql] +---- { # relationship 1 `movies` - for GraphQL types `Person`, `Movie` event: "DELETE_RELATIONSHIP" @@ -1740,4 +1832,4 @@ Had we subscribed to `Person` as well, we would have received two more events: } } }, -``` +---- diff --git a/modules/ROOT/pages/subscriptions/getting-started.adoc b/modules/ROOT/pages/subscriptions/getting-started.adoc index 406a2993..ea58063e 100644 --- a/modules/ROOT/pages/subscriptions/getting-started.adoc +++ b/modules/ROOT/pages/subscriptions/getting-started.adoc @@ -4,7 +4,8 @@ To get started with subscriptions you need a GraphQL server with subscription capabilities. You can enable them by passing the `subscriptions` feature to `Neo4jGraphQL`: -```javascript +[source, javascript] +---- new Neo4jGraphQL({ typeDefs, driver, @@ -12,7 +13,7 @@ new Neo4jGraphQL({ subscriptions: true }, }); -``` +---- == Example using Apollo and WebSockets For this example, we will use link:https://www.apollographql.com/[Apollo] and link:https://github.com/enisdenjo/graphql-ws[graphql-ws]. @@ -20,13 +21,17 @@ For this example, we will use link:https://www.apollographql.com/[Apollo] and li === Setting up the server Install the following dependencies: -```bash + +[source, bash] +---- npm i --save ws graphql-ws neo4j-driver @neo4j/graphql express @apollo/server body-parser cors -``` +---- The following code implements a simple `@apollo/server` server with subscriptions. You can find more examples and documentation on subscriptions in link:https://www.apollographql.com/docs/apollo-server/data/subscriptions/[Apollo's documentation]. -```javascript + +[source, javascript] +---- import { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@apollo/server/express4"; import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer"; @@ -116,7 +121,7 @@ async function main() { } main(); -``` +---- [NOTE] ==== @@ -126,7 +131,9 @@ If you need to scale horizontally for a production-ready application, see xref:: === GraphQL subscriptions With the previous server running, we have subscriptions available for `Movie` and `Actor`. We can subscribe to new movies created with the following statement: -```graphql + +[source, graphql] +---- subscription { movieCreated(where: { title: "The Matrix" }) { createdMovie { @@ -134,10 +141,12 @@ subscription { } } } -``` +---- Any new movie created with the matching title will trigger a subscription. You can try this with the following query: -```graphql + +[source, graphql] +---- mutation { createMovies(input: [{ title: "The Matrix" }]) { movies { @@ -145,7 +154,7 @@ mutation { } } } -``` +---- NOTE: This example uses the link:https://www.npmjs.com/package/graphql-ws[graphql-ws] implementation, if you are using Apollo Studio, make sure to select "graphql-ws" implementation in connection settings. diff --git a/modules/ROOT/pages/troubleshooting.adoc b/modules/ROOT/pages/troubleshooting.adoc index f96410aa..a62dcab4 100644 --- a/modules/ROOT/pages/troubleshooting.adoc +++ b/modules/ROOT/pages/troubleshooting.adoc @@ -142,13 +142,14 @@ You can ensure that the data is available to query by passing a bookmark into yo The following example will create inputs with `_emptyInput`: -```graphql +[source, graphql] +---- type Cookie { id: ID! @id owner: Owner! @relationship(type: "HAS_OWNER", direction: OUT) # f: String # If you don't want _emptyInput, uncomment this line. } -``` +---- === Relationship nullability isn't being enforced in my graph From c943ba0f70d8d35152a754202e600269de3b8e96 Mon Sep 17 00:00:00 2001 From: Darrell Warde <8117355+darrellwarde@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:24:20 +0100 Subject: [PATCH 3/8] Update modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc Co-authored-by: Lidia Zuin <102308961+lidiazuin@users.noreply.github.com> --- modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc index b0c4ec04..096ed655 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc +++ b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc @@ -1,4 +1,4 @@ = How to use the Neo4j GraphQL Library with Next.js We maintain an https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository on how to use the Neo4j GraphQL Library with Next.js. -The example demonstrates how to use Neo4j with https://neo4j.com/docs/getting-started/appendix/example-data/[the "Movies" example], the Neo4j GraphQL Library and https://www.apollographql.com/docs/apollo-server/[Apollo Server]. +See the https://github.com/vercel/next.js/blob/canary/examples/with-apollo-neo4j-graphql/README.md[README] file for more instructions. From 7353aa70bd94ee10af9778a6d11ee0a9285f4849 Mon Sep 17 00:00:00 2001 From: Darrell Warde <8117355+darrellwarde@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:24:49 +0100 Subject: [PATCH 4/8] Update modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc Co-authored-by: Lidia Zuin <102308961+lidiazuin@users.noreply.github.com> --- modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc index 096ed655..d5e98a08 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc +++ b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc @@ -1,4 +1,4 @@ = How to use the Neo4j GraphQL Library with Next.js -We maintain an https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository on how to use the Neo4j GraphQL Library with Next.js. +This https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository demonstrates how to use Neo4j with https://neo4j.com/docs/getting-started/appendix/example-data/[the "Movies" example], the Neo4j GraphQL Library and https://www.apollographql.com/docs/apollo-server/[Apollo Server]. See the https://github.com/vercel/next.js/blob/canary/examples/with-apollo-neo4j-graphql/README.md[README] file for more instructions. From 7f6e90afb3ab457475393d469e5b739b93e42240 Mon Sep 17 00:00:00 2001 From: Darrell Warde <8117355+darrellwarde@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:27:25 +0100 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: Lidia Zuin <102308961+lidiazuin@users.noreply.github.com> --- .../integrations/apollo-federation.adoc | 35 +++++++++++-------- .../how-to-guides/integrations/nextjs.adoc | 4 ++- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc index 66a1a931..0eb74c81 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc +++ b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc @@ -1,7 +1,10 @@ [[apollo-federation]] -= How to create a subgraph compatible with Apollo Federation +:description: This guide shows how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. += Create a subgraph compatible with Apollo Federation -This guide shows you how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. In this guide, the following monolithic schema will be converted into a subgraph schema for use behind a Federation gateway: +This guide shows how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. + +The objective is to convert the following monolithic schema into a subgraph schema for use behind a Federation gateway: [source, javascript] ---- @@ -40,7 +43,7 @@ const { url } = await startStandaloneServer(server); console.log(`🚀 Server ready at ${url}`); ---- -== 1. Create a new project +== Create a new project and install the Apollo Server Follow the steps in xref::how-to-guides/create-project.adoc. @@ -57,7 +60,7 @@ Run the following command to install this final package: npm install @apollo/server ---- -== 3. Opt in to Federation +== Opt in to Federation For a set of type definitions to be usable as a subgraph for Federation, they must include the following schema extension: @@ -73,11 +76,13 @@ const typeDefs = `#graphql `; ---- -NOTE: This example only includes the Federation `@key` directive. As you want to use more https://www.apollographql.com/docs/federation/federated-types/federated-directives[Federation directives], you will need to add them to the `import` array. +Note that this example only includes the Federation `@key` directive. +To use more https://www.apollographql.com/docs/federation/federated-types/federated-directives[Federation directives], add them to the `import` array. -== 4. Define an entity +== Define an entity -In order for other subgraphs to be able to contribute fields to the `Movie` type, we must define that type as an https://www.apollographql.com/docs/federation/entities/[entity]. You do this by using the `@key` directive to designate a field (or fields) as a key: +Defining a type as an https://www.apollographql.com/docs/federation/entities/[entity] allows other subgraphs to contribute with fields to the `Movie` type. +To achieve that, use the `@key` directive to designate a field (or fields) as a key: [source, javascript] ---- @@ -91,20 +96,22 @@ const typeDefs = `#graphql `; ---- -NOTE: Whilst only the `@key` directive has been added in this example, you should consider using either the `@id` or `@unique` directive on the `id` field. The Federation gateway expects each key to resolve to one result, so it is good practice to ensure that these values are unique in the database. +Although only the `@key` directive has been added to this example, consider using either the `@id` or the `@unique` directives on the `id` field. +The Federation gateway expects each key to resolve to one result, so it is good practice to ensure that these values are unique in the database. -== 5. Generate a subgraph schema +== Generate a subgraph schema -When using the Neo4j GraphQL Library, generating the subgraph schema is as simple as calling `getSubgraphSchema` instead of `getSchema`, so only the following line needs to be changed: +When using the Neo4j GraphQL Library, generating the subgraph schema can be achieved by calling `getSubgraphSchema` instead of `getSchema`. +In other words, only the following line needs to be changed: [source, javascript] ---- const schema = neo4jgraphql.getSubgraphSchema(); ---- -== Complete example +== Conclusion -The above snippets are combined below: +By combining all previous snippets, you should get this: [source, javascript] ---- @@ -142,9 +149,9 @@ const { url } = await startStandaloneServer(server); console.log(`🚀 Server ready at ${url}`); ---- -== Next steps -The subgraph above can now be composed into a supergraph. The following guides from Apollo guide you through this: +For further iteration, this subgraph can also be composed into a supergraph. +Check Apollo's guides for more instructions: * https://www.apollographql.com/docs/federation/quickstart/studio-composition[Composition in Apollo Studio] * https://www.apollographql.com/docs/federation/quickstart/local-composition[Local composition] diff --git a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc index d5e98a08..556125fc 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc +++ b/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc @@ -1,4 +1,6 @@ -= How to use the Neo4j GraphQL Library with Next.js +[[next.js]] +:description: This page shows information on how to use the Neo4j GraphQL Library with Next.js += Use the Neo4j GraphQL Library with Next.js This https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository demonstrates how to use Neo4j with https://neo4j.com/docs/getting-started/appendix/example-data/[the "Movies" example], the Neo4j GraphQL Library and https://www.apollographql.com/docs/apollo-server/[Apollo Server]. See the https://github.com/vercel/next.js/blob/canary/examples/with-apollo-neo4j-graphql/README.md[README] file for more instructions. From 733f81802fd407ebca648895760900468119cc3b Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Wed, 30 Aug 2023 17:32:58 +0100 Subject: [PATCH 6/8] Remove project creation guide --- modules/ROOT/content-nav.adoc | 1 - .../pages/how-to-guides/create-project.adoc | 126 ------------------ .../integrations/apollo-federation.adoc | 119 ++++++++++++++++- 3 files changed, 113 insertions(+), 133 deletions(-) delete mode 100644 modules/ROOT/pages/how-to-guides/create-project.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index ed437a1e..494c30be 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -77,7 +77,6 @@ *** xref:reference/driver-configuration.adoc[] ** How-to guides -*** xref:how-to-guides/create-project.adoc[] *** Integrations **** xref:how-to-guides/integrations/apollo-federation.adoc[] **** xref:how-to-guides/integrations/nextjs.adoc[] diff --git a/modules/ROOT/pages/how-to-guides/create-project.adoc b/modules/ROOT/pages/how-to-guides/create-project.adoc deleted file mode 100644 index d74ace9d..00000000 --- a/modules/ROOT/pages/how-to-guides/create-project.adoc +++ /dev/null @@ -1,126 +0,0 @@ -= How to create a new project - -This guide shows you how to create a new project. - -This how-to guide assumes that you are familiar with the command line and JavaScript, and have https://nodejs.org/en[Node.js LTS] installed. The how-to guide contains options for both JavaScript and TypeScript. - -== 1. Create the project directory - -Create a directory for a new project and `cd` into it: - -[source, bash] ----- -mkdir neo4j-graphql-subgraph-example -cd neo4j-graphql-subgraph-example ----- - -== 2. Initialize the project - -Initialize a new Node.js project with `npm`: - -[source, bash] ----- -npm init --yes -npm pkg set type="module" ----- - -NOTE: This how-to guide sets up the project using ES Modules, which allows the usage of features such as top-level `await`. - -== 3. Language specific setup - -Follow the instructions below to set up with either TypeScript or JavaScript: - -.TypeScript -[%collapsible] -==== -. Create a `src` directory with an empty `index.ts` file to contain the entrypoint to your code for this project: -+ -[source, bash] ----- -mkdir src -touch src/index.ts ----- -+ -. Install the development dependencies required for working with a TypeScript project: -+ -[source, bash] ----- -npm install --save-dev typescript @types/node @tsconfig/node-lts ----- -+ -. Create an empty `tsconfig.json` file which will contain the compiler configuration for TypeScript: -+ -[source, bash] ----- -touch tsconfig.json ----- -+ -. Add the following configuration to the `tsconfig.json` file created above: -+ -[source, json] ----- -{ - "extends": "@tsconfig/node-lts/tsconfig.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - } -} ----- -+ -NOTE: The configuration above extends the https://github.com/tsconfig/bases#node-lts-tsconfigjson[community base for Node.js LTS], provided by the `@tsconfig/node-lts` package installed above. For more information on the available options, see the https://www.typescriptlang.org/tsconfig[TypeScript Compiler docs]. -+ -. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: -+ -[source, json] ----- -{ - // ...etc. - "scripts": { - "compile": "tsc", - "start": "npm run compile && node ./dist/index.js" - } - // other dependencies -} ----- -==== - -.JavaScript -[%collapsible] -==== -. Create a `src` directory with an empty `index.js` file to contain the entrypoint to your code for this project: -+ -[source, bash] ----- -mkdir src -touch src/index.js ----- -+ -. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: -+ -[source, json] ----- -{ - // ...etc. - "scripts": { - "start": "node index.js" - } - // other dependencies -} ----- -==== - -== 4. Install dependencies - -The following dependencies are always required when using the Neo4j GraphQL Library: - -* `@neo4j/graphql` is the Neo4j GraphQL Library, which translates GraphQL into Cypher and returns the results. -* `graphql` is the reference implementation of the GraphQL specification. It is required for `@neo4j/graphql` to function. -* `neo4j-driver` is the library for the Neo4j driver, which is required to execute Cypher queries against the database. - -Install these dependencies by running the following command: - -[source, bash] ----- -npm install @neo4j/graphql graphql neo4j-driver ----- diff --git a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc index 0eb74c81..23a89ca6 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc +++ b/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc @@ -45,19 +45,126 @@ console.log(`🚀 Server ready at ${url}`); == Create a new project and install the Apollo Server -Follow the steps in xref::how-to-guides/create-project.adoc. +=== Create the project directory -== 2. Install dependencies +Create a directory for a new project and `cd` into it: -The core dependencies for a Neo4j GraphQL Library have already been installed in your new project. +[source, bash] +---- +mkdir neo4j-graphql-subgraph-example +cd neo4j-graphql-subgraph-example +---- + +=== Initialize the project + +Initialize a new Node.js project with `npm`: + +[source, bash] +---- +npm init --yes +npm pkg set type="module" +---- + +NOTE: This how-to guide sets up the project using ES Modules, which allows the usage of features such as top-level `await`. + +=== Language specific setup + +Follow the instructions below to set up with either TypeScript or JavaScript: + +.TypeScript +[%collapsible] +==== +. Create a `src` directory with an empty `index.ts` file to contain the entrypoint to your code for this project: ++ +[source, bash] +---- +mkdir src +touch src/index.ts +---- ++ +. Install the development dependencies required for working with a TypeScript project: ++ +[source, bash] +---- +npm install --save-dev typescript @types/node @tsconfig/node-lts +---- ++ +. Create an empty `tsconfig.json` file which will contain the compiler configuration for TypeScript: ++ +[source, bash] +---- +touch tsconfig.json +---- ++ +. Add the following configuration to the `tsconfig.json` file created above: ++ +[source, json] +---- +{ + "extends": "@tsconfig/node-lts/tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + } +} +---- ++ +NOTE: The configuration above extends the https://github.com/tsconfig/bases#node-lts-tsconfigjson[community base for Node.js LTS], provided by the `@tsconfig/node-lts` package installed above. For more information on the available options, see the https://www.typescriptlang.org/tsconfig[TypeScript Compiler docs]. ++ +. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: ++ +[source, json] +---- +{ + // ...etc. + "scripts": { + "compile": "tsc", + "start": "npm run compile && node ./dist/index.js" + } + // other dependencies +} +---- +==== + +.JavaScript +[%collapsible] +==== +. Create a `src` directory with an empty `index.js` file to contain the entrypoint to your code for this project: ++ +[source, bash] +---- +mkdir src +touch src/index.js +---- ++ +. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: ++ +[source, json] +---- +{ + // ...etc. + "scripts": { + "start": "node index.js" + } + // other dependencies +} +---- +==== + +=== Install dependencies + +The following dependencies are required for this guide: -The final dependency to install is `@apollo/server`, the library for Apollo Server. It is used in this guide to host the subgraph. +* `@apollo/server`, the library for Apollo Server, is used in this guide to host the subgraph. +* `@neo4j/graphql` is the Neo4j GraphQL Library, which translates GraphQL into Cypher and returns the results. +* `graphql` is the reference implementation of the GraphQL specification. It is required for `@neo4j/graphql` to function. +* `neo4j-driver` is the library for the Neo4j driver, which is required to execute Cypher queries against the database. -Run the following command to install this final package: +Install these dependencies by running the following command: [source, bash] ---- -npm install @apollo/server +npm install @apollo/server @neo4j/graphql graphql neo4j-driver ---- == Opt in to Federation From 4c27de7a009069cc9fe0861e55df4d846df48fd9 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Wed, 30 Aug 2023 17:35:23 +0100 Subject: [PATCH 7/8] Restructure of integrations --- modules/ROOT/content-nav.adoc | 7 +++---- .../integrations/apollo-federation.adoc | 2 +- .../pages/{how-to-guides => }/integrations/nextjs.adoc | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) rename modules/ROOT/pages/{how-to-guides => }/integrations/apollo-federation.adoc (99%) rename modules/ROOT/pages/{how-to-guides => }/integrations/nextjs.adoc (92%) diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index 494c30be..17b316ad 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -76,10 +76,9 @@ *** xref:reference/driver-configuration.adoc[] -** How-to guides -*** Integrations -**** xref:how-to-guides/integrations/apollo-federation.adoc[] -**** xref:how-to-guides/integrations/nextjs.adoc[] +** Frameworks and integrations +*** xref:integrations/apollo-federation.adoc[] +*** xref:integrations/nextjs.adoc[] ** xref:troubleshooting.adoc[] diff --git a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc b/modules/ROOT/pages/integrations/apollo-federation.adoc similarity index 99% rename from modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc rename to modules/ROOT/pages/integrations/apollo-federation.adoc index 23a89ca6..b85b29f4 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/apollo-federation.adoc +++ b/modules/ROOT/pages/integrations/apollo-federation.adoc @@ -1,6 +1,6 @@ [[apollo-federation]] :description: This guide shows how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. -= Create a subgraph compatible with Apollo Federation += Apollo Federation This guide shows how to create a subgraph using the Neo4j GraphQL Library, for composition into a supergraph using Apollo Federation. diff --git a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc b/modules/ROOT/pages/integrations/nextjs.adoc similarity index 92% rename from modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc rename to modules/ROOT/pages/integrations/nextjs.adoc index 556125fc..1f5695c7 100644 --- a/modules/ROOT/pages/how-to-guides/integrations/nextjs.adoc +++ b/modules/ROOT/pages/integrations/nextjs.adoc @@ -1,6 +1,6 @@ [[next.js]] :description: This page shows information on how to use the Neo4j GraphQL Library with Next.js -= Use the Neo4j GraphQL Library with Next.js += Next.js This https://github.com/vercel/next.js/tree/canary/examples/with-apollo-neo4j-graphql[example project] in the Next.js repository demonstrates how to use Neo4j with https://neo4j.com/docs/getting-started/appendix/example-data/[the "Movies" example], the Neo4j GraphQL Library and https://www.apollographql.com/docs/apollo-server/[Apollo Server]. See the https://github.com/vercel/next.js/blob/canary/examples/with-apollo-neo4j-graphql/README.md[README] file for more instructions. From 596032811bfb6d9ef58962ba11ca3dc1dfd41004 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Wed, 30 Aug 2023 17:48:14 +0100 Subject: [PATCH 8/8] Bold instead of headings --- modules/ROOT/pages/integrations/apollo-federation.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/integrations/apollo-federation.adoc b/modules/ROOT/pages/integrations/apollo-federation.adoc index b85b29f4..a4a7682d 100644 --- a/modules/ROOT/pages/integrations/apollo-federation.adoc +++ b/modules/ROOT/pages/integrations/apollo-federation.adoc @@ -45,7 +45,7 @@ console.log(`🚀 Server ready at ${url}`); == Create a new project and install the Apollo Server -=== Create the project directory +*Create the project directory* Create a directory for a new project and `cd` into it: @@ -55,7 +55,7 @@ mkdir neo4j-graphql-subgraph-example cd neo4j-graphql-subgraph-example ---- -=== Initialize the project +*Initialize the project* Initialize a new Node.js project with `npm`: @@ -67,7 +67,7 @@ npm pkg set type="module" NOTE: This how-to guide sets up the project using ES Modules, which allows the usage of features such as top-level `await`. -=== Language specific setup +*Language specific setup* Follow the instructions below to set up with either TypeScript or JavaScript: @@ -151,7 +151,7 @@ touch src/index.js ---- ==== -=== Install dependencies +*Install dependencies* The following dependencies are required for this guide: