`;
```
## Backend validation
Backend validation is needed in some cases. For example, you have a sign up form, the username could be already taken. You can add an `AsyncValidator` to check the availability when the `username` field is changed but you may have a conflict when you submit the form (another user take the username in parallel).
```js preview-story
export const backendValidation = () => {
// Mock
function fakeFetch(ms = 0, withError = false) {
return new Promise(resolve => {
setTimeout(() => {
resolve(
new Response(
JSON.stringify({
message: withError ? 'Username is already taken' : '',
}),
{ status: withError ? 400 : 200 },
),
);
}, ms);
});
}
let backendValidationResolver;
let backendErrorMessage = 'Unknown Error';
let isBackendCallPending = false;
const submitHandler = ev => {
const lionForm = ev.target;
if (lionForm.hasFeedbackFor.includes('error')) {
const firstFormElWithError = lionForm.formElements.find(el =>
el.hasFeedbackFor.includes('error'),
);
firstFormElWithError.focus();
return;
}
isBackendCallPending = true;
lionForm.formElements.username.validate(); // => backendValidationResolver will be assigned
const formData = lionForm.serializedValue;
fakeFetch(2000, formData.simulateError.length).then(async response => {
if (response.status !== 200) {
backendErrorMessage = (await response.json())?.message;
backendValidationResolver(true);
}
backendValidationResolver(false);
isBackendCallPending = false;
});
};
class BackendValidator extends Validator {
static get validatorName() {
return 'backendValidator';
}
static get async() {
return true;
}
async execute() {
if (isBackendCallPending) {
return await new Promise(resolve => (backendValidationResolver = resolve));
}
return false;
}
static getMessage({ fieldName, modelValue, params: param }) {
return backendErrorMessage;
}
}
return html`