@@ -26,14 +26,18 @@ import { wildcardMediaTypeMatch } from './utils/wildcardMediaTypeMatch';
2626
2727export { validateSecurity } from './validators/security' ;
2828
29- const checkRequiredBodyIsProvided = ( requestBody : O . Option < IHttpOperationRequestBody > , body : unknown ) =>
29+ const checkRequiredBodyIsProvided = (
30+ requestBody : O . Option < IHttpOperationRequestBody > ,
31+ body : unknown ,
32+ bodyIsProvided : boolean
33+ ) =>
3034 pipe (
3135 requestBody ,
3236 E . fromPredicate < O . Option < IHttpOperationRequestBody > , NonEmptyArray < IPrismDiagnostic > > (
33- requestBody => O . isNone ( requestBody ) || ! ( ! ! requestBody . value . required && body == null ) ,
37+ requestBody => O . isNone ( requestBody ) || ! ( ! ! requestBody . value . required && ! bodyIsProvided ) ,
3438 ( ) => [ { code : 'required' , message : 'Body parameter is required' , severity : DiagnosticSeverity . Error } ]
3539 ) ,
36- E . map ( requestBody => [ requestBody , body == null ? O . none : O . some ( body ) ] as const )
40+ E . map ( requestBody => [ requestBody , bodyIsProvided ? O . some ( body ) : O . none ] as const )
3741 ) ;
3842
3943const isMediaTypeSupportedInContents = ( mediaType ?: string , contents ?: IMediaTypeContent [ ] ) : boolean =>
@@ -73,17 +77,23 @@ const validateInputBody = (
7377 bundle : unknown ,
7478 body : unknown ,
7579 headers : IHttpNameValue
76- ) =>
77- pipe (
78- checkRequiredBodyIsProvided ( requestBody , body ) ,
79- E . map ( b => [ ...b , caseless ( headers || { } ) ] as const ) ,
80+ ) => {
81+ const headersCaseless = caseless ( headers || { } ) ;
82+ const contentLength = parseInt ( headersCaseless . get ( 'content-length' ) ) || 0 ;
83+ // A body is considered "provided" if:
84+ // - body is not undefined, AND
85+ // - body is not null OR content-length > 0 (null with content-length > 0 means JSON null value)
86+ const bodyIsProvided = body !== undefined && ( body !== null || contentLength > 0 ) ;
87+
88+ return pipe (
89+ checkRequiredBodyIsProvided ( requestBody , body , bodyIsProvided ) ,
90+ E . map ( b => [ ...b , headersCaseless ] as const ) ,
8091 E . chain ( ( [ requestBody , body , headers ] ) => {
8192 const contentTypeHeader = headers . get ( 'content-type' ) ;
8293 const [ multipartBoundary , mediaType ] = contentTypeHeader
8394 ? parseMIMEHeader ( contentTypeHeader )
8495 : [ undefined , undefined ] ;
8596
86- const contentLength = parseInt ( headers . get ( 'content-length' ) ) || 0 ;
8797 if ( contentLength === 0 ) {
8898 // generously allow this content type if there isn't a body actually provided
8999 return E . right ( [ requestBody , body , mediaType , multipartBoundary ] as const ) ;
@@ -114,6 +124,7 @@ const validateInputBody = (
114124 validateInputIfBodySpecIsProvided ( body , requestBody , mediaType , multipartBoundary , bundle )
115125 )
116126 ) ;
127+ } ;
117128
118129export const validateInput : ValidatorFn < IHttpOperation , IHttpRequest > = ( { resource, element } ) => {
119130 const { request } = resource ;
0 commit comments