Self documenting API specifications

I wanted to prepare the API specification for the backend developers in the most efficient way possible. Elm code is quite self explanatory, unfortunately Elm language is not the best at introspection. My idea was to display the Model type and the Decoders in some page that other developers could use for documentation. Moreover I wanted to provide a simple interface to test the API’s payloads.

This is the simplest solution that I could think of

  1. Provide a list of input fields and button that would allow to test the API and have their payload going through the Elm decoders
  2. Read the Elm source code and display on the page the significant part (Decoders and Types)

This is the result:

These are two examples of screens with a successful API test and one with error:

The test area is created with Elm, the two grey areas at the bottom are generated with Javascript using this code:

<pre id="decoders"></pre>
<pre id="types"></pre>
<script type="text/javascript">
(function() {
function readTextFile(file, fn) {
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function() {
if (rawFile.readyState === 4) {
if (rawFile.status === 200 || rawFile.status === 0) {
var allText = rawFile.responseText;
return fn(allText);
}
}
};
rawFile.send(null);
}
readTextFile("/source/scripts/helpers/types.elm", function(allText) {
document.getElementById('types').innerHTML = allText.match(/-- DATA[\s\S]*/)[0];
});
readTextFile("/source/scripts/helpers/decoders.elm", function(allText) {
document.getElementById('decoders').innerHTML = allText.match(/-- DATA[\s\S]*/)[0];
});
})();
</script>

types.elm and decoders.elm are accessible, in the development environment, through the webserver. So the above snippet is receiving them using XMLHttpRequest.

This is, for example, decoders.elm

module Helpers.Decoders exposing (..)
import Json.Decode as Decode exposing (Decoder)
import Helpers.Types as Types
-- DATA DECODERS --
originDecoder : Decoder Types.Origin
originDecoder =
Decode.at [ "origin" ] Decode.string