Skip to content

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).