Skip to main content
Version: v0.1.10

Check a folder of messages in CI

In this tutorial you build a small script that validates every file in a folder of sample messages, watch it catch an invalid FHIR resource and a file that is not a message, and run it as a CI step. By the end you have a gate that fails a build when a message in the repository stops being valid.

You need the cosyte command (see Installation) and bash. Work in an empty directory.

1. Make a folder of messages​

Write two synthetic messages: an HL7 v2 admit and a FHIR Patient.

mkdir -p messages
printf 'MSH|^~\\&|SENDINGAPP|SENDINGFAC|RECEIVINGAPP|RECEIVINGFAC|20240101120000||ADT^A01|MSG00001|P|2.5\rEVN|A01|20240101120000\rPID|1||MRN-000123^^^HOSP^MR||ZZSENTINELLAST^ZZSENTINELFIRST^M||19800101|M\rPV1|1|I|WARD^101^A\r' > messages/admit.hl7
echo '{"resourceType":"Patient","id":"example","gender":"female"}' > messages/patient.json

2. Validate one file and read its exit code​

cosyte validate prints its findings on stderr and puts the verdict in the exit code. With --quiet it prints nothing when the file is valid, and the exit code is the whole answer:

cosyte validate messages/patient.json --quiet; echo "exit $?"
exit 0

3. Write the script​

The script validates each file in the folder it is given, prints one line per file, and exits 1 if any file is not valid:

cat > check-messages.sh <<'EOF'
#!/usr/bin/env bash
# Validate every file in the folder named as the first argument.
# Exit 0 when every file is valid, 1 when any is not.
failed=0
for file in "$1"/*; do
cosyte validate "$file" --quiet
code=$?
case $code in
0) echo "valid $file" ;;
1) echo "invalid $file"; failed=1 ;;
*) echo "error $file (exit $code)"; failed=1 ;;
esac
done
exit $failed
EOF
chmod +x check-messages.sh

It tells two failures apart. Exit 1 means cosyte read the file and the message is invalid. Any other non-zero code means it could not check the file at all; the exit-code table says which code means what.

Run it:

./check-messages.sh messages; echo "exit $?"
valid messages/admit.hl7
valid messages/patient.json
exit 0

4. Watch it catch an invalid resource​

Add a FHIR Observation whose status is not one of the codes FHIR allows, and run the script again:

echo '{"resourceType":"Observation","id":"example","status":"done","code":{"text":"Synthetic test"}}' > messages/result.json
./check-messages.sh messages; echo "exit $?"
valid messages/admit.hl7
valid messages/patient.json
invalid messages/result.json
exit 1

To see why, validate that file without --quiet:

cosyte validate messages/result.json; echo "exit $?"
cosyte: validate: error CODE_INVALID at Observation.status
cosyte: validate: fhir is INVALID (1 error(s), 0 other finding(s))
exit 1

The finding gives the code and the path, never the value, so it is safe to leave in a CI log.

5. Watch it catch a file that is not a message​

Fix the Observation, then add a file that is not a message at all:

echo '{"resourceType":"Observation","id":"example","status":"final","code":{"text":"Synthetic test"}}' > messages/result.json
echo 'not a message' > messages/notes.txt
./check-messages.sh messages; echo "exit $?"
valid messages/admit.hl7
cosyte: CLI_FORMAT_UNDETECTED: could not detect the input format; re-run with --format (detectable: hl7, mllp, fhir, x12, astm, ccda, ncpdp, dicom)
error messages/notes.txt (exit 65)
valid messages/patient.json
valid messages/result.json
exit 1

--quiet hides the summary of a successful check, never a diagnostic: the CLI_FORMAT_UNDETECTED line still reaches stderr. cosyte does not guess a format, so the file fails with the data-error exit, 65, and the script reports it. Remove it and the folder passes again:

rm messages/notes.txt
./check-messages.sh messages; echo "exit $?"
valid messages/admit.hl7
valid messages/patient.json
valid messages/result.json
exit 0

6. Run it in CI​

Commit the folder and the script, and add a step that installs the command and runs the script. In GitHub Actions:

- uses: actions/setup-node@v4
with:
node-version: "22"
- run: npm install -g @cosyte/cli
- run: ./check-messages.sh messages

The step fails when the script exits non-zero, so the build fails on the first invalid message.

What you built​

A gate that validates every message in a folder, tells an invalid message from a file it could not check, and keeps values out of the log. The same pattern works with cosyte parse or cosyte inspect in place of validate.

Next​