Go-Fed Activity v1 Preview

I am happy to announce that go-fed v1 is preview-ready. It has seen significant improvements over go-fed v0, which was my first attempt at an ActivityStreams and ActivityPub implementation that began over a year ago. The new version is built upon knowledge, experiences, and hindsight gained over the past year communicating with other ActivityPub developers.

The new features include: a new tool called astool to generate ActivityStreams native golang types from an OWL definition for any extension, a redesign of the ActivityStreams API to be more intuitive, successful compilation on memory constrained environments, and a refactor of the ActivityPub implementation to facilitate different degrees of customization.

Version 1 has not yet had all of its unit tests complete. Hence, it is available for preview but not yet touted as a full release. There may still be bugs and misbehaviors in the code, but it is expected that any further changes will be internal fixes. Any changes to the interfaces are expected to be very minor.

Let’s examine some of the significant changes now.

The first major change to go-fed v1 is the introduction of the astool. It takes an OWL definition of the ActivityStreams specification, or any extension of the ActivityStreams vocabulary, and outputs code that implements the properties and types as native golang types. The go-fed v0 implementation had two different tools for generating the ActivityStreams types because there were two different APIs provided. Those tools had hard coded data for only the ActivityStreams specification and was generally unmaintainable going forward. The new tool is able to properly understand OWL definitions as RDF and linked data, but only at code generation time, which means go-fed’s ActivityPub implementation is still not linked-data aware at runtime. The tool is designed to be more sustainable going forward if more features are requested of it. Furthermore, only one API is generated for the ActivityStreams types and it is much more developer-friendly than either of the go-fed v0 ActivityStreams APIs were.

This isn’t all. The ActivityStreams types are interacted with solely through interfaces, which allows developers to dependency inject their own implementations should they find the default serialization/deserialization of go-fed insufficient. ActivityStreams properties are now viewed as golang types which makes it easier to process data. The generated code also has comments. Great care has been put in to ensure that the comments are accurate and useful when viewing the generated interfaces. Finally, the generated code is independent of future extensions that have yet to be generated. An astute developer may notice that the vocabulary name “ActivityStreams” is present in a lot of identifiers. These more verbose names ensure code written today is valid no matter how many extensions are generated in the future.

And as always, the ActivityStreams types can be used independently of the ActivityPub implementation.

As for the go-fed ActivityPub implementation, it has seen major rework. It now caters towards application developers who want more granular ActivityPub support. It is my hope that this is appealing both to developers creating a new app from scratch and developers trying to incorporate go-fed into to an existing project. For example, a developer can first decide whether to use the ActivityPub solution provided out of the box, or implement their own higher level abstraction (DelegateActor) for a custom ActivityPub solution. On a more detailed level, those that decide to use the out-of-the-box solution can choose whether to support the federating protocol, the social protocol, or both. They can also enable, disable, or augment the default behaviors for common ActivityStreams types. Since the library supports progressive customization, application developers may progressively accumulate customized behavior with the out-of-the-box solution and then later switch to the fully-custom DelegateActor option. The library does its best to not get in the way of the lifecycle of an application; it provides a lot of help to quickly get bootstrapped and then can slowly be replaced with custom behavior as the application matures.

The Actor interface is very small and meant for concurrent use. New applications can build their HTTP handlers around the Actor’s hooks. Existing applications should find it relatively trivial to integrate these calls into new or existing handlers. It uses the standard library’s Context concept throughout the library to ensure the application can manage per-request state. Since an Actor requires some help from dependency injected implementations, both new and existing applications will find the bulk of the work in implementing these interfaces so go-fed can accomplish ActivityPub tasks out of the box.

One problem with go-fed v0’s ActivityPub implementation was how it handled dispatching concrete ActivityStreams types to callbacks. This is now flexibly handled by code-generated Resolvers in the ActivityStreams library itself. Therefore, applications that are built using go-fed can seamlessly generate the new extensions of the future and begin coding application logic directly against the new vocabularies. The way go-fed scales in its ActivityPub implementation with new vocabulary extensions requires only for the application to write new handlers for the new types they care about and want to handle.

So whether it is by ActivityStreams extensions, more custom behaviors, or supporting both C2S and S2S, go-fed is designed to scale.

The future looks bright! All that is left are copious amounts of unit tests and redesigning the go-fed site to reflect v1 of the library. I would like to run an additional implementation report. Then, go-fed v1 should be stable for many ActivityPub extensions and applications to come.

Published: Jun 19, 2019 17:12:20 EDT
By: Cory Slep