Vue API methods and validation errors¶
makeFetch — the generic HTTP helper¶
makeFetch (from ChillMainAssets/lib/api/apiMethods) is the standard way to call
the Chill JSON API from Vue components. It performs a single fetch, parses the JSON
response, and throws typed exceptions for common error scenarios.
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
const result = await makeFetch<InputType, OutputType, ViolationMapType>(
"POST",
"/api/1.0/person/service-provision",
payload,
);
The three generic type parameters are:
| Parameter | Purpose |
|---|---|
Input |
Shape of the request body |
Output |
Shape of the successful JSON response |
M |
Violation Map — describes which validation errors can appear (see below) |
M can be omitted when no 422 response is expected (e.g. GET requests).
Exceptions thrown by makeFetch¶
| Status | Exception class |
|---|---|
| 422 | ValidationException<M> |
| 403 | AccessException |
| 409 | ConflictHttpException |
| other | generic Error |
Typing 422 errors with a Violation Map¶
Symfony's validation problem+json payload returns violations keyed by propertyPath,
each carrying a parameters object with curly-brace placeholders like {{ value }}.
A Violation Map type M describes, per property path, which placeholder keys can
appear. This makes error handling fully type-safe.
// In types.ts alongside the payload type
export interface CreateServiceProvisionViolationMap extends Record<
string,
Record<string, string>
> {
notBeforeDateTime: {
"{{ value }}": string;
};
notAfterDateTime: {
"{{ value }}": string;
};
}
Rules for building a Violation Map:
- Each key is the exact propertyPath string returned by Symfony (matches DTO field names).
- Each value maps placeholder strings to their TypeScript type.
- Only list placeholders you actually use in the UI; you can always add more later.
- Use {} for a property that carries no parameters.
Handling validation errors in a Vue component¶
Step 1 — set up the composable¶
import { useViolationList } from "ChillMainAssets/vuejs/_composables/violationList";
import { isValidationException } from "ChillMainAssets/lib/api/apiMethods";
import { CreateServiceProvisionViolationMap } from "ChillPersonAssets/vuejs/ServiceProvision/types";
const violations = useViolationList<CreateServiceProvisionViolationMap>();
Step 2 — catch the exception and populate violations¶
Wrap the makeFetch call (or the api function that delegates to it) in a try/catch.
Use isValidationException to narrow the error before passing it to the composable.
import { useToast } from "vue-toast-notification";
const toast = useToast();
const create = async () => {
try {
const s = await createServiceProvision(/* … */);
toast.success("Created successfully");
emit("created", s);
} catch (e: unknown) {
if (isValidationException<CreateServiceProvisionViolationMap>(e)) {
violations.setValidationException(e); // populates the reactive violation state
} else {
console.error("Unexpected error", e);
toast.error("An unexpected error occurred");
}
}
};
Step 3 — display errors in the template¶
Use violations.violationTitles(propertyPath) to get an array of human-readable error
titles for a given field, then render them with v-for:
<div v-if="transition_selected !== null && transition_selected.context.requiresNotBefore">
<input type="datetime-local" v-model="dateNotBefore" />
<div
v-for="err in violations.violationTitles('notBeforeDateTime')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
</div>
<div v-if="transition_selected !== null && transition_selected.context.requiresNotAfter">
<input type="datetime-local" v-model="dateNotAfter" />
<div
v-for="err in violations.violationTitles('notAfterDateTime')"
class="invalid-feedback was-validated-force"
:key="err"
>
{{ err }}
</div>
</div>
The invalid-feedback was-validated-force CSS classes come from Bootstrap and the Chill
design system; they render the text in red below the field.
useViolationList API reference¶
| Method / property | Description |
|---|---|
setValidationException(e) |
Stores the caught ValidationException and makes violation data reactive. |
cleanException() |
Clears all stored violations (call before re-submitting a form). |
violationTitles(property) |
Returns string[] of human-readable titles for the given propertyPath. Returns [] when no violations are set. |
violationTitlesWithParameter(property, param, value) |
Like violationTitles but further filtered to violations where parameters[param] === value. |
hasViolation(property) |
Returns true if any violations exist for the property. |
hasViolationWithParameter(property, param, value) |
Like hasViolation with parameter filtering. |
Complete example¶
See src/Bundle/ChillPersonBundle/Resources/public/vuejs/ServiceProvision/Create/CreateServiceProvision.vue
for a complete working example that covers all three steps above.
The corresponding api function with its @throws JSDoc is in
src/Bundle/ChillPersonBundle/Resources/public/vuejs/ServiceProvision/api.ts
(createServiceProvision).