@@ -146,7 +146,15 @@ pub const IncomingMessage = struct {
146146 return error .SkippedParams ;
147147 }
148148
149- try self .scanUntil ("params" );
149+ self .scanUntil ("params" ) catch | err | {
150+ // handle nullable type
151+ if (@typeInfo (T ) == .Optional ) {
152+ if (err == error .InvalidToken or err == error .EndOfDocument ) {
153+ return null ;
154+ }
155+ }
156+ return err ;
157+ };
150158
151159 // parse "params"
152160 const options = std.json.ParseOptions {
@@ -251,3 +259,34 @@ test "read incoming message with null session id" {
251259 try std .testing .expectEqual (1 , try msg .getId ());
252260 }
253261}
262+
263+ test "message with nullable params" {
264+ const T = struct {
265+ bar : []const u8 ,
266+ };
267+
268+ // nullable type, params is present => value
269+ const not_null =
270+ \\{"id": 1,"method":"foo","params":{"bar":"baz"}}
271+ ;
272+ var msg = IncomingMessage .init (std .testing .allocator , not_null );
273+ defer msg .deinit ();
274+ const input = try Input (? T ).get (std .testing .allocator , & msg );
275+ defer input .deinit ();
276+ try std .testing .expectEqualStrings (input .params .? .bar , "baz" );
277+
278+ // nullable type, params is not present => null
279+ const is_null =
280+ \\{"id": 1,"method":"foo","sessionId":"AAA"}
281+ ;
282+ var msg_null = IncomingMessage .init (std .testing .allocator , is_null );
283+ defer msg_null .deinit ();
284+ const input_null = try Input (? T ).get (std .testing .allocator , & msg_null );
285+ defer input_null .deinit ();
286+ try std .testing .expectEqual (null , input_null .params );
287+ try std .testing .expectEqualStrings ("AAA" , input_null .sessionId .? );
288+
289+ // not nullable type, params is not present => error
290+ const params_or_error = msg_null .getParams (std .testing .allocator , T );
291+ try std .testing .expectError (error .EndOfDocument , params_or_error );
292+ }
0 commit comments