Skip to content

Commit 6951133

Browse files
Aditi-1400targos
authored andcommitted
doc: improve documentation on argument validation
PR-URL: #56954 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
1 parent 44dd8a5 commit 6951133

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

src/README.md

+62
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,68 @@ void InitializeHttpParser(Local<Object> target,
589589
}
590590
```
591591
592+
### Argument validation in public APIs vs. internal code
593+
594+
#### Public API argument sanitization
595+
596+
When arguments come directly from user code, Node.js will typically validate them at the
597+
JavaScript layer and throws user-friendly
598+
[errors](https://github.com/nodejs/node/blob/main/doc/contributing/using-internal-errors.md)
599+
(e.g., `ERR_INVALID_*`), if they are invalid. This helps end users
600+
quickly understand and fix mistakes in their own code.
601+
602+
This approach ensures that the error message pinpoints which argument is wrong
603+
and how it should be fixed. Additionally, problems in user code do not cause
604+
mysterious crashes or hard-to-diagnose failures deeper in the engine.
605+
606+
Example from `zlib.js`:
607+
608+
```js
609+
function crc32(data, value = 0) {
610+
if (typeof data !== 'string' && !isArrayBufferView(data)) {
611+
throw new ERR_INVALID_ARG_TYPE('data', ['Buffer', 'TypedArray', 'DataView','string'], data);
612+
}
613+
validateUint32(value, 'value');
614+
return crc32Native(data, value);
615+
}
616+
```
617+
618+
The corresponding C++ assertion code for the above example from it's binding `node_zlib.cc`:
619+
620+
```cpp
621+
CHECK(args[0]->IsArrayBufferView() || args[0]->IsString());
622+
CHECK(args[1]->IsUint32());
623+
```
624+
625+
#### Internal code and C++ binding checks
626+
627+
Inside Node.js’s internal layers, especially the C++ [binding function][]s
628+
typically assume their arguments have already been checked and sanitized
629+
by the upper-level (JavaScript) callers. As a result, internal C++ code
630+
often just uses `CHECK()` or similar assertions to confirm that the
631+
types/values passed in are correct. If that assertion fails, Node.js will
632+
crash or abort with an internal diagnostic message. This is to avoid
633+
re-validating every internal function argument repeatedly which can slow
634+
down the system.
635+
636+
However, in a less common case where the API is implemented completely in
637+
C++, the arguments would be validated directly in C++, with the errors
638+
thrown using `THROW_ERR_INVALID_*` macros from `src/node_errors.h`.
639+
640+
For example in `worker_threads.moveMessagePortToContext`:
641+
642+
```cpp
643+
void MessagePort::MoveToContext(const FunctionCallbackInfo<Value>& args) {
644+
Environment* env = Environment::GetCurrent(args);
645+
if (!args[0]->IsObject() ||
646+
!env->message_port_constructor_template()->HasInstance(args[0])) {
647+
return THROW_ERR_INVALID_ARG_TYPE(env,
648+
"The \"port\" argument must be a MessagePort instance");
649+
}
650+
// ...
651+
}
652+
```
653+
592654
<a id="exception-handling"></a>
593655

594656
### Exception handling

0 commit comments

Comments
 (0)