The frontend half of the TYPO3 extension TCA API. The TCA API serves the records of a TYPO3 site as JSON and writes an OpenAPI spec of them; this package turns that spec into types and makes typed requests with them. The two belong together: without the TCA API there is no spec.
- Client: typed
GET,POST,PATCH,DELETEon top of openapi-fetch; every failed request throws anApiError - Helpers for the TCA API's formats: Hydra lists and range filters
- CLI for the types: generate them from the spec, compare them in CI, check the code against them
Requirements: a TYPO3 project with the TCA API, Node.js 18+.
npm install @xima-media/tca-api-client openapi-fetch
npm install --save-dev openapi-typescript
npm install --save-dev svelte-check # optional, for `check` in Svelte projects| Folder | Holds | Runs in |
|---|---|---|
src/ |
the client | the browser |
src/helpers/ |
Hydra lists, range filters | the browser |
cli/ |
the tca-api-client command |
Node |
1. Spec and types. The TCA API writes the spec, the package the types. Commit the types; their diff shows every API change.
vendor/bin/typo3 tca-api:openapi <site> --output var/api/openapi.json
npx tca-api-client generate var/api/openapi.json src/api/schema.d.ts2. Client. Create it once, typed by the generated types:
import { createApiClient } from '@xima-media/tca-api-client'
/** @type {import('openapi-fetch').Client<import('./schema').paths>} */
export const api = createApiClient({ baseUrl: '' })baseUrl can be a function, read on every request, e.g. for a language prefix. headers are sent with every request.
3. Requests. Paths, parameters and fields autocomplete from the types.
import { ApiError, dayRange, hydraPage, today } from '@xima-media/tca-api-client'
const { data } = await api.GET('/_api/events', { params: { query: { start_date: dayRange(today()), page: 1 } } })
const { items, total, nextPage } = hydraPage(data)
try {
await api.PATCH('/_api/offers/{uid}', { params: { path: { uid: 12 } }, body: { title: '' } })
} catch (error) {
if (error instanceof ApiError && error.status === 422) errors = error.fieldErrors() // { title: ['…'] }
}| Export | Does |
|---|---|
createApiClient({ baseUrl, headers }) |
an openapi-fetch client that throws ApiError on every response that is not ok; a FormData body is sent as multipart/form-data |
ApiError |
status, url, message and title from the API's error body; on a 422 violations and fieldErrors() per field |
hydraItems(data), hydraPage(data) |
rows, or { items, total, nextPage }, of a list, with or without the hydra: prefix |
dayRange(from?, to?), today() |
two YYYY-MM-DD days as { gte, lte } in Unix seconds, the format of the range filter |
Array parameters are named as the spec writes them ('type[]'), because PHP reads repeated keys as a list only with [].
4. CI. Both commands exit with 1 on a finding.
| Command | Fails when |
|---|---|
tca-api-client compare <openapi.json> <schema.d.ts> |
the committed types differ from the spec; prints the diff |
tca-api-client check <source dir> [--ext svelte,js] [--exclude dir] [--tsconfig file] |
the code does not fit the types; runs svelte-check, default --ext svelte |
The types are only as good as the spec. Where the spec and a real response disagree, the fix belongs in the TCA API.
Please have a look at CONTRIBUTING.md.
This project is licensed under GNU General Public License 2.0 (or later).