Proper way to sanitize and validate options when using the settings API?

What is the proper way to sanitize and validate options when using the settings API?

I am generating each fields html with a callback function based on passed parameters. I am trying to get some re-usable validation functions but the whole thing seems strange to me. I feel it is either a terrible system or I have completely misunderstood it.

The only place I can see that I can validate it is with the sanitize_callback on register_setting. I tried this:

register_setting( 'maws_settings_general', 'maws_school_name', 'maws_setting_validation_text_required');

function maws_setting_validation_text_required($data)
{
if (null == $data)
{
add_settings_error(
'requiredTextFieldEmpty',
'empty',
'Cannot be empty',
'error'
);
}

return sanitize_text_field($data);
}

The error is useless. It appears at the top and it does not stop the empty value from being saved. It seems crazy but on the codex it says this callback is where its validated but value is always saved. Also it is impossible to re-use code here as you have to specify the field name as it appears at the top of the page. This means I will have a function for every option just to sanitize and validate it.

Am I just supposed to use the pre-save hook to validate it? How do I then output the validation error?

There is obviously something I am missing but the codex has hardly any information on settings api.

What validation technique should be used with settings API?