activitypub-federation-rust/docs/07_fetching_data.md
2023-07-12 15:27:29 +09:30

2.8 KiB

Fetching data

After setting up our structs, implementing traits and initializing configuration, we can easily fetch data from remote servers:

# use activitypub_federation::fetch::object_id::ObjectId;
# use activitypub_federation::traits::tests::DbUser;
# use activitypub_federation::config::FederationConfig;
# let db_connection = activitypub_federation::traits::tests::DbConnection;
# tokio::runtime::Runtime::new().unwrap().block_on(async {
let config = FederationConfig::builder()
    .domain("example.com")
    .app_data(db_connection)
    .build().await?;
let user_id = ObjectId::<DbUser>::parse("https://mastodon.social/@LemmyDev")?;
let data = config.to_request_data();
let user = user_id.dereference(&data).await;
assert!(user.is_ok());
# Ok::<(), anyhow::Error>(())
# }).unwrap()

dereference retrieves the object JSON at the given URL, and uses serde to convert it to Person. It then calls your method Object::from_json which inserts it in the database and returns a DbUser struct. request_data contains the federation config as well as a counter of outgoing HTTP requests. If this counter exceeds the configured maximum, further requests are aborted in order to avoid recursive fetching which could allow for a denial of service attack.

After dereferencing a remote object, it is stored in the local database and can be retrieved using ObjectId::dereference_local without any network requests. This is important for performance reasons and for searching.

We can similarly dereference a user over webfinger with the following method. It fetches the webfinger response from .well-known/webfinger and then fetches the actor using ObjectId::dereference as above.

# use activitypub_federation::traits::tests::DbConnection;
# use activitypub_federation::config::FederationConfig;
# use activitypub_federation::fetch::webfinger::webfinger_resolve_actor;
# use activitypub_federation::traits::tests::DbUser;
# let db_connection = DbConnection;
# tokio::runtime::Runtime::new().unwrap().block_on(async {
# let config = FederationConfig::builder().domain("example.com").app_data(db_connection).build().await?;
# let data = config.to_request_data();
let user: DbUser = webfinger_resolve_actor("nutomic@lemmy.ml", &data).await?;
# Ok::<(), anyhow::Error>(())
# }).unwrap();

Note that webfinger queries don't contain a leading @. It is possible tha there are multiple Activitypub IDs returned for a single webfinger query in case of multiple actors with the same name (for example Lemmy permits group and person with the same name). In this case webfinger_resolve_actor automatically loops and returns the first item which can be dereferenced successfully to the given type.