~yana/lemmy-api

A set of bindings to the Lemmy API, for Common Lisp
remove whitespace
Add a utilities file for helpful utilities and wrappers.
add auto method for calling an api endpoint

clone

read-only
https://git.sr.ht/~yana/lemmy-api
read/write
git@git.sr.ht:~yana/lemmy-api

You can also use your local clone with git send-email.

#LEMMY-API

This repository implements bindings to the Lemmy API for Common Lisp.

Lemmy API interfaces, API endpoints, enums, and types are defined according to the unofficial openapi specification.

#Build Status

builds.sr.ht status

#Information

The main project page is available at https://sr.ht/~yana/cl-lemmy-api/. Bugs may be reported at https://todo.sr.ht/~yana/cl-lemmy-api/. The mailing list is used for patches and general discussion. The mailing list archives can be browsed at https://lists.sr.ht/~yana/cl-lemmy-api/.

#Quickstart

Start by loading the ASDF system :LEMMY-API. This will load the most recent version of the api bindings (v0.19.5 at time of writing).The API can now be interacted with by using the generic function CALL-API-ENDPOINT with an endpoint and an instance of a lemmy interface class, such as GET-POSTS. The instances of lemmy interface objects can be validated with the function VALIDATE-LEMMY-INTERFACE.

As an example of this, lets take a look at what logging in might look like:

CL-USER> (ql:quickload :lemmy-api)
To load "lemmy-api":
  Load 1 ASDF system:
    lemmy-api
; Loading "lemmy-api"
..................................................
[package lemmy-api/0.19.5]........................
..................................................
[package lemmy-api].
(:LEMMY-API)
CL-USER> (lemmy-api:call-api-endpoint 'lemmy-api:/user/login
                                      (make-instance 'lemmy-api:login
                                                     :username-or-email
                                                     "USERNAME"
                                                     :password
                                                     "PASSWORD")
                                      :server "https://SERVER.com"
                                      :validate-inbound t)
WARNING: Received HTTP response code 200. Expected one of the following:
         400, 201
#<LEMMY-INTERFACE "LoginResponse" {1005020BE3}>
200 (8 bits, #xC8, #o310, #b11001000)
CL-USER> (setf lemmy-api:*jwt* (lemmy-api:jwt *))
"long-token"
CL-USER> (lemmy-api:call-api-endpoint 'lemmy-api:/user/list_logins
                                      nil
                                      :server "https://SERVER.com")
(#<LEMMY-INTERFACE "LoginToken" {1005829293}>
 #<LEMMY-INTERFACE "LoginToken" {1005829333}>
 #<LEMMY-INTERFACE "LoginToken" {10058293D3}>
 #<LEMMY-INTERFACE "LoginToken" {1005829473}>
 #<LEMMY-INTERFACE "LoginToken" {1005829513}>
 #<LEMMY-INTERFACE "LoginToken" {10058295B3}>)
200 (8 bits, #xC8, #o310, #b11001000)

Most api endpoints return a lemmy interface object, however this one (/user/list_logins) returns an array of lemmy interface objects.

Since version 0.19.5 the way the API is interacted with has changed. Prior to this API calls were made with the function LEMMY-API-OPERATE. This is considered deprecated and is not implemented for version 0.19.5 or later, but the generic function is still present.

#Quirks

As of version 0.18.3: Some slots are specified as required but are not given by the server. These should be specified when calling VALIDATE-LEMMY-INTERFACE, or added to the dynamic variable *SLOTS-TO-IGNORE*. A non-comprehensive list is given at the end of this document. If you become aware of such errors, please submit a patch updating this list.

When parsing a lemmy interface object without being given an explicit type, a object of type EMPTY-LEMMY-INTERFACE will be instantiated instead, with its slot UNKNOWN-SLOTS propogated with whatever the JSON parsed out to. An example of this can be found in the api endpoint /USER/VALIDATE_AUTH in version 0.19.5, which does not expect a JSON response from the server but gets one anyway.

This system does not bind slots that dont have a value when generating them from a JSON response. As such, it may be helpful in certain circumstances to define custom accessors for specific slots, or alternatively to establish a handler for unbound slot errors that returns NIL when invoked with a lemmy-interface object. E.g.

(handler-bind ((unbound-slot
                (lambda (c)
                  (when (typep (unbound-slot-instance c) 'lemmy-interface)
                    (let ((r (find-restart 'use-value c)))
                      (when r
                        (invoke-restart r nil)))))))
  (code body))

As of version 0.18.3: This system does not provide complete bindings. The current system of parsing bindings from the javascript sources is error prone; not all interfaces and methods parse correctly. The solution to this would be to generate an api specification from the rust sources using rust macros. While this is currently under consideration at time of writing, it appears there are numerous issues standing in the way of this. If you are interested in contributing to this endeavor, please see this issue as a starting point: https://github.com/LemmyNet/lemmy/issues/2937.

As of version 0.19.5: The unofficial lemmy openapi specification is used to generate the bindings. This eliminates the error prone parsing of javascript sources. However this system should not be assumed to provide all bindings. If you find a binding that is not present or has not been parsed correctly, please open an issue.

#Systems

This project is broken up into three strata. The base system, LEMMY-API/BASE, defines the framework that allows interface objects to be implemented. This includes, among other things, the macros DEFINE-INTERFACE-CLASS and DEFINE-API-ENDPOINT. The top level system LEMMY-API provides a common package to expose symbols from specific lemmy api versions. These versioned packages, such as LEMMY-API/0.18.3, are USEd by, and have their symbols re-exported from, LEMMY-API.

#Using Specific API Versions

The system LEMMY-API loads the latest version of the API bindings (at the time of writing this is v0.19.5), however alternate versions can be loaded by asdf by specifying the version number, e.g. LEMMY-API/0.18.3. The LEMMY-API package does not define or export any additional symbols, it is provided simply for ease of use, and the underlying versioned packages can be used in its stead.

The specific definition files for individual versions lie in the version/x.y.z/ folders. In addition, the specific version of the lemmy api currently loaded is pushed to the *FEATURES* list, and multiple versions of the api bindings can be loaded, as they reside in separate packages.

#USE-ing This Package

Do not use the System LEMMY-API, unless providing a vendored version; the LEMMY-API package tracks the latest api version, and its exported symbols are subject to change. However, LEMMY-API/MAJ.MIN.PAT packages should be considered stable and not subject to change.

#Defining New API Versions

New api versions can be defined by running the shell script generate-bindings.sh. This shell script takes a single .yaml specification file as its only argument. This will place the result of the specification into its own version folder. It will not generate the asd file entry for the generated version, this must be manually added to the file lemmy-api.asd using the macro define-lemmy-version.

#Documentation

#Base System

#FILE: mop.lisp

This file defines the metaobject used for lemmy interface classes. The MOP is used to add additional parameters to slot definitions, which eases the conversion of slot values into and out of the JSON format, and allows for easier validation.

#FILE: interfaces.lisp

This file provides the interface definition macro and the validation function for interface objects.

#FILE: conditions.lisp

This file defines conditions used in the lemmy api system.

#FILE: json-to-interface.lisp

This file defines how interface objects will be parsed from JSON.

#FILE: interface-to-json.lisp

This file provides the inverse of json-to-interface.lisp.

#FILE: api-methods.lisp

This file provides the plumbing for sending and receiving information to and from a server. It defines the macro DEFINE-API-ENDPOINT, as well as the deprecated DEFINE-LEMMY-API-METHOD. It also defines a host of auxillary functions for making the actual api calls.

#Versioned Systems

#FILE: versions/major.minor.patch/package.lisp

This file defines the specific versioned package, and registers the feature :LEMMY-API/MAJOR.MINOR.PATCH.

#FILE: versions/major.minor.patch/definitions.lisp

As of version 0.19.5: This file is generated automatically in two stages from the unofficial openapi specification. First the specification (a .yaml file) is parsed into memory, and then used to generate a lispy specification file. That specification file is used to generate a definitions file containing all the type, class, and method definitions.

As of version 0.18.3: This file is generated automatically in two stages from the lemmy javascript client sources. First the javascript client sources are parsed into a specification file. These specifications are then used to generate the types, classes, and methods which reside in this file. In addition all types, class names, and accessors are exported.

#License

GPLv3

#Slots to Ignore

  • v0.18.3
    • INBOX-URL