Working examples of talking to Axiell's EMu REST API, in PHP and in TypeScript. Each example is a small, self-contained function with the API's quirks documented inline; the tests alongside them double as usage examples.
| Operation | PHP | Node |
|---|---|---|
| Authorization (JWT) | src/Tokens/Auth.php |
src/tokens/auth.ts |
| Retrieve a single record | src/Texpress/Retrieve.php |
src/texpress/retrieve.ts |
| Search a module | src/Texpress/Search.php |
src/texpress/search.ts |
Not implemented yet, in either language:
- Insert (no key), Insert/Replace
- Edit
- Delete
These cost us time, so they are called out here as well as in the code.
-
The auth token comes back in a response header, not the response body. Read
Authorizationoff the response to thePOST /{tenant}/tokensrequest. -
A search is a POST, not a GET. The Texpress documentation is unclear on this. Send a
POSTwithX-HTTP-Method-Override: GETand a form-encoded body; a plainGETwill not do what you want. See the Override appendix. -
Tokens renew themselves. When a token is created with
renewenabled (the default in these examples), every subsequent response carries a freshAuthorizationheader with an updated expiry. Pass it to the next request instead of authenticating again — the retrieve and search examples return it alongside the data for exactly this reason.
Both examples read their settings from a .env file in their own directory.
cp php/.env.example php/.env # then fill it in
cp node/.env.example node/.env # then fill it inEMUAPI_PORT can be left empty if your API is served on the default port.
Credentials are only needed for the integration tests; see below.
Requires PHP 8.2 or newer and Composer.
cd php
composer install
composer test| Command | What it does |
|---|---|
composer test |
Runs the mocked tests. No credentials needed. |
composer test:integration |
Runs the tests that hit a real EMu. |
composer test:all |
Both. |
composer lint |
Checks formatting with Pint. |
composer lint:fix |
Fixes formatting. |
Requires Node 18 or newer, for native fetch and AbortSignal.timeout.
cd node
npm install
npm test| Command | What it does |
|---|---|
npm test |
Runs the mocked tests. No credentials needed. |
npm run test:one -- <path> [-t <name>] |
Runs one file, or one test, with each test name printed. |
npm run test:integration |
Runs the tests that hit a real EMu. |
npm run test:one:integration -- <path> [-t <name>] |
Same as test:one, for the integration tests. |
npm run example |
Runs src/index.ts end to end against your tenant. |
npm run typecheck |
Typechecks without emitting. |
npm run lint |
Lints with ESLint. |
npm run format / npm run format:fix |
Checks / applies Prettier formatting. |
The tests are the usage examples, so they are written to be read:
-
*.test.tsandtests/Unitmock the HTTP layer. They run on a fresh clone with no credentials and no EMu installation, and they assert on the exact request each example sends — method, URL, headers and body — which is usually the part you want to copy. These are what CI runs. -
*.integration.test.tsandtests/Integrationsend real requests. They skip themselves unless.envholds working credentials, so they are safe to leave in place.EMUAPI_TEST_IRNpoints the retrieve test at a record that exists in your tenant.
In node, test:one takes a file and an optional test name, and prints each
test name as it runs:
npm run test:one -- src/tokens/auth.test.ts # one file
npm run test:one -- src/tokens/auth.test.ts -t "omits the port" # one testThe path is a regex matched against the file path rather than a literal path, so
npm run test:one -- tokens runs everything under that directory. -t matches
on a substring of the test name; the other tests in the file are reported as
skipped. Note that test:one uses the default config, so it will not find an
integration test; those have their own script:
npm run test:one:integration -- src/tokens/auth.integration.test.tsIn php, Pest takes a path, and --filter narrows to one test:
./vendor/bin/pest tests/Unit/AuthTest.php
./vendor/bin/pest tests/Unit/AuthTest.php --filter="rejects missing credentials"MIT. See LICENSE.