Documentation Wiki

GoActivityPub logo

The GoActivityPub library contains the building blocks for adding ActivityPub functionality to both client and server applications for the Go programming language. It is a robust, “batteries included” product with a high level of interoperability with the rest of the Go ecosystem.

The focus is on high spec compliance, minimal external dependencies, and minimal computing requirements.

The library is divided into functionally independent modules connected through interfaces.

The official repositories for the project are hosted under the go-ap GitHub organization.

The high level view on the project offers the following distinct pieces:

For more information go to the description page.

Design decisions

The main problem of implementing the ActivityPub specification in the Go programming language stems from the very dynamic nature of JSON-LD, which is used as its data format, and the limited (in this respect) features of the Go type system.

This apparent incompatibility stems from the fact that an object property in the ActivityPub specification can have any of the following values:

Because the Go type system can’t express this union explicitly, we rely on implementing these four meta-types independently and giving them unifying behavoiur through the interface: ObjectOrLink. Basically if any type implements this interface[1], it can be used with the GoActivityPub modules.

To keep in line with Go’s interface guidelines, we have tried to keep the methods this interface exposed to a minimum, and this led to a very limited guaranteed API for the module.

To circumvent the fact that most of the library deals with instances of this interface, we had to create the convenience functions that allow a developer to assert them to actual useful ActivityPub structs.

They are the functions starting with OnXXX and ToXXX in the module and give the possibility of treating any struct that impelments ObjectOrIRI as an XXX ActivityPub object, where XXX can be an Activity, an Actor, Object, Link samd.

This is incidentally the mechanism through which we allow extending the default AP vocabulary by other modules. Other developers can create their own type YYY, implement the interface and add their OnYYY functionality[2].

The first caveat about this type of logic is that it relies heavily (at least currently) on the fact that the memory layout for each type needs to be identical for the properties which are common. The properties need to have the same order and the same type. Basically the existing ToXXX functions work as a cast does in plain C. It takes the pointer the interface holds, and converts it to the desired type (using the unsafe package) relying on the fact that the common properties of the Objects are at the same offsets from the pointer[3].

[1] The interface matches the ActivityStreams separation between Object compatible structs and Link compatible structs.

[2] This also requires overriding the default typer function, which is used to return the correct type based on the YYY.Type property.

[3] This behaviour is risky and it can probably change without warning if the Go dev team changes the language’s memory model at a later date. I hope I’ll find a cleaner way to implemnt this in the future, but for now it serves its purpose.

Spec compliance chart.

Pitfalls

I compiled a list of pitfalls when using the modules.