schemedoc / api.scheme.org

Web server for the Scheme API
1 stars 1 forks source link

Overview

This repository holds a first shot of a documentation infrastructure for various Scheme dialects.

The complete functionality is split into various layers:

  1. An central API server, which provides an HTTP API for various ways to request documentation relevant information.

  2. An API middleware, which can optionally be used on the developers systems to access the API server. It defines an API client, which performs the communication with the API server, but it can also define additional features such as caching API responses or access to documentation-related features of a given Scheme dialect such as the describe {identifier} command of various Scheme REPLs.

  3. An editor client, that can either access the API server, or - if installed - the API middleware.

It is planned to implements the layers so that it's possible to use at least a subset of the overall functionality without having to have all layers available. So in a simplified local setup the editor client might directly communicate with the central API server, in this case missing access to the features a locally running instance of the given Scheme dialect. Or the locally installed API middleware can make access to all built-in features available while no access to the internet and the central API server is possible.

For the maximal 3-tier deployment option, the complement component architecture can be depicted as shown below:

     +------------+        +----------------+
     | Metadata:  |        |                |
     | source of  +--------> API server     |
     | truth      |        |                |
     +------------+        +--------+-------+
                                    |
  Internet                          |
+------------------------------------------------+
  local                             |
                                    |
     +------------+        +--------v-------+
     | Metadata   |        |                |
     | local      +--------> API middleware |
     | cache/copy |        |                |
     +------------+        +---+---------+--+
                               |         |
                               |         |
     +------------+   +--------v---+  +--v---------+
     | Metadata   |   |            |  |            |
     | local      +---> API client |  | Editor     |
     | cache/copy |   |            |  |            |
     +------------+   +------------+  +------------+

History

It all started with various discussions in the srfi-discuss mailing list, which revolved around the topic as how to set-up an infrastructure allowing access to the documentation of Scheme procedures and other symbols defined by Scheme SRFIs. The initial idea in this discussion was to add structural information to existing and new Scheme SRFIs in order to potentially support various mostly documentation-related tools. A summary of these discussions can be found here.

Some concretization with focus on some simple Emacs helpers incl. some links on exisiting Emacs infrastucture has been noted here.

And finally a first shot on collecting some relevant meta data to drive the Scheme documentation infrastructure can be found here.

Prior art:

Status

Implementation

Sharing common code

Folder ~/src/common defines some common code shared by all implementations. Since I cannot expect to find a sufficiently common module feature set over all implementations, I do not even try to use modules for this task, instead I'm using more low-level file inclusion. This section holds some notes on what I found out while trying to combine the module mechanism specific for a given Scheme dialect and the low-level file inclusion.

Note that it's necessary that the calling module already imports all required dependencies before including a common Scheme file, so that these files can be written without having to require their dependencies - as the loading of these dependencies might again force implementation-specific code to be used.

The following procedure naming convention has been chosen for the common include files:

Gauche

Both include and load do work, assuming that the folder for the common sources (~/src/common/sdp/common) has been added to the load path; see Makefile. Still when using load, Gauche requires to pass the environment of the current module as shown in the source block below:

(load "metadata" :environment (find-module 'sdp.common.metadata-gauche))

Note that when including a file into a Gauche modul, it seems to be necessary to first explicitly select the current module using something like (select-module sdp.common.model-gauche) to avoid errors such as "Attempted to create a binding (...) into gauche....".

Guile

When using load, Guile requires eval-when, see the example source block below (and the documentation). Guile also requires to add the root folder for the common sources (~/src/common) to be added to the load path. Alternatively primitive-load-path can be used within eval-when and with using a relative path.

As it is supposed to do, include does not require eval-when, but it also did not resolve paths as expected. So instead for Guile I'm using include-from-path, which again requires a relative path and assumes that the root folder for the common sources (~/src/common) has been added to the load path; see Makefile.

(eval-when (expand load eval)
;; requires -L "$(CURDIR)/common": this will call (primitive-load-path "sdp/common/metadata.scm")
(load "metadata.scm")) ; or: (primitive-load-path "sdp/common/metadata.scm")

Note: Guile has a non-standard extension which allows to customize the default printing behavior of records, see here, chapter "Custom Printers". This is currently not used.

Testing included and imported bindings

Gauche

gosh -A"./gauche" -A"./common/sdp/common" -e"(use sdp.common.model-gauche)" -e"(display (list make-client-info-gauche make-request))" -e"(exit)"

Guile

guile  -L "./guile" -L "./common" -c "(use-modules (sdp common model-guile)) (display (list make-client-info-guile make-request))"

Reading metadata

Some of the features provided by this application are implemented by accessing the schemedoc metadata defined in this repository: https://github.com/schemedoc/implementation-metadata. The files from this repository are expected locally in a filesystem folder, which needs to be passed to the helper procedures defined below; see Makefile variable MD_PATH.

The helper procedures wrap the access to the metadata, as far as the content is related to the Scheme documentation.

API server, implemented in Guile Scheme

The API server is implemented as an HTTP server, so it will run as a central instance and hence there is no (urgent) need to implement it in a portable way. The current implementation is using Guile Scheme.

The HTTP API server obviously exposes its features as HTTP requests/responses, where each supported URL exposes one specific documentation feature and where each such feature is provided by one of the lower-level modules, e.g. the modules wrapping access to the metadata or the REPL-specific documentation helpers.

Note that since the server is implemented dependent from a specific Scheme dialect, we can only support the implementation of that specific Scheme for those features, that forward documentation-search to Scheme-specific code. Concretely we can e.g. only call the Guile-specific REPL documentation helpers from Guile in the API server.

Guile server runner

The code in module (sdp server http) is mostly a hack/stub, which currently just tests the end-to-end call chain from the request dispatcher to response generation, dispatching from the requested URL-infix and the related feature to the lower-level implementation of that feature.

API middleware and API client

The API server supports a simple 2-tier architecture, where its API client (usually the editor) can directly access that central HTTP server, no further infrastructure required.

But an API client written for a specific editor can only support those features that have been implemented for that central API server. So using that 2-tier architecture there is no way for the documentation infrastructure implemented in Guile Scheme to allow access to the Scheme-specific REPL documentation helpers from any other Scheme dialect - we need a local Scheme instance for the given dialect also to support that. So while complicating both the implementation as well as the setup of the documentation infrastructure, a local API middleware can in exchange provide some additional features: