diff --git a/modules/ROOT/pages/authentication-and-authorization/authorization.adoc b/modules/ROOT/pages/authentication-and-authorization/authorization.adoc index 21b4757a..4fab80aa 100644 --- a/modules/ROOT/pages/authentication-and-authorization/authorization.adoc +++ b/modules/ROOT/pages/authentication-and-authorization/authorization.adoc @@ -1,25 +1,25 @@ +[[authorization]] +:description: This page describes how to set up authorization features in the Neo4j GraphQL Library. = Authorization -Authorization rules concern themselves with specific data which is executed against during a generated Cypher query. -They are evaluated via predicates in the Cypher generated from a GraphQL query, so they execute within the context of nodes and their properties. +Authorization rules cover what specific data a generated Cypher query is executed against. +They use predicates to evaluate the Cypher generated from a GraphQL query, thus allowing or disallowing execution within the context of nodes and their properties. -All authorization rules have an implied requirement for authentication, given that the rules are normally evaluated -against values in the JWT payload. +All authorization rules have an implied requirement for authentication, given that the rules are normally evaluated against values in the JWT payload. -In the case of explicit authentication, configured using the `@authentication` directive, is only ever evaluated -during Cypher translation time, and unauthenticated requests with queries requiring authentication -will never reach the database. +In the case of explicit authentication, configured using the `@authentication` directive, it is only ever evaluated during Cypher translation time. +Unauthenticated requests with queries requiring authentication never reach the database. == Rules -=== Filter +=== Filtering -Filter rules filter out data which users do not have access to, without throwing any errors. These rules -are evaluated in the database, with the rules translated into filter predicates and evaluated against matched data. -Filter rules are valuable because they protect your data as well as obfuscate the information on the _existence_ of -data to unauthorized users. +Filtering rules filter out data which users do not have access to, without throwing any errors. +These rules are evaluated in the database, then translated into filtering predicates that are evaluated against matched data. -For instance, to filter out `Post` nodes which don't belong to the current `User`: +Filtering rules protect data as well as obfuscate the information on the _existence_ of that data to unauthorized users. + +For instance, here is how to filter out `Post` nodes which don't belong to the current `User`: [source, graphql, indent=0] ---- @@ -36,13 +36,13 @@ type Post @authorization(filter: [ } ---- -=== Validate +=== Validating -Validate rules throw an error if a query executes against data which users do not have access to. These rules are -evaluated in the database via filtering predicates containing calls to +Validating rules throw an error if a query is executed against data which users do not have access to. +These rules are evaluated in the database via filtering predicates containing calls to https://neo4j.com/docs/apoc/current/overview/apoc.util/apoc.util.validatePredicate/[`apoc.util.validatePredicate`]. -For instance, to throw an error if a `User` is accessed by anyone but the user themselves or an admin: +For instance, here is how to throw an error if a `User` is accessed by anyone but the user themselves or an admin: [source, graphql, indent=0] ---- @@ -58,12 +58,12 @@ type User @authorization(validate: [ } ---- -== Authorization not requiring authentication +== Authorization without authentication Authentication is implicitly required for every authorization check by default, but this can be disabled on a per-rule basis. -This might be desired perhaps if a node has a property which flags whether the node should be public or not. +This could be the case, for instance, when a node has a property which flags whether the node should be public or not. -For instance, `Post` nodes might be private and belong to a particular `User`, or be public and readable by any user: +For instance, in the case where some `Post` nodes are private and belong to a particular `User`, while other `Post` nodes are public and readable by any user, here is how to set this up: [source, graphql, indent=0] ---- diff --git a/modules/ROOT/pages/authentication-and-authorization/impersonation-and-user-switching.adoc b/modules/ROOT/pages/authentication-and-authorization/impersonation-and-user-switching.adoc index 5ec4da36..dd4c3cb6 100644 --- a/modules/ROOT/pages/authentication-and-authorization/impersonation-and-user-switching.adoc +++ b/modules/ROOT/pages/authentication-and-authorization/impersonation-and-user-switching.adoc @@ -1,3 +1,5 @@ +[[impersonation-and-user-switching]] +:description: This page describes the impersonation and user switching features of the Neo4j GraphQL Library. = Impersonation and user switching Impersonation and user switching are features of the Neo4j database and driver which allow for query execution in a different context to the initial connection. @@ -5,13 +7,16 @@ Impersonation and user switching are features of the Neo4j database and driver w == Impersonation Impersonation still authenticates with the database as the original configured user, but runs the query in the context of an impersonated user. -When impersonating a user, the query is run within the complete security context of the impersonated user and not the authenticated user (home database, permissions, etc.). +When impersonating a user, the query is run within the complete security context of the impersonated user and not the authenticated user (home database, permissions etc). -An example of how to impersonate a different user per request can be found below. In this example, the user to impersonate is taken from a HTTP header `User`: +Consider the following an example of how to impersonate a different user per request. +Here the user to impersonate is taken from a HTTP header `User`: -.TypeScript -[%collapsible] +[.tabbed-example] ==== + +[.include-with-Typescript] +===== [source, typescript, indent=0] ---- import { ApolloServer } from "@apollo/server"; @@ -52,11 +57,10 @@ const { url } = await startStandaloneServer(server, { console.log(`🚀 Server ready at: ${url}`); ---- -==== +===== -.JavaScript -[%collapsible] -==== +[.include-with-JavaScript] +===== [source, javascript, indent=0] ---- import { ApolloServer } from "@apollo/server"; @@ -97,6 +101,7 @@ const { url } = await startStandaloneServer(server, { console.log(`🚀 Server ready at: ${url}`); ---- +===== ==== == User switching @@ -105,9 +110,11 @@ User switching completely switches the user authenticating with the database for An example of configuring user switching on a per request basis can be found in the example below. Note that the username and password are provided in HTTP headers `User` and `Password`, but this would not be recommended for production use: -.TypeScript -[%collapsible] +[.tabbed-example] ==== + +[.include-with-TypeScript] +===== [source, typescript, indent=0] ---- import { ApolloServer } from "@apollo/server"; @@ -148,11 +155,10 @@ const { url } = await startStandaloneServer(server, { console.log(`🚀 Server ready at: ${url}`); ---- -==== +===== -.JavaScript -[%collapsible] -==== +[.include-with-JavaScript] +===== [source, javascript, indent=0] ---- import { ApolloServer } from "@apollo/server"; @@ -193,6 +199,7 @@ const { url } = await startStandaloneServer(server, { console.log(`🚀 Server ready at: ${url}`); ---- +===== ==== diff --git a/modules/ROOT/pages/authentication-and-authorization/index.adoc b/modules/ROOT/pages/authentication-and-authorization/index.adoc index 771643e8..f51c7a3e 100644 --- a/modules/ROOT/pages/authentication-and-authorization/index.adoc +++ b/modules/ROOT/pages/authentication-and-authorization/index.adoc @@ -1,15 +1,15 @@ = Authentication and Authorization +:description: This section covers authentication andd authorization features in the Neo4j GraphQL Library. :page-aliases: auth/index.adoc, auth/setup.adoc, auth/authentication.adoc, \ auth/authorization.adoc, auth/auth-directive.adoc, auth/subscriptions.adoc, \ auth/authorization/allow.adoc, auth/authorization/bind.adoc, auth/authorization/roles.adoc, \ auth/authorization/where.adoc, guides/v4-migration/authorization.adoc - [WARNING] -==== +=== The `@auth` directive has been replaced by `@authentication` and `@authorization`. See the xref::migration/v4-migration/authorization.adoc[Migration guide] for details on how to upgrade. -==== +=== * xref::authentication-and-authorization/authentication.adoc[Authentication] - Explicit authentication, configured using the `@authentication` directive. * xref::authentication-and-authorization/authorization.adoc[Authorization] - Authorization rules set using the `@authorization` directive. diff --git a/modules/ROOT/pages/integrations/apollo-federation.adoc b/modules/ROOT/pages/integrations/apollo-federation.adoc index e354b625..0882c0fc 100644 --- a/modules/ROOT/pages/integrations/apollo-federation.adoc +++ b/modules/ROOT/pages/integrations/apollo-federation.adoc @@ -44,38 +44,39 @@ const { url } = await startStandaloneServer(server); console.log(`🚀 Server ready at ${url}`); ---- -== Create a new project and install the Apollo Server +== Setup -*Create the project directory* - -Create a directory for a new project and `cd` into it: +To proceed with the convertion, follow these steps: +. Create a directory for a new project and `cd` into it: ++ [source, bash] ---- mkdir neo4j-graphql-subgraph-example cd neo4j-graphql-subgraph-example ---- -*Initialize the project* - -Initialize a new Node.js project with `npm`: - +. 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`. +=== -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] +. Choose TypeScript or JavaScript to proceed with the setup: ++ +[.tabbed-example] ==== -. Create a `src` directory with an empty `index.ts` file to contain the entrypoint to your code for this project: + +[.include-with-Typescript] +===== +. Create a `src` directory with an empty `index.ts` file to contain the entrypoint to your code: + [source, bash] ---- @@ -90,14 +91,14 @@ touch src/index.ts npm install --save-dev typescript @types/node @tsconfig/node-lts ---- + -. Create an empty `tsconfig.json` file which will contain the compiler configuration for TypeScript: +. Create an empty `tsconfig.json` file containing the compiler configuration for TypeScript: + [source, bash] ---- touch tsconfig.json ---- + -. Add the following configuration to the `tsconfig.json` file created above: +. Add the following configuration to the `tsconfig.json` file: + [source, json] ---- @@ -110,9 +111,13 @@ touch tsconfig.json } ---- + -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]. +[NOTE] +=== +This configuration 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: +. Replace the default `scripts` entry in your `package.json` file with the following: + [source, json] ---- @@ -125,12 +130,11 @@ NOTE: The configuration above extends the https://github.com/tsconfig/bases#node // other dependencies } ---- -==== +===== -.JavaScript -[%collapsible] -==== -. Create a `src` directory with an empty `index.js` file to contain the entrypoint to your code for this project: +[.include-with-JavaScript] +===== +. Create a `src` directory with an empty `index.js` file to contain the entrypoint to your code: + [source, bash] ---- @@ -138,7 +142,7 @@ mkdir src touch src/index.js ---- + -. Replace the default `scripts` entry in your `package.json` file with the following `scripts` entry: +. Replace the default `scripts` entry in your `package.json` file with the following: + [source, json] ---- @@ -150,18 +154,19 @@ touch src/index.js // other dependencies } ---- +===== ==== - -*Install dependencies* - -The following dependencies are required for this guide: - ++ +. This guide requires the installation of the following dependencies: ++ * `@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. -Install these dependencies by running the following command: ++ + +Install them by running this command: [source, bash] ---- @@ -184,8 +189,11 @@ const typeDefs = `#graphql `; ---- -Note that this example only includes the Federation `@key` directive. +[NOTE] +=== +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. +=== == Define an entity @@ -210,7 +218,7 @@ The Federation gateway expects each key to resolve to one result, so it is good == Generate a subgraph schema 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: +For that, the following line needs to be changed: [source, javascript] ---- @@ -257,7 +265,6 @@ const { url } = await startStandaloneServer(server); console.log(`🚀 Server ready at ${url}`); ---- - For further iteration, this subgraph can also be composed into a supergraph. Check Apollo's guides for more instructions: diff --git a/modules/ROOT/pages/reference/directives/cypher.adoc b/modules/ROOT/pages/reference/directives/cypher.adoc deleted file mode 100644 index 390d1351..00000000 --- a/modules/ROOT/pages/reference/directives/cypher.adoc +++ /dev/null @@ -1,229 +0,0 @@ -[[type-definitions-cypher]] -= `@cypher` directive -:page-aliases: type-definitions/cypher.adoc - -The `@cypher` directive binds a GraphQL field to the result(s) of a Cypher query. - -This directive can be used both for properties in a type or as top level queries: - -== Definition - -[source, graphql, indent=0] ----- -"""Instructs @neo4j/graphql to run the specified Cypher statement in order to resolve the value of the field to which the directive is applied.""" -directive @cypher( - """The Cypher statement to run which returns a value of the same type composition as the field definition on which the directive is applied.""" - statement: String!, - """Name of the returned variable from the Cypher statement.""" - columnName: String! -) on FIELD_DEFINITION ----- - - -== Globals - -Global variables are available for use within the Cypher statement. - -=== `this` - -The value `this` is a reference to the currently resolved node, and it can be used to traverse the graph. - -This can be seen in the usage example xref::/type-definitions/directives/cypher.adoc#type-definitions-cypher-object-usage[On an object type field] below. - -=== `auth` - -The value `auth` is represented by the following TypeScript interface definition: - -[source, typescript, indent=0] ----- -interface Auth { - isAuthenticated: boolean; - roles?: string[]; - jwt: any; -} ----- - -For example, you could use the JWT in the request to return the value of the currently logged in User: - -[source, graphql, indent=0] ----- -type User { - id: String -} - -type Query { - me: User @cypher( - statement: """ - MATCH (user:User {id: $jwt.sub}) - RETURN user - """, - columnName: "user" - ) -} ----- - - -=== `cypherParams` -Use to inject values into the cypher query from the GraphQL context function. - -Inject into context: - -[source, typescript, indent=0] ----- -const server = new ApolloServer({ - typeDefs, -}); - -await startStandaloneServer(server, { - context: async ({ req }) => ({ cypherParams: { userId: "user-id-01" } }), -}); ----- - -Use in cypher query: - -[source, graphql, indent=0] ----- -type Query { - userPosts: [Post] @cypher(statement: """ - MATCH (:User {id: $userId})-[:POSTED]->(p:Post) - RETURN p - """, columnName: "p") -} ----- - -== Return values - -The return value of the Cypher statement must be of the same type to which the directive is applied. - -The variable should also be aliased with a name that must be the same as the named passed to `columnName`, this can be the name of a node or relationship query or an alias in the `RETURN` statement of the cypher. - -=== Scalar values - -The Cypher statement must return a value which matches the scalar type to which the directive was applied. - -[source, graphql, indent=0] ----- -type Query { - randomNumber: Int @cypher(statement: "RETURN rand() as result", columnName: "result") -} ----- - -=== Object types - -When returning an object type, all fields of the type must be available in the Cypher return value. This can be achieved by either returning the entire object from the Cypher query, or returning a map of the fields which are required for the object type. Both approaches are demonstrated below: - -[source, graphql, indent=0] ----- -type User { - id -} - -type Query { - users: [User] - @cypher( - statement: """ - MATCH (u:User) - RETURN u - """, - columnName: "u" - ) -} ----- - -[source, graphql, indent=0] ----- -type User { - id -} - -type Query { - users: [User] @cypher(statement: """ - MATCH (u:User) - RETURN { - id: u.id - } as result - """, columnName: "result") -} ----- - -The downside of the latter approach is that you will need to adjust the return object as you change your object type definition. - -== Usage examples - -[[type-definitions-cypher-object-usage]] -=== On an object type field - -In the example below, a field `similarMovies` is bound to the `Movie` type, to find other movies with an overlap of actors: - -[source, graphql, indent=0] ----- -type Actor { - actorId: ID! - name: String - movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT) -} - -type Movie { - movieId: ID! - title: String - description: String - year: Int - actors(limit: Int = 10): [Actor!]! - @relationship(type: "ACTED_IN", direction: IN) - similarMovies(limit: Int = 10): [Movie] - @cypher( - statement: """ - MATCH (this)<-[:ACTED_IN]-(:Actor)-[:ACTED_IN]->(rec:Movie) - WITH rec, COUNT(*) AS score ORDER BY score DESC - RETURN rec LIMIT $limit - """, - columnName: "rec" - ) -} ----- - -=== On a query type field - -The example below demonstrates a simple query to return all of the actors in the database: - -[source, graphql, indent=0] ----- -type Actor { - actorId: ID! - name: String -} - -type Query { - allActors: [Actor] - @cypher( - statement: """ - MATCH (a:Actor) - RETURN a - """, - columnName: "a" - ) -} ----- - -=== On a mutation type field - -The example below demonstrates a simple mutation using a Cypher query to insert a single actor with the specified name argument: - -[source, graphql, indent=0] ----- -type Actor { - actorId: ID! - name: String -} - -type Mutation { - createActor(name: String!): Actor - @cypher( - statement: """ - CREATE (a:Actor {name: $name}) - RETURN a - """, - columnName: "a" - ) -} ----- \ No newline at end of file diff --git a/modules/ROOT/pages/reference/directives/default-values.adoc b/modules/ROOT/pages/reference/directives/default-values.adoc deleted file mode 100644 index 97c72d29..00000000 --- a/modules/ROOT/pages/reference/directives/default-values.adoc +++ /dev/null @@ -1,96 +0,0 @@ -[[type-definitions-default-values]] -= Default Values - -[[type-definitions-default-values-default]] -== `@default` - -When generating the input type for the create mutation, the value specified in this directive will be used as the default value for this field. - -=== Definition - -[source, graphql, indent=0] ----- -"""Int | Float | String | Boolean | ID | DateTime | Enum""" -scalar Scalar - -"""Instructs @neo4j/graphql to set the specified value as the default value in the CreateInput type for the object type in which this directive is used.""" -directive @default( - """The default value to use. Must be a scalar type and must match the type of the field with which this directive decorates.""" - value: Scalar!, -) on FIELD_DEFINITION ----- - -=== Usage with Enums - -`@default` may be used with enums. When setting the default value for an enum field, -the value must be one of the enumerated enum values. - -[source, graphql, indent=0] ----- -enum Location { - HERE - THERE - EVERYWHERE -} - -type SomeType { - firstLocation: Location! @default(value: HERE) # valid usage - secondLocation: Location! @default(value: ELSEWHERE) # invalid usage, will throw an error -} ----- - -[[type-definitions-default-values-coalesce]] -== `@coalesce` - -When translating from GraphQL to Cypher, any instances of fields to which this directive is applied will be wrapped in a `coalesce()` function in the WHERE clause (see https://neo4j.com/developer/kb/understanding-non-existent-properties-and-null-values/#_use_coalesce_to_use_a_default_for_a_null_value). This helps to query against non-existent properties in a database, however it is encouraged to populate these properties with meaningful values if this is becoming the norm. This is a very primitive implementation of the function which only takes a static default value as opposed to using another property in a node or a Cypher expression. - -=== Definition - -[source, graphql, indent=0] ----- -"""Int | Float | String | Boolean | ID | DateTime | Enum""" -scalar ScalarOrEnum - -"""Instructs @neo4j/graphql to wrap the property in a coalesce() function during queries, using the single value specified.""" -directive @coalesce( - """The value to use in the coalesce() function. Must be a scalar type and must match the type of the field with which this directive decorates.""" - value: Scalar!, -) on FIELD_DEFINITION ----- - -=== Usage with Enums - -`@coalesce` may be used with enums. When setting the default value for an enum field, -the value must be one of the enumerated enum values. - -[source, graphql, indent=0] ----- -enum Status { - ACTIVE - INACTIVE -} -type Movie { - status: Status @coalesce(value: ACTIVE) -} ----- - -[[type-definitions-default-values-limit]] -== `@limit` - -The `@limit` is to be used on nodes, where applied will inject values into a query such as the `limit`. - -=== Definition - -[source, graphql, indent=0] ----- -"""The `@limit` is to be used on nodes, where applied will inject values into a query such as the `limit`.""" -directive @limit( - default: Int - max: Int -) on OBJECT ----- - -The directive has two arguments: - -* `default` - If no `limit` argument is passed to the query, the default limit will be used. The query may still pass a higher or lower `limit`. -* `max` - Defines the maximum limit to be passed to the query. If a higher value is passed, this will be used instead. If no `default` value is set, `max` will be used for queries without limit. \ No newline at end of file diff --git a/modules/ROOT/pages/reference/directives/index.adoc b/modules/ROOT/pages/reference/directives/index.adoc deleted file mode 100644 index 89535425..00000000 --- a/modules/ROOT/pages/reference/directives/index.adoc +++ /dev/null @@ -1,161 +0,0 @@ -[[directives]] -= Directives -:page-aliases: directives.adoc - -== `@alias` - -The `@alias` directive will map a GraphQL schema field to a Neo4j property on a node or relationship. - -Reference: xref::/type-definitions/directives/database-mapping.adoc#type-definitions-alias[`@alias`] - -== `@coalesce` - -The `@coalesce` directive exposes a mechanism for querying against non-existent, `null` values on a node. - -Reference: xref::/type-definitions/directives/default-values.adoc#type-definitions-default-values-coalesce[`@coalesce`] - -[[custom-resolver-directive]] -== `@customResolver` - -The `@customResolver` directive specifies that a field will be resolved by a custom resolver, and allows the specification -of any required fields that will be passed as arguments to the custom resolver. - -Reference: xref::custom-resolvers.adoc#custom-resolver-directive[`@customResolver`] - -== `@cypher` - -The `@cypher` directive overrides field resolution (including `Query` and `Mutation` fields), instead resolving with the specified Cypher. - -Reference: xref::/type-definitions/directives/cypher.adoc[`@cypher` directive] - -== `@default` - -The `@default` directive allows for the setting of a default value for a field on object creation. - -Reference: xref::/type-definitions/directives/default-values.adoc#type-definitions-default-values-default[`@default`] - -== `@exclude` label:deprecated[] - -This directive is deprecated. - -Use the xref:schema-configuration/type-configuration.adoc#_query[`@query`], xref:schema-configuration/type-configuration.adoc#_mutation[`@mutation`] and the xref:schema-configuration/type-configuration.adoc#_subscription[`@subscription`] directives instead. - -The `@exclude` directive is used on object types to instruct them to be skipped during Query, Mutation and Subscription generation. - -Reference: xref::schema-configuration/type-configuration.adoc#_exclude_deprecated[`@exclude`] - -== `@filterable` - -The `@filterable` directive defines the filters generated for a field. - -Reference: xref:schema-configuration/field-configuration.adoc#_filterable[`@filterable`] - -== `@fulltext` - -The `@fulltext` directive indicates that there should be a Fulltext index inserted into the database for the specified Node and its properties. - -Reference: xref::/type-definitions/directives/indexes-and-constraints.adoc#type-definitions-indexes-fulltext[Fulltext indexes] - -== `@id` - -The `@id` directive marks a field as the unique ID for an object type, and allows for autogeneration of IDs. - -Reference: xref::/type-definitions/directives/autogeneration.adoc#type-definitions-autogeneration-id[`@id`] - -== `@limit` - -The `@limit` is to be used on nodes, and when applied will inject values into Cypher `LIMIT` clauses. - -Reference: xref::/type-definitions/directives/default-values.adoc#type-definitions-default-values-limit[`@limit`] - -== `@mutation` - -This directive is used to limit the availability of Mutation operations in the library. - -Reference: xref:schema-configuration/type-configuration.adoc#_mutation[`@mutation`] - -== `@node` - -The `@node` directive is used to specify the configuration of a GraphQL object type which represents a Neo4j node. - -Reference: xref::/type-definitions/directives/database-mapping.adoc#type-definitions-node[`@node`] - -[[plural-directive]] -== `@plural` - -The `@plural` directive redefines how to compose the plural of the type for the generated operations. -This is particularly useful for types that are not correctly pluralized or are non-English words. - -Reference: xref::/type-definitions/directives/database-mapping.adoc#type-definitions-plural[`@plural`] - -[[populated-by-directive]] -== `@populatedBy` - -The `@populatedBy` directive is used to specify a callback function that gets executed during GraphQL query parsing, -to populate fields which have not been provided within the input. - -Reference: xref::/type-definitions/directives/autogeneration.adoc#type-definitions-autogeneration-populated-by[`@populatedBy`] - -== `@private` - -The `@private` directive protects fields which should only be available through the xref::ogm/index.adoc[OGM]. - -Reference: xref::ogm/private.adoc[`@private` Directive] - -== `@query` - -This directive is used to limit the availability of Query operations in the library. - -Reference: xref:schema-configuration/type-configuration.adoc#_query[`@query`] - -== `@relationship` - -The `@relationship` directive is used to configure relationships between object types. - -Reference: xref::/type-definitions/types/relationships.adoc[Relationships], xref::schema-configuration/field-configuration.adoc#_relationship[`@relationship`] - -== `@relationshipProperties` - -Required to help you distinguish between interfaces which are used for relationship properties, and otherwise. - -Can only be used on interfaces, as per its definition: - -[source, graphql, indent=0] ----- -"""Required to differentiate between interfaces for relationship properties, and otherwise.""" -directive @relationshipProperties on INTERFACE ----- - -== `@relayId` - -The `@relayId` directive can be used on object type fields, to flag which field should be used as the global node identifier for Relay. Can be used once per type. The use of the `@relayId` directive ensures a unique node property constraint for the field. - -== `@selectable` - -The `@selectable` directive sets the availability of fields on queries and aggregations. - -Reference: xref:schema-configuration/field-configuration.adoc#_selectable[`@selectable`] - -== `@settable` - -The `@settable` directive sets the availability of fields on the create and update inputs. - -Reference: xref:schema-configuration/field-configuration.adoc#_settable[`@settable`] - -== `@subscription` - -This directive is used to limit Subscription events available in the library. - -Reference: xref:schema-configuration/type-configuration.adoc#_subscription[`@subscription`] - -== `@timestamp` - -The `@timestamp` directive flags fields to be used to store timestamps on create/update events. - -Reference: xref::/type-definitions/directives/autogeneration.adoc#type-definitions-autogeneration-timestamp[`@timestamp`] - -== `@unique` - -The `@unique` directive indicates that there should be a uniqueness constraint in the database for the fields that it is applied to. - -Reference: xref::/type-definitions/directives/indexes-and-constraints.adoc#type-definitions-constraints-unique[Unique node property constraints] diff --git a/modules/ROOT/pages/reference/directives/schema-configuration/type-configuration.adoc b/modules/ROOT/pages/reference/directives/schema-configuration/type-configuration.adoc deleted file mode 100644 index 0d0a5e46..00000000 --- a/modules/ROOT/pages/reference/directives/schema-configuration/type-configuration.adoc +++ /dev/null @@ -1,156 +0,0 @@ -[[schema-configuration-type-configuration]] -= Type Configuration - - -When representing a Neo4j Node, a GraphQL Object type produces multiple operation fields in the `Query`, `Mutation`, and `Subscription` types. -For example: - -[source, graphql, indent=0] ----- -type Movie { - title: String - length: Int -} ----- - -From these type definitions, the library generates the following operation fields: - -**Query**: - - * `movies` - * `moviesAggregate` - * `moviesConnection` - -**Mutation**: - - * `createMovies` - * `deleteMovies` - * `updateMovies` - -**Subscription**: - - * `movieCreated` - * `movieUpdated` - * `movieDeleted` -. - -This section explains how to reduce the operation fields produced using the directives `@query`, `@mutation`, and `@subscription`. - -== `@query` - -This directive is used to limit the availability of query operations in the library. - -=== Definition - -[source, graphql, indent=0] ----- -directive @query(read: Boolean! = true, aggregate: Boolean! = false) on OBJECT | SCHEMA ----- - -[NOTE] -==== -Aggregations will no longer be generated by default in the 4.0.0 version of the library. -See xref:migration/v4-migration/index.adoc#opt-in-aggregation[`Opt-in Aggregation`] for more information. -==== - -=== Usage - -==== Disable _movies_ and _moviesConnection_ operations - -[source, graphql, indent=0] ----- -type Movie @query(read: false, aggregate: true) { - title: String - length: Int -} ----- - -==== Disable _moviesAggregate_ operations - -[source, graphql, indent=0] ----- -type Movie @query(read: true, aggregate: false) { - title: String - length: Int -} ----- - -== `@mutation` - -This directive is used to limit the availability of Mutation operations in the library. - -=== Definition - -[source, graphql, indent=0] ----- -enum MutationFields { - CREATE - UPDATE - DELETE -} - -directive @mutation(operations: [MutationFields!]! = [CREATE, UPDATE, DELETE]) on OBJECT | SCHEMA ----- - -=== Usage - -==== Disable Create, Delete, and Update operations for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @mutation(operations: []) { - title: String - length: Int -} ----- - -==== Enable only Create operations for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @mutation(operations: [CREATE]) { - title: String - length: Int -} ----- - -== `@subscription` - -This directive is used to limit Subscription operations in the library. - -=== Definition - -[source, graphql, indent=0] ----- -enum SubscriptionEvent { - CREATED - UPDATED - DELETED - RELATIONSHIP_CREATED - RELATIONSHIP_DELETED -} - -directive @subscription(events: [SubscriptionEvent!]! = [CREATED, UPDATED, DELETED, RELATIONSHIP_CREATED, RELATIONSHIP_DELETED]) on OBJECT | SCHEMA ----- - -=== Usage - -==== Disable subscriptions for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @subscription(events: []) { - title: String - length: Int -} ----- - -==== Enable only _movieCreated_ subscription for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @subscription(events: [CREATED]) { - title: String - length: Int -} ----- diff --git a/modules/ROOT/pages/reference/type-definitions/interfaces.adoc b/modules/ROOT/pages/reference/type-definitions/interfaces.adoc deleted file mode 100644 index adc72a27..00000000 --- a/modules/ROOT/pages/reference/type-definitions/interfaces.adoc +++ /dev/null @@ -1,135 +0,0 @@ -[[schema-configuration-type-configuration]] -= Type Configuration - - -When representing a Neo4j Node, a GraphQL Object type produces multiple operation fields in the `Query`, `Mutation`, and `Subscription` types. -For example: - -[source, graphql, indent=0] ----- -type Movie { - title: String - length: Int -} ----- - -From these type definitions, the library generates the following operation fields: - -**Query**: - - * `movies` - * `moviesAggregate` - * `moviesConnection` - -**Mutation**: - - * `createMovies` - * `deleteMovies` - * `updateMovies` - -**Subscription**: - - * `movieCreated` - * `movieUpdated` - * `movieDeleted` -. - -This section explains how to reduce the operation fields produced using the directives `@query`, `@mutation`, and `@subscription`. - -== `@query` - -This directive is used to limit the availability of query operations in the library. - -=== Definition - -[source, graphql, indent=0] ----- -directive @query(read: Boolean! = true, aggregate: Boolean! = false) on OBJECT | SCHEMA ----- - -[NOTE] -==== -Aggregations will no longer be generated by default in the 4.0.0 version of the library. -See xref:migration/v4-migration/index.adoc#opt-in-aggregation[`Opt-in Aggregation`] for more information. -==== - -[[type-definitions-interfaced-types-querying]] -== Querying an interface - -Which implementations are returned by a query are dictated by the `where` filter applied. - -For example, the following will return all productions with title starting "The " for every actor: - -[source, graphql, indent=0] ----- -enum MutationFields { - CREATE - UPDATE - DELETE -} - -directive @mutation(operations: [MutationFields!]! = [CREATE, UPDATE, DELETE]) on OBJECT | SCHEMA ----- - -=== Usage - -==== Disable Create, Delete, and Update operations for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @mutation(operations: []) { - title: String - length: Int -} ----- - -==== Enable only Create operations for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @mutation(operations: [CREATE]) { - title: String - length: Int -} ----- - -== `@subscription` - -This directive is used to limit Subscription operations in the library. - -=== Definition - -[source, graphql, indent=0] ----- -enum SubscriptionFields { - CREATE - UPDATE - DELETE - CREATE_RELATIONSHIP - DELETE_RELATIONSHIP -} - -directive @subscription(operations: [SubscriptionFields!]! = [CREATE, UPDATE, DELETE, CREATE_RELATIONSHIP, DELETE_RELATIONSHIP]) on OBJECT | SCHEMA ----- - -=== Usage - -==== Disable subscriptions for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @subscription(operations: []) { - title: String - length: Int -} ----- - -==== Enable only _movieCreated_ subscription for _Movie_ - -[source, graphql, indent=0] ----- -type Movie @subscription(operations: [CREATE]) { - title: String - length: Int -} ----- \ No newline at end of file diff --git a/modules/ROOT/pages/subscriptions/events.adoc b/modules/ROOT/pages/subscriptions/events.adoc index ec6a94ea..155d0b38 100644 --- a/modules/ROOT/pages/subscriptions/events.adoc +++ b/modules/ROOT/pages/subscriptions/events.adoc @@ -1,19 +1,42 @@ [[subscription-events]] = Subscription events +:description: This page covers a variety of subscription options offered by the Neo4j GraphQL Library. :page-aliases: subscriptions/events/create.adoc, \ subscriptions/events/create_relationship.adoc, subscriptions/events/delete.adoc, subscriptions/events/delete_relationship.adoc, \ subscriptions/events/update.adoc -:description: This page covers a variety of subscription options offered by the Neo4j GraphQL Library. - This page covers a variety of subscription options offered by the Neo4j GraphQL Library. [NOTE] -==== +=== Only changes made through `@neo4j/graphql` should trigger the events here described. -Changes made directly to the database or using the xref::reference/directives/cypher.adoc[`@cypher` directive] will **not** trigger any event. -==== +Changes made directly to the database or using the xref::type-definitions/directives/cypher.adoc[`@cypher` directive] will **not** trigger any event. +=== + +== `CREATE` + +Subscriptions to `CREATE` events listen *only* to newly created nodes, not new relationships. +In this case, a new event is triggered for each new node, containing its properties. + +This action is performed with the top-level subscription `[type]Created`, which contains the following fields: + +* `event`: the event triggering this subscription (in this case, `CREATE`). +* `created`: top-level properties of the newly created node, without relationships. +* `timestamp`: the timestamp in which the mutation was made. +If a same query triggers multiple events, they should have the same timestamp. + +As an example, consider the following type definitions: + +[source,graphql,indent=0] +---- +type Movie { + title: String + genre: String +} +---- +Note, however, that only changes made through `@neo4j/graphql` should trigger events. +Changes made directly to the database or using the xref::type-definitions/directives/cypher.adoc[`@cypher` directive] will **not** trigger any event. == `CREATE` diff --git a/publish.yml b/publish.yml index e9d0695b..a15467e4 100644 --- a/publish.yml +++ b/publish.yml @@ -7,7 +7,7 @@ site: content: sources: - url: https://github.com/neo4j/docs-graphql.git - branches: ['dev', '3.x'] + branches: ['4.x', '3.x'] exclude: - '!**/_includes/*' - '!**/readme.adoc'