You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/advanced/custom-scalars.md
+20-18Lines changed: 20 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -17,6 +17,7 @@ Lets say we wanted to build a scalar called `Money` that can handle both an amou
17
17
publicclassInventoryController : GraphController
18
18
{
19
19
[QueryRoot("search")]
20
+
// highlight-next-line
20
21
publicIEnumerable<Product> Search(MoneyminPrice)
21
22
{
22
23
return_service.RetrieveProducts(
@@ -41,6 +42,7 @@ public class Money
41
42
42
43
```graphql title="Using the Money Scalar"
43
44
query {
45
+
# highlight-next-line
44
46
search(minPrice: "$18.45"){
45
47
id
46
48
name
@@ -99,42 +101,44 @@ public interface ILeafValueResolver
99
101
- This method is used when generated default values for field arguments and input object fields via introspection queries.
100
102
- This method must return a value exactly as it would appear in a schema type definition For example, strings must be surrounded by quotes.
101
103
102
-
-`ValidateObject(object)`: A method used when validating data returned from a a field resolver. GraphQL will call this method and provide an object instance to determine if its acceptable and can be used in a query.
104
+
-`ValidateObject(object)`: A method used when validating data returned from a a field resolver. GraphQL will call this method and provide an object instance to determine if its acceptable and can be used in a query result.
103
105
104
106
:::note
105
-
`ValidateObject(object)` should not attempt to enforce nullability rules. In general, all scalars should return `true` for a validation result if the provided object is `null`.
107
+
`ValidateObject(object)` should not attempt to enforce nullability rules. In general, all scalars "could be null" depending on their usage in a schema. All scalars should return `true` for a validation result if the provided object is `null`.
106
108
:::
107
109
108
-
### ILeafValueResolver Members
110
+
### ILeafValueResolver
109
111
110
-
-`Resolve(ReadOnlySpan<char>)`: A resolver function capable of converting an array of characters into the internal representation of the scalar.
112
+
ILeafValueResolver contains a single method:
113
+
114
+
-`Resolve(ReadOnlySpan<char>)`: A resolver function used for converting an array of characters into the internal representation of the scalar.
111
115
112
116
#### Dealing with Escaped Strings
113
117
114
118
The span provided to `ILeafValueResolver.Resolve` will be the raw data read from the query document. If the data represents a string, it will be provided in its delimited format. This means being surrounded by quotes as well as containing escaped characters (including escaped unicode characters):
115
119
116
-
Example string data:
120
+
Example data:
117
121
118
122
-`"quoted string"`
119
123
-`"""triple quoted string"""`
120
124
-`"With \"\u03A3scaped ch\u03B1racters\""`;
121
125
122
-
The static type`GraphQLStrings` provides a handy static method for unescaping the data if you don't need to do anything special with it, `GraphQLStrings.UnescapeAndTrimDelimiters`.
126
+
The static method`GraphQLStrings.UnescapeAndTrimDelimiters` provides a handy way for unescaping the data if you don't need to do anything special with it.
123
127
124
-
Calling `UnescapeAndTrimDelimiters` with the previous examples produces:
128
+
Calling `GraphQLStrings.UnescapeAndTrimDelimiters` with the previous examples produces:
125
129
126
130
-`quoted string`
127
131
-`triple quoted string`
128
132
-`With "Σscaped chαracters"`
129
133
130
134
#### Indicating an Error
131
135
132
-
When resolving input values with `Resolve()`, if the provided value is not usable and must be rejected then the entire query document must be rejected. For instance, if a document contained the value `"$15.R0"` for our money scalar it would need to be rejected because `15.R0` cannot be converted to a decimal decimal.
136
+
When resolving incoming values with `Resolve()`, if the provided value is not usable and must be rejected then the entire query document must be rejected. For instance, if a document contained the value `"$15.R0"` for our money scalar it would need to be rejected because `15.R0` cannot be converted to a decimal.
133
137
134
-
Throw an exception when this happens and GraphQL will automatically generate an appropriate response with the correct origin information indicating the line and column in the query document where the error occurred. However, like with any other encounterd exception, GraphQL will obfuscate it to a generic message and only expose your exception details if allowed by the [schema configuration](../reference/schema-configuration).
138
+
Throw an exception when this happens and GraphQL will automatically generate an appropriate response with the correct origin information indicating the line and column in the query document where the error occurred. However, like with any other encounterd exception, the library will obfuscate it to a generic message and only expose your exception details if allowed by the [schema configuration](../reference/schema-configuration).
135
139
136
140
:::tip Pro Tip!
137
-
If you throw `UnresolvedValueException` your error message will be delivered verbatim to the requestor as part of the response message instead of being obfuscated.
141
+
If you throw the special `UnresolvedValueException` your error message will be delivered verbatim to the requestor as part of the response message instead of being obfuscated.
138
142
:::
139
143
140
144
### Example: Money Scalar
@@ -219,7 +223,7 @@ services.AddGraphQL();
219
223
```
220
224
221
225
:::info
222
-
Since our scalar is represented by a .NET class, if we don't pre-register it GraphQL will attempt to parse the `Money` class as an object graph type. Once registered as a scalar, any attempt to use `Money` as an object graph type will cause an exception.
226
+
Since our scalar is represented by a .NET class, if we don't pre-register it GraphQL will attempt to parse the `Money` class as an input object graph type. Once registered as a scalar, any attempt to use `Money` as an object graph type will cause an exception.
223
227
:::
224
228
225
229
## @specifiedBy Directive
@@ -274,7 +278,7 @@ A few points about designing your scalar:
274
278
- Scalar types should be simple and work in isolation.
275
279
- The `ReadOnlySpan<char>` provided to `ILeafValueResolver.Resolve` should be all the data needed to generate a value, there should be no need to perform side effects or fetch additional data.
276
280
- Scalar types should not track any state, depend on any stateful objects, or attempt to use any sort of dependency injection.
277
-
-`ILeafValueResolver.Resolve` must be **FAST**! Since your resolver is used to construct an initial query plan from a text document, it'll be called many orders of magnitude more often than any other method.
281
+
-`ILeafValueResolver.Resolve` must be **FAST**! Since your resolver is used to construct an initial query plan from the raw query text, it'll be called many orders of magnitude more often than any other method.
278
282
279
283
### Aim for Fewer Scalars
280
284
@@ -295,24 +299,22 @@ public class InventoryController : GraphController
295
299
296
300
publicclassMoney
297
301
{
298
-
publicstringSymbol { get; }
299
-
publicdecimalPrice { get; }
302
+
publicstringSymbol { get; set; }
303
+
publicdecimalPrice { get; set; }
300
304
}
301
305
```
302
306
303
307
```graphql title="Using the Money Input Object"
304
308
query {
305
-
search(minPrice: {
306
-
symbol: "$"
307
-
price: 18.45}){
309
+
search(minPrice: {symbol: "$"price: 18.45}){
308
310
id
309
311
name
310
312
}
311
313
}
312
314
```
313
315
314
316
315
-
This is a lot more flexible. We can add more properties to `Money` when needed and not break existing queries. Whereas with a scalar if we change the acceptable format of the string data any existing query text will now be invalid. It is almost always better to represent your data as an object or input object rather than a scalar.
317
+
This is a lot more flexible. We can add more properties to `Money` when needed and not break existing queries. Whereas with a scalar if we change the acceptable format of the string data any existing applications using our graph may need to be updated. It is almost always better to represent your data as an input object rather than a custom scalar.
316
318
317
319
:::caution Be Careful
318
320
Creating a custom scalar should be a last resort, not a first option.
Copy file name to clipboardExpand all lines: docs/advanced/directives.md
+73-69Lines changed: 73 additions & 69 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -79,26 +79,26 @@ The following properties are available to all directive action methods:
79
79
Directives may contain input arguments just like fields. However, its important to note that while a directive may declare multiple action methods for different locations to seperate your logic better, it is only a single entity in the schema. ALL action methods must share a common signature. The runtime will throw an exception while creating your schema if the signatures of the action methods differ.
The `@deprecated` directive is a built in type system directive provided by graphql to indicate deprecation on a field definition or enum value. Below is the code for its implementation.
GraphQLASP.NETbuildsyourschema and all of its types from your controllers and objects. In general, this is done behind the scenes and you do not need to interact with it. However, when applying type system directives you are affecting the generated schema and need to understand the various parts of it. If you have a question don't be afraid to ask on [github](https://github.com/graphql-aspnet/graphql-aspnet).
0 commit comments