Implement HTTP API using generics (fixes #380)

This commit is contained in:
Felix 2020-01-15 16:37:25 +01:00
parent 8604c1d257
commit 1e60e1e351
4 changed files with 66 additions and 2 deletions

View file

@ -1,2 +1,2 @@
tab_spaces = 2 tab_spaces = 2
edition="2018" edition="2018"

View file

@ -6,7 +6,7 @@ use actix::prelude::*;
use actix_web::*; use actix_web::*;
use diesel::r2d2::{ConnectionManager, Pool}; use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection; use diesel::PgConnection;
use lemmy_server::routes::{federation, feeds, index, nodeinfo, webfinger, websocket}; use lemmy_server::routes::{api, federation, feeds, index, nodeinfo, webfinger, websocket};
use lemmy_server::settings::Settings; use lemmy_server::settings::Settings;
use lemmy_server::websocket::server::*; use lemmy_server::websocket::server::*;
use std::io; use std::io;
@ -44,6 +44,7 @@ async fn main() -> io::Result<()> {
.data(pool.clone()) .data(pool.clone())
.data(server.clone()) .data(server.clone())
// The routes // The routes
.configure(api::config)
.configure(federation::config) .configure(federation::config)
.configure(feeds::config) .configure(feeds::config)
.configure(index::config) .configure(index::config)

62
server/src/routes/api.rs Normal file
View file

@ -0,0 +1,62 @@
use crate::api::community::{
GetCommunity, GetCommunityResponse, ListCommunities, ListCommunitiesResponse,
};
use crate::api::UserOperation;
use crate::api::{Oper, Perform};
use actix_web::{web, HttpResponse};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection;
use failure::Error;
use serde::Serialize;
type DbParam = web::Data<Pool<ConnectionManager<PgConnection>>>;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg
// TODO: need to repeat this for every endpoint
.route(
"/api/v1/list_communities",
web::get().to(|info, db| {
route::<ListCommunities, ListCommunitiesResponse>(UserOperation::ListCommunities, info, db)
}),
)
.route(
"/api/v1/get_community",
web::get().to(|info, db| {
route::<GetCommunity, GetCommunityResponse>(UserOperation::GetCommunity, info, db)
}),
);
}
fn perform<Request, Response>(
op: UserOperation,
data: Request,
db: DbParam,
) -> Result<HttpResponse, Error>
where
Response: Serialize,
Oper<Request>: Perform<Response>,
{
let conn = match db.get() {
Ok(c) => c,
Err(e) => return Err(format_err!("{}", e)),
};
let oper: Oper<Request> = Oper::new(op, data);
let response = oper.perform(&conn);
Ok(HttpResponse::Ok().json(response?))
}
async fn route<Data, Response>(
op: UserOperation,
info: web::Query<Data>,
db: DbParam,
) -> Result<HttpResponse, Error>
where
Data: Serialize,
Response: Serialize,
Oper<Data>: Perform<Response>,
{
// TODO: want an implementation like this, where useroperation is passed without explicitly passing the other params
// maybe with a higher order functions? (but that would probably have worse performance)
perform::<Data, Response>(op, info.0, db)
}

View file

@ -1,3 +1,4 @@
pub mod api;
pub mod federation; pub mod federation;
pub mod feeds; pub mod feeds;
pub mod index; pub mod index;