This is a template implementation of an API server with an example command-line tool to go along with it. It features complete option parsing, like in template-optparse, a command-line tool like in template-cli as well as handlers, testing and best-practices.
- Haskell code for an api-server
- Per-route integration tests for the api-server
- Haskell code for an accompanying command-line tool
- Per-command integration test for the cli tool
- Option parsing & Option parsing tests for both the server and the cli tool
- Stack build
- Cabal build
- Nix build
- Statically linked Nix build
- Test Coverage report
- Weeder check
- NixOS module for hosting the server
- Nix home manager module for using the client
- Flake-based CI
- Pre-commit hooks
- hlint
- hpack
- nixpkgs-fmt
- ormolu
This template is not free to use. See https://template.cs-syd.eu/template/NorfairKing/template-api-server-with-auth-and-cli for more information.
Copyright (c) 2020-2024 Tom Sydney Kerckhove.
All Rights Reserved.
To use this template in a new project, choose the name for your project, for example homeless-shelter
.
Then use template-filler to use the template, like this:
template-filler --source /path/to/this/template-api-server-with-auth-and-cli --destination /path/to/your/homeless-shelter --find FooBar --replace HomelessShelter
This template contains these haskell packages and notable modules:
foo-bar-api
: The API, as aservant
-based type definition, and related data types.Foo/Bar.API.Data
: The API data type definitionsFoo/Bar.API
: The API Type definition
foo-bar-api-gen
: The generators and tests for the API and its data types.FooBar.API.Data.Gen
: Generators for the API data types
foo-bar-api-server
: The API server that implements this API.Foo/Bar.API.Server.OptParse
: Option parsingFoo/Bar.API.Server.Env
: The (read-only) environment and related functionsFoo/Bar.API.Server.Handler.<CommandName>
: One module per command of the CLI.
foo-bar-api-server-gen
: The generators and tests for the API server.Foo/Bar.API.Server.TestUtils
: Utility functions to write tests that use the API serverFoo/Bar.API.Server.Handler.<CommandName>Spec
: One module per handler containing its tests
foo-bar-client
: The client record of functions to call the API server.- The
Foo/Bar.Client.foo-barClient
record.
- The
foo-bar-cli
: An example command-line tool to call the API server.Foo/Bar.CLI.OptParse
: Option parsingFoo/Bar.CLI.Env
: The (read-only) environment and related functionsFoo/Bar.CLI.Command.<CommandName>
: One module per command of the CLI.
The option parsing for both foo-bar-cli
and foo-bar-api-server
is based on the option parsing template.
It is included in this template so you will not need to also buy the option parsing template.
For more information about how to use the option parsing, follow the instructions in template-cli/src/Foo/Bar/Cli/OptParse.hs
.
If you don't need a nix build, remove these files:
rm -rf *.nix nix
The project overlay is defined in nix/overlay.nix
.
In nix/nixos-module.nix
, we define a NixOS module for hosting the server.
In nix/home-manager-module.nix
, we define a nix home manager module for using the project on NixOS.
In nix/nixos-module-test.nix
, both of those are tested. This test is not run on CI because GitHub actions does not support it.
See the instructions in nix/overlay.nix
for more details.
-
Add the endpoint in
foo-bar-api/src/Foo/Bar/API.hs
. -
Add a handler module in
foo-bar-api-server/src/Foo/Bar/API/Server/Handler/<RouteName>hs
with a function as follows:handle<RouteName> :: H ()
Give it a type according to the endpoint type. If it requires authentication, add
AuthCookie
as the first argument. -
Hook up the handler in the
foo-barHandlers
record infoo-bar-api-server/src/Foo/Bar/API/Server.hs
.If the endpoint requires authentication, use the
protected
combinator. -
Add tests in
foo-bar-api-server-gen/test/Foo/Bar/API/Server/Handler/<RouteName>Spec.hs
-
Add the new command's option parsing in the
Foo/Bar.CLI.OptParse
module according to the instructions within. -
Add a
Foo/Bar.CLI.Command.<CommandName>
module with a function as follows:commandName :: CommandNameSettings -> C ()
-
Add a case to the
dispatch
function inFoo/Bar.CLI
. -
Add tests in
Foo/Bar.CLI.Command.<CommandName>Spec
.