Add helper function for creating responses with pagination header

This commit is contained in:
silverpill 2022-08-06 16:17:38 +00:00
parent acb139b0ee
commit 53ace3bf57
3 changed files with 78 additions and 43 deletions

View file

@ -5,8 +5,9 @@ pub mod markers;
pub mod media;
pub mod notifications;
pub mod oauth;
mod pagination;
pub mod search;
pub mod statuses;
pub mod timelines;
pub const MASTODON_API_VERSION: &str = "3.0.0";
const MASTODON_API_VERSION: &str = "3.0.0";

View file

@ -1,33 +1,26 @@
/// https://docs.joinmastodon.org/methods/notifications/
use actix_web::{get, web, HttpResponse, Scope as ActixScope};
use actix_web::{
get, web,
HttpRequest, HttpResponse,
Scope as ActixScope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use crate::config::Config;
use crate::database::{Pool, get_database_client};
use crate::errors::HttpError;
use crate::mastodon_api::oauth::auth::get_current_user;
use crate::mastodon_api::pagination::get_paginated_response;
use crate::models::notifications::queries::get_notifications;
use super::types::{ApiNotification, NotificationQueryParams};
fn get_pagination_header(
instance_url: &str,
last_id: &str,
) -> String {
let next_page_url = format!(
"{}/api/v1/notifications?max_id={}",
instance_url,
last_id
);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
format!(r#"<{}>; rel="next""#, next_page_url)
}
#[get("")]
async fn get_notifications_view(
auth: BearerAuth,
config: web::Data<Config>,
db_pool: web::Data<Pool>,
query_params: web::Query<NotificationQueryParams>,
request: HttpRequest,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let current_user = get_current_user(db_client, auth.token()).await?;
@ -40,18 +33,15 @@ async fn get_notifications_view(
.into_iter()
.map(|item| ApiNotification::from_db(item, &config.instance_url()))
.collect();
let max_index = usize::from(query_params.limit - 1);
let response = if let Some(item) = notifications.get(max_index) {
let pagination_header = get_pagination_header(&config.instance_url(), &item.id);
HttpResponse::Ok()
.append_header(("Link", pagination_header))
// Link header needs to be exposed
// https://github.com/actix/actix-extras/issues/192
.append_header(("Access-Control-Expose-Headers", "Link"))
.json(notifications)
} else {
HttpResponse::Ok().json(notifications)
};
let max_index = usize::from(query_params.limit.saturating_sub(1));
let maybe_last_id = notifications.get(max_index)
.map(|item| item.id.clone());
let response = get_paginated_response(
&config.instance_url(),
request.uri().path(),
notifications,
maybe_last_id,
);
Ok(response)
}
@ -59,19 +49,3 @@ pub fn notification_api_scope() -> ActixScope {
web::scope("/api/v1/notifications")
.service(get_notifications_view)
}
#[cfg(test)]
mod tests {
use super::*;
const INSTANCE_URL: &str = "https://example.org";
#[test]
fn test_get_next_page_link() {
let result = get_pagination_header(INSTANCE_URL, "123");
assert_eq!(
result,
r#"<https://example.org/api/v1/notifications?max_id=123>; rel="next""#,
);
}
}

View file

@ -0,0 +1,60 @@
use actix_web::HttpResponse;
use serde::Serialize;
fn get_pagination_header(
instance_url: &str,
path: &str,
last_id: &str,
) -> String {
let next_page_url = format!(
"{}{}?max_id={}",
instance_url,
path,
last_id
);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
format!(r#"<{}>; rel="next""#, next_page_url)
}
pub fn get_paginated_response(
instance_url: &str,
path: &str,
items: Vec<impl Serialize>,
maybe_last_item_id: Option<impl ToString>,
) -> HttpResponse {
if let Some(last_item_id) = maybe_last_item_id {
let pagination_header = get_pagination_header(
instance_url,
path,
&last_item_id.to_string(),
);
HttpResponse::Ok()
.append_header(("Link", pagination_header))
// Link header needs to be exposed
// https://github.com/actix/actix-extras/issues/192
.append_header(("Access-Control-Expose-Headers", "Link"))
.json(items)
} else {
HttpResponse::Ok().json(items)
}
}
#[cfg(test)]
mod tests {
use super::*;
const INSTANCE_URL: &str = "https://example.org";
#[test]
fn test_get_next_page_link() {
let result = get_pagination_header(
INSTANCE_URL,
"/api/v1/notifications",
"123",
);
assert_eq!(
result,
r#"<https://example.org/api/v1/notifications?max_id=123>; rel="next""#,
);
}
}