packages feed

haskoin-store-1.10.1: src/Haskoin/Store/Web/Docs.hs

{-# LANGUAGE TemplateHaskell #-}

-- |
-- Module      : Haskoin.Store.Web.Docs
-- Copyright   : (c) Haskoin Developers
-- License     : MIT
-- Maintainer  : jprupp@protonmail.ch
-- Stability   : experimental
-- Portability : POSIX
--
-- The reference of the API, served by the server that it describes: the
-- page at the root of the server, and the description that the page reads.
--
-- = Why the server carries its own reference
--
-- @swagger.yaml@ is the reference of the API. A copy on a web site
-- describes whatever version that site was last given, and someone who
-- runs a server wants the reference of the server in front of them. So the
-- file is compiled into the program ('swaggerYaml'), and the root of the
-- server answers with a page that shows it ('swaggerPage').
--
-- The file names one server, @.\/@, a relative address that a reader
-- resolves against the address it read the file from. Requests tried from
-- the page go to the server that served it, whether it answers at the root
-- of a host or behind a proxy under a path such as @\/btc\/@. The file
-- names no public servers: those would describe someone else's servers,
-- at whatever version they run. The page has no list of servers to choose
-- from and no box to load another description, for the same reason.
--
-- = What the page needs
--
-- The page is Swagger UI, loaded from a public CDN at a fixed version. A
-- browser without access to the Internet shows an empty page;
-- @\/swagger.yaml@ is served either way. The program is not made a
-- megabyte and a half larger to carry a copy of it.
module Haskoin.Store.Web.Docs
  ( swaggerYaml,
    swaggerPage,
  )
where

import Data.ByteString (ByteString)
import Data.ByteString qualified as B
import Data.FileEmbed (embedFile, makeRelativeToProject)

-- | @swagger.yaml@ as it was when the program was built.
swaggerYaml :: ByteString
swaggerYaml = $(makeRelativeToProject "swagger.yaml" >>= embedFile)

-- | The page at the root of the server: Swagger UI, showing 'swaggerYaml',
-- which it asks this server for, next to wherever the page itself is. It
-- leaves out the bar of Swagger UI that loads another description, and the
-- list of servers, which holds only this one.
swaggerPage :: ByteString
swaggerPage =
  B.intercalate
    "\n"
    [ "<!DOCTYPE html>",
      "<html lang=\"en\">",
      "<head>",
      "  <meta charset=\"UTF-8\">",
      "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">",
      "  <title>Haskoin Store API</title>",
      "  <link rel=\"stylesheet\" href=\"" <> cdn <> "/swagger-ui.css\">",
      "  <style>",
      "    /* the list of servers, which holds only this one */",
      "    .swagger-ui .scheme-container { display: none; }",
      "  </style>",
      "</head>",
      "<body>",
      "  <div id=\"swagger-ui\"></div>",
      "  <noscript>The reference of this API is at <a href=\"swagger.yaml\">swagger.yaml</a>.</noscript>",
      "  <script src=\"" <> cdn <> "/swagger-ui-bundle.js\" charset=\"UTF-8\"></script>",
      "  <script>",
      "    window.onload = function () {",
      "      // next to this page, whether or not its address ends in a slash",
      "      const here = window.location.href.split(/[?#]/)[0].replace(/\\/?$/, '/');",
      "      window.ui = SwaggerUIBundle({",
      "        url: new URL('swagger.yaml', here).href,",
      "        dom_id: '#swagger-ui',",
      "        presets: [SwaggerUIBundle.presets.apis],",
      "        layout: 'BaseLayout'",
      "      });",
      "    };",
      "  </script>",
      "</body>",
      "</html>",
      ""
    ]
  where
    cdn = "https://unpkg.com/swagger-ui-dist@5.17.14"