go-mastodon
go-mastodon copied to clipboard
Feature: Save API JSON (briefly) if requested by client
I'm using this library for archival purposes (eg. saving my favourites to SQLite) and I find it useful to keep the raw API response around after the API call since it often contains extensions, fields, etc., that aren't necessarily parsed out and returned in library objects.
e.g. from my Akkoma instance, status responses have information about quote-boosting which doesn't exist in the mastodon.Status
struct. Also various pleroma
and akkoma
extensions for the status text and instance information.
Since almost no-one is going to need this, it's gated behind Client.SaveJSON
being true
(and limited to 100MB of JSON to be safe.) By default, the library will behave exactly the same as before.
(I admit it's not a great solution but I don't think there is one for a situation like this without extending every API method to optionally return the JSON or similar.)
I prefer to do with TeeReader.
type Client struct {
...
JsonWriter io.Writer
}
if c.JsonWriter != nil {
return json.NewDecoder(io.TeeReader(resp.Body, c.JsonWriter)).Decode(&res)
} else {
return json.NewDecoder(resp.Body).Decode(&res)
}
client := mastodon.NewClient()
var buf bytes.Buffer
client.JsonWriter = &buf
// something to do with a client
Neat solution! It does require the caller to remember to issue a buf.Reset()
before every API call they want the JSON from though -- a definite footgun (I know because I just encountered it) and a bit untidy. Can't do the Reset()
from the library though because it's not available on io.Writer
.
A localised WriteResetter
interface fixes things and keeps the client code tidy.
type WriteResetter interface {
io.Writer
Reset()
}
type Client struct {
...
JSONWriter WriteResetter
}
if c.JSONWriter != nil {
c.JSONWriter.Reset()
return json.NewDecoder(io.TeeReader(resp.Body, c.JSONWriter)).Decode(&res)
} else {
return json.NewDecoder(resp.Body).Decode(&res)
}
Thoughts?
Reverted to simple io.Writer
with client-initiated resetting. Think making JSONWriter
a simple *bytes.Buffer
and moving the reset to the library makes more sense (when would someone supply a non-bytes.Buffer
as somewhere to save the JSON?) but could live with this solution.
It can check before call Write()
if resetter, ok := c.JSONWriter.(WriterResetter); ok {
resetter.Reset()
}
Ah, I think I got almost to that solution twice with the WriteResetter
and then checking if an interface{}
could call Reset()
. Never checked a type assertion on an interface that's bigger than a type before. Thanks.