@@ -25,9 +25,9 @@ module HttpHandlers =
25
25
26
26
let rec private moduleType = getModuleType <@ moduleType @>
27
27
28
- let ofTaskIResult ctx ( taskRes : Task < IResult >) : HttpFuncResult = task {
28
+ let ofTaskIResult ctx ( taskRes : Task < IResult >) : HttpFuncResult = task {
29
29
let! res = taskRes
30
- do ! res.ExecuteAsync( ctx)
30
+ do ! res.ExecuteAsync ( ctx)
31
31
return Some ctx
32
32
}
33
33
@@ -41,28 +41,28 @@ module HttpHandlers =
41
41
42
42
let logger = sp.CreateLogger moduleType
43
43
44
- let options = sp.GetRequiredService< IOptionsMonitor< GraphQLOptions< 'Root>>>()
44
+ let options = sp.GetRequiredService< IOptionsMonitor< GraphQLOptions< 'Root>>> ()
45
45
46
46
let toResponse { DocumentId = documentId ; Content = content ; Metadata = metadata } =
47
47
48
48
let serializeIndented value =
49
49
let jsonSerializerOptions = options.Get( IndentedOptionsName) .SerializerOptions
50
- JsonSerializer.Serialize( value, jsonSerializerOptions)
50
+ JsonSerializer.Serialize ( value, jsonSerializerOptions)
51
51
52
52
match content with
53
- | Direct( data, errs) ->
54
- logger.LogDebug(
53
+ | Direct ( data, errs) ->
54
+ logger.LogDebug (
55
55
$" Produced direct GraphQL response with documentId = '{{documentId}}' and metadata:\n {{metadata}}" ,
56
56
documentId,
57
57
metadata
58
58
)
59
59
60
60
if logger.IsEnabled LogLevel.Trace then
61
- logger.LogTrace( $" GraphQL response data:\n :{{data}}" , serializeIndented data)
61
+ logger.LogTrace ( $" GraphQL response data:\n :{{data}}" , serializeIndented data)
62
62
63
- GQLResponse.Direct( documentId, data, errs)
64
- | Deferred( data, errs, deferred) ->
65
- logger.LogDebug(
63
+ GQLResponse.Direct ( documentId, data, errs)
64
+ | Deferred ( data, errs, deferred) ->
65
+ logger.LogDebug (
66
66
$" Produced deferred GraphQL response with documentId = '{{documentId}}' and metadata:\n {{metadata}}" ,
67
67
documentId,
68
68
metadata
@@ -71,41 +71,32 @@ module HttpHandlers =
71
71
if logger.IsEnabled LogLevel.Debug then
72
72
deferred
73
73
|> Observable.add ( function
74
- | DeferredResult( data, path) ->
75
- logger.LogDebug(
76
- " Produced GraphQL deferred result for path: {path}" ,
77
- path |> Seq.map string |> Seq.toArray |> Path.Join
78
- )
74
+ | DeferredResult ( data, path) ->
75
+ logger.LogDebug ( " Produced GraphQL deferred result for path: {path}" , path |> Seq.map string |> Seq.toArray |> Path.Join)
79
76
80
77
if logger.IsEnabled LogLevel.Trace then
81
- logger.LogTrace(
82
- $" GraphQL deferred data:\n {{data}}" ,
83
- serializeIndented data
84
- )
85
- | DeferredErrors( null , errors, path) ->
86
- logger.LogDebug(
87
- " Produced GraphQL deferred errors for path: {path}" ,
88
- path |> Seq.map string |> Seq.toArray |> Path.Join
89
- )
78
+ logger.LogTrace ( $" GraphQL deferred data:\n {{data}}" , serializeIndented data)
79
+ | DeferredErrors ( null , errors, path) ->
80
+ logger.LogDebug ( " Produced GraphQL deferred errors for path: {path}" , path |> Seq.map string |> Seq.toArray |> Path.Join)
90
81
91
82
if logger.IsEnabled LogLevel.Trace then
92
- logger.LogTrace( $" GraphQL deferred errors:\n {{errors}}" , errors)
93
- | DeferredErrors( data, errors, path) ->
94
- logger.LogDebug(
83
+ logger.LogTrace ( $" GraphQL deferred errors:\n {{errors}}" , errors)
84
+ | DeferredErrors ( data, errors, path) ->
85
+ logger.LogDebug (
95
86
" Produced GraphQL deferred result with errors for path: {path}" ,
96
87
path |> Seq.map string |> Seq.toArray |> Path.Join
97
88
)
98
89
99
90
if logger.IsEnabled LogLevel.Trace then
100
- logger.LogTrace(
91
+ logger.LogTrace (
101
92
$" GraphQL deferred errors:\n {{errors}}\n GraphQL deferred data:\n {{data}}" ,
102
93
errors,
103
94
serializeIndented data
104
95
))
105
96
106
- GQLResponse.Direct( documentId, data, errs)
97
+ GQLResponse.Direct ( documentId, data, errs)
107
98
| Stream stream ->
108
- logger.LogDebug(
99
+ logger.LogDebug (
109
100
$" Produced stream GraphQL response with documentId = '{{documentId}}' and metadata:\n {{metadata}}" ,
110
101
documentId,
111
102
metadata
@@ -115,48 +106,60 @@ module HttpHandlers =
115
106
stream
116
107
|> Observable.add ( function
117
108
| SubscriptionResult data ->
118
- logger.LogDebug( " Produced GraphQL subscription result" )
109
+ logger.LogDebug ( " Produced GraphQL subscription result" )
119
110
120
111
if logger.IsEnabled LogLevel.Trace then
121
- logger.LogTrace(
122
- $" GraphQL subscription data:\n {{data}}" ,
123
- serializeIndented data
124
- )
125
- | SubscriptionErrors( null , errors) ->
126
- logger.LogDebug( " Produced GraphQL subscription errors" )
112
+ logger.LogTrace ( $" GraphQL subscription data:\n {{data}}" , serializeIndented data)
113
+ | SubscriptionErrors ( null , errors) ->
114
+ logger.LogDebug ( " Produced GraphQL subscription errors" )
127
115
128
116
if logger.IsEnabled LogLevel.Trace then
129
- logger.LogTrace( $" GraphQL subscription errors:\n {{errors}}" , errors)
130
- | SubscriptionErrors( data, errors) ->
131
- logger.LogDebug( " Produced GraphQL subscription result with errors" )
117
+ logger.LogTrace ( $" GraphQL subscription errors:\n {{errors}}" , errors)
118
+ | SubscriptionErrors ( data, errors) ->
119
+ logger.LogDebug ( " Produced GraphQL subscription result with errors" )
132
120
133
121
if logger.IsEnabled LogLevel.Trace then
134
- logger.LogTrace(
122
+ logger.LogTrace (
135
123
$" GraphQL subscription errors:\n {{errors}}\n GraphQL deferred data:\n {{data}}" ,
136
124
errors,
137
125
serializeIndented data
138
126
))
139
127
140
128
GQLResponse.Stream documentId
141
129
| RequestError errs ->
142
- logger.LogWarning(
143
- $" Produced request error GraphQL response with documentId = '{{documentId}}' and metadata:\n {{metadata}}" ,
144
- documentId,
145
- metadata
146
- )
130
+ let noExceptionsFound =
131
+ errs
132
+ |> Seq.map
133
+ ( fun x ->
134
+ x.Exception |> ValueOption.iter ( fun ex ->
135
+ logger.LogError ( ex, " Error while processing request that generated response with documentId '{documentId}'" , documentId)
136
+ )
137
+ x.Exception.IsNone
138
+ )
139
+ |> Seq.forall id
140
+ if noExceptionsFound then
141
+ logger.LogWarning (
142
+ ( " Produced request error GraphQL response with:\n "
143
+ + " - documentId: '{documentId}'\n "
144
+ + " - error(s):\n {requestError}\n "
145
+ + " - metadata:\n {metadata}\n " ),
146
+ documentId,
147
+ errs,
148
+ metadata
149
+ )
147
150
148
- GQLResponse.RequestError( documentId, errs)
151
+ GQLResponse.RequestError ( documentId, errs)
149
152
150
153
/// Checks if the request contains a body
151
- let checkIfHasBody ( request : HttpRequest ) = task {
154
+ let checkIfHasBody ( request : HttpRequest ) = task {
152
155
if request.Body.CanSeek then
153
156
return ( request.Body.Length > 0 L)
154
157
else
155
- request.EnableBuffering()
158
+ request.EnableBuffering ()
156
159
let body = request.Body
157
160
let buffer = Array.zeroCreate 1
158
- let! bytesRead = body.ReadAsync( buffer, 0 , 1 )
159
- body.Seek( 0 , SeekOrigin.Begin) |> ignore
161
+ let! bytesRead = body.ReadAsync ( buffer, 0 , 1 )
162
+ body.Seek ( 0 , SeekOrigin.Begin) |> ignore
160
163
return bytesRead > 0
161
164
}
162
165
@@ -165,23 +168,21 @@ module HttpHandlers =
165
168
/// and lastly by parsing document AST for introspection operation definition.
166
169
/// </summary>
167
170
/// <returns>Result of check of <see cref="OperationType"/></returns>
168
- let checkOperationType ( ctx : HttpContext ) = taskResult {
171
+ let checkOperationType ( ctx : HttpContext ) = taskResult {
169
172
170
- let checkAnonymousFieldsOnly ( ctx : HttpContext ) = taskResult {
171
- let! gqlRequest = ctx.TryBindJsonAsync< GQLRequestContent>( GQLRequestContent.expectedJSON)
173
+ let checkAnonymousFieldsOnly ( ctx : HttpContext ) = taskResult {
174
+ let! gqlRequest = ctx.TryBindJsonAsync< GQLRequestContent> ( GQLRequestContent.expectedJSON)
172
175
let! ast = Parser.parseOrIResult ctx.Request.Path.Value gqlRequest.Query
173
176
let operationName = gqlRequest.OperationName |> Skippable.toOption
174
177
175
- let createParsedContent () = {
178
+ let createParsedContent () = {
176
179
Query = gqlRequest.Query
177
180
Ast = ast
178
181
OperationName = gqlRequest.OperationName
179
182
Variables = gqlRequest.Variables
180
183
}
181
184
if ast.IsEmpty then
182
- logger.LogTrace(
183
- " Request is not GET, but 'query' field is an empty string. Must be an introspection query"
184
- )
185
+ logger.LogTrace ( " Request is not GET, but 'query' field is an empty string. Must be an introspection query" )
185
186
return IntrospectionQuery <| ValueNone
186
187
else
187
188
match Ast.findOperationByName operationName ast with
@@ -196,34 +197,33 @@ module HttpHandlers =
196
197
let hasNonMetaFields =
197
198
Ast.containsFieldsBeyond
198
199
Ast.metaTypeFields
199
- ( fun x ->
200
- logger.LogTrace( $" Operation Selection in Field with name: {{fieldName}}" , x.Name))
200
+ ( fun x -> logger.LogTrace ( $" Operation Selection in Field with name: {{fieldName}}" , x.Name))
201
201
( fun _ -> logger.LogTrace " Operation Selection is non-Field type" )
202
202
op
203
203
204
204
if hasNonMetaFields then
205
- return createParsedContent() |> OperationQuery
205
+ return createParsedContent () |> OperationQuery
206
206
else
207
207
return IntrospectionQuery <| ValueSome ast
208
208
}
209
209
210
210
let request = ctx.Request
211
211
212
212
if HttpMethods.Get = request.Method then
213
- logger.LogTrace( " Request is GET. Must be an introspection query" )
213
+ logger.LogTrace ( " Request is GET. Must be an introspection query" )
214
214
return IntrospectionQuery <| ValueNone
215
215
else
216
216
let! hasBody = checkIfHasBody request
217
217
218
218
if not hasBody then
219
- logger.LogTrace( " Request is not GET, but has no body. Must be an introspection query" )
219
+ logger.LogTrace ( " Request is not GET, but has no body. Must be an introspection query" )
220
220
return IntrospectionQuery <| ValueNone
221
221
else
222
222
return ! checkAnonymousFieldsOnly ctx
223
223
}
224
224
225
225
/// Execute default or custom introspection query
226
- let executeIntrospectionQuery ( executor : Executor < _ >) ( ast : Ast.Document voption ) = task {
226
+ let executeIntrospectionQuery ( executor : Executor < _ >) ( ast : Ast.Document voption ) = task {
227
227
let! result =
228
228
match ast with
229
229
| ValueNone -> executor.AsyncExecute IntrospectionQuery.Definition
@@ -239,18 +239,18 @@ module HttpHandlers =
239
239
let variables = content.Variables |> Skippable.filter ( not << isNull) |> Skippable.toOption
240
240
241
241
operationName
242
- |> Option.iter ( fun on -> logger.LogTrace( " GraphQL operation name: '{operationName}'" , on))
242
+ |> Option.iter ( fun on -> logger.LogTrace ( " GraphQL operation name: '{operationName}'" , on))
243
243
244
- logger.LogTrace( $" Executing GraphQL query:\n {{query}}" , content.Query)
244
+ logger.LogTrace ( $" Executing GraphQL query:\n {{query}}" , content.Query)
245
245
246
246
variables
247
- |> Option.iter ( fun v -> logger.LogTrace( $" GraphQL variables:\n {{variables}}" , v))
247
+ |> Option.iter ( fun v -> logger.LogTrace ( $" GraphQL variables:\n {{variables}}" , v))
248
248
249
249
let root = options.CurrentValue.RootFactory ctx
250
250
251
251
let! result =
252
- Async.StartAsTask(
253
- executor.AsyncExecute( content.Ast, root, ?variables = variables, ?operationName = operationName),
252
+ Async.StartAsTask (
253
+ executor.AsyncExecute ( content.Ast, root, ?variables = variables, ?operationName = operationName),
254
254
cancellationToken = ctx.RequestAborted
255
255
)
256
256
0 commit comments