A simple REST API server for returning JSON things.
3.1K
A simple REST API server for returning JSON things.
docker pull ghcr.io/mitchallen/thing-server:latest
docker pull mitchallen/thing-server:latest
This will pull the image down from the repo if you didn't already.
This example runs the server locally on port 1234.
docker run -p 1234:3000 --name thing-server ghcr.io/mitchallen/thing-server:latest
You can also run the Docker Hub image instead:
docker run -p 1234:3000 --name thing-server mitchallen/thing-server:latest
From the doc:
The docker run command first creates a writeable container layer over the specified image, and then starts it using the specified command. That is, docker run is equivalent to the API /containers/create then /containers/(id)/start. A stopped container can be restarted with all its previous changes intact using docker start. See docker ps -a to view a list of all containers.
docker stop thing-server
docker rm thing-server
docker run -p 1234:3000 --name thing-server ghcr.io/mitchallen/thing-server:latest
docker ps
Once the container is running, the interactive API explorer is available at:
http://localhost:1234/api-docs
The root endpoint also advertises the explorer path in its explorer field.
All configuration is optional — unset, the server serves the bundled data set at the root with no authentication.
| Variable | Default | Purpose |
|---|---|---|
PORT | 3000 | Port the server listens on inside the container. Map it with docker run -p <host>:3000. |
THINGSFILE | ./data/things.json | Path to the data file. Usually left alone and overridden with a volume mount instead — see Running with your own things. |
API_KEY | unset | When set, the things routes require a matching x-api-key header. See Require an API key. |
APP_NAME | thing-server | Name reported in the root, 404 and 401 bodies. See Override APP_NAME. |
BASE_PATH | / | Mounts the whole API under a sub-path. See Mount under a base path. |
The data file itself supplies the label (things) and path (/v1) segments of the routes; BASE_PATH is applied as a prefix on top of those.
The things routes can require an x-api-key header. Enforcement is off by default and turns on only when you set the API_KEY environment variable at launch:
docker run -p 1234:3000 -e API_KEY=your-secret-key --name thing-server ghcr.io/mitchallen/thing-server:latest
With API_KEY set, requests to the things routes must send a matching header or receive 401 unauthorized:
curl -H "x-api-key: your-secret-key" http://localhost:1234/v1/things
The root (/) health check and the Swagger explorer (/api-docs) remain open regardless. If API_KEY is not set, the API is open (no key required).
The server reports its name as thing-server in the root response and in error bodies. Set APP_NAME to override it:
docker run -p 1234:3000 -e APP_NAME=widget-server --name thing-server ghcr.io/mitchallen/thing-server:latest
curl http://localhost:1234/
{"status":"OK","app":"widget-server", ... }
The name also appears in the 401 unauthorized and 404 not found bodies, and as the Swagger explorer's page title.
By default the API lives at the root: /, /v1/things, /api-docs. Set BASE_PATH to move the whole API — root, things routes and explorer — under a sub-path, which is useful behind a reverse proxy that routes several services by prefix:
docker run -p 1234:3000 -e BASE_PATH=/api/svc1 --name thing-server ghcr.io/mitchallen/thing-server:latest
curl http://localhost:1234/api/svc1
curl http://localhost:1234/api/svc1/v1/things
curl http://localhost:1234/api/svc1/v1/things/count
The explorer moves too, to http://localhost:1234/api/svc1/api-docs, and the generated OpenAPI spec records the base path as its server URL. A trailing slash is tolerated (/api/svc1/ behaves the same as /api/svc1).
Note that BASE_PATH is a prefix: it stacks on top of the path from your data file, so the default path of /v1 becomes /api/svc1/v1. Once BASE_PATH is set the un-prefixed routes no longer resolve. The root response reports the resolved values in route, explorer and meta.path:
curl http://localhost:1234/api/svc1
{"status":"OK","app":"thing-server","route":"/api/svc1","explorer":"/api/svc1/api-docs","meta":{"label":"things","path":"/api/svc1/v1","count":3}}
Unset, both APP_NAME and BASE_PATH leave every route and response exactly as before.
Assumes container is running and set to port 1234.
Note that if you are observing the console, the examples on the screen will show the docker containers internal port - you must use the one you mapped the container to.
curl http://localhost:1234
curl http://localhost:1234/v1
curl http://localhost:1234/v1/things/count
curl http://localhost:1234/v1/things
curl http://localhost:1234/v1/things/1
Create a folder in your current directory called pets:
mkdir pets
In the new ./pets folder create a file called things.json (it must be called 'things.json' or the server won't find it).
Paste into things.json this JSON content and save it:
{
"label": "pets",
"path": "/v2",
"list": [
{
"name": "Pepper",
"age": 19
},
{
"name": "Marchio",
"age": 20
},
{
"name": "Richmond",
"age": 7
},
{
"name": "Bonnie",
"age": 18
}
]
}
You can change the data if you like, but remember the following:
http://localhost:1234/v2/pets/count (here pets is the label)http://localhost:1234/v2/pets/1 (here /v2 is the path)Now run the following to build a new container named pet-things
docker run -p 8100:3000 -v ${PWD}/pets:/usr/src/app/data --name pet-things mitchallen/thing-server
With the above content and values you could perform curl operations like this:
curl http://localhost:8100/
curl http://localhost:8100/v2
curl http://localhost:8100/v2/pets
curl http://localhost:8100/v2/pets/count
curl http://localhost:8100/v2/pets/1
You can run multiple containers on multiple ports like this:
docker run -p 8101:3000 -v ${PWD}/dogs:/usr/src/app/data --name dog-things mitchallen/thing-server
docker run -p 8102:3000 -v ${PWD}/cats:/usr/src/app/data --name cat-things mitchallen/thing-server
The servers would look for:
docker stop thing-server
docker stop pet-things
docker stop dog-things
docker stop cat-things
docker start thing-server
docker start pet-things
docker start dog-things
docker start cat-things
docker stop thing-server
docker rm thing-server
docker stop thing-server
docker rm thing-server
docker rmi mitchallen/thing-server
npm ci
npm test # build, then run the Cucumber suite
npm run test-coverage # same suite under c8; text table + coverage/lcov-report/index.html
Coverage must stay at 100% (statements, branches, functions and lines); test-coverage fails below that. CI runs test-coverage on every push and PR to main, writes the coverage table to the job summary, and uploads the HTML/lcov report as the coverage artifact.
Builds are automated via GitHub Actions and triggered by pushing a version tag.
Bump the version, commit, tag, and push:
npm version patch --no-git-tag-version
git add package.json package-lock.json
git commit -m "1.x.x"
git tag v1.x.x
git push origin main
git push origin v1.x.x
Tags matching v* trigger two workflows that build and push multi-platform (linux/amd64, linux/arm64) images to:
ghcr.io/mitchallen/thing-servermitchallen/thing-serverEach publish creates both a versioned tag and updates latest.
The Docker Hub workflow also syncs this README to the Docker Hub repository description.
The Docker Hub workflow needs these repository secrets (Settings → Secrets and variables → Actions):
DOCKERHUB_USERNAME — your Docker Hub usernameDOCKERHUB_TOKEN — a Docker Hub access tokenThe GitHub Container Registry workflow uses the built-in GITHUB_TOKEN; no extra secret is required.
MIT — see LICENSE.
The license covers this project's own code. It does not apply to any third party assets that were imported into the project as a utility or for demonstration purposes; contact the authors of those assets for their licensing information.
Content type
Image
Digest
sha256:93510a4c5…
Size
66.8 MB
Last updated
6 days ago
docker pull mitchallen/thing-server