[pbs-devel] [PATCH proxmox-backup v2 3/3] examples: add example for a simple rest server with a small api
Thomas Lamprecht
t.lamprecht at proxmox.com
Wed Sep 29 08:41:26 CEST 2021
On 28.09.21 11:11, Dominik Csapak wrote:
> show how to generally start a daemon that serves a rest api + index page
>
> api calls are:
well they are prefixed with `/api2` that's really something that we need to
make configurable, for any future project I definitively do not want to use
the rather confusing /api2 from the start, that can be rather easily adapted
in the client's central HTTP request handling code.
> / GET listing
> /ping GET returns "pong"
> /items GET lists existing items
> POST lets user create new items
> /items/{id} GET returns the content of a single item
> PUT updates an item
> DELETE deletes an item
>
> Contains a small dummy user/authinfo
>
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
> changes from v1:
> * use hyper::server::conn::AddrIncoming::from_listener
>
> proxmox-rest-server/Cargo.toml | 5 +
> proxmox-rest-server/examples/rest_server.rs | 219 ++++++++++++++++++++
> 2 files changed, 224 insertions(+)
> create mode 100644 proxmox-rest-server/examples/rest_server.rs
>
> diff --git a/proxmox-rest-server/Cargo.toml b/proxmox-rest-server/Cargo.toml
> index b0e53d19..a6d25b8b 100644
> --- a/proxmox-rest-server/Cargo.toml
> +++ b/proxmox-rest-server/Cargo.toml
> @@ -5,6 +5,11 @@ authors = ["Proxmox Support Team <support at proxmox.com>"]
> edition = "2018"
> description = "REST server implementation"
>
> +# for example
> +[dev-dependencies]
> +proxmox = { version = "0.13.4", features = ["router","api-macro"] }
0.13.4 is already outdated, do we even need tho have that version target so strict as
else I'd go with "0.13" for now..
> +pbs-runtime = { path = "../pbs-runtime" }
> +
> [dependencies]
> anyhow = "1.0"
> futures = "0.3"
> diff --git a/proxmox-rest-server/examples/rest_server.rs b/proxmox-rest-server/examples/rest_server.rs
> new file mode 100644
> index 00000000..89efbcb2
> --- /dev/null
> +++ b/proxmox-rest-server/examples/rest_server.rs
> @@ -0,0 +1,219 @@
> +use std::sync::{Arc, Mutex};
> +use std::collections::HashMap;
> +
> +use anyhow::{bail, format_err, Error};
> +use futures::{FutureExt, TryFutureExt};
> +use lazy_static::lazy_static;
> +
> +use proxmox::api::{api, router::SubdirMap, Router, RpcEnvironmentType, UserInformation};
> +use proxmox::list_subdirs_api_method;
> +use proxmox_rest_server::{ApiAuth, ApiConfig, AuthError, RestServer};
> +
> +// Create a Dummy User info and auth system
> +// Normally this would check and authenticate the user
> +struct DummyUserInfo;
> +
> +impl UserInformation for DummyUserInfo {
> + fn is_superuser(&self, _userid: &str) -> bool {
> + true
> + }
> + fn is_group_member(&self, _userid: &str, group: &str) -> bool {
> + group == "Group"
> + }
> + fn lookup_privs(&self, _userid: &str, _path: &[&str]) -> u64 {
> + u64::MAX
> + }
> +}
> +
> +struct DummyAuth;
> +
> +impl ApiAuth for DummyAuth {
> + fn check_auth(
> + &self,
> + _headers: &http::HeaderMap,
> + _method: &hyper::Method,
> + ) -> Result<(String, Box<dyn UserInformation + Sync + Send>), AuthError> {
> + // get some global/cached userinfo
> + let userinfo = DummyUserInfo;
> + // Do some user checks, e.g. cookie/csrf
> + Ok(("User".to_string(), Box::new(userinfo)))
> + }
> +}
> +
> +// this should return the index page of the webserver
> +// iow. what the user browses to
above fits in one line even with 80 cc, and in rust we normally go always for 100cc.
> +fn get_index(
> + _auth_id: Option<String>,
> + _language: Option<String>,
> + _api: &ApiConfig,
> + _parts: http::request::Parts,
> +) -> http::Response<hyper::Body> {
> + // build an index page
> + http::Response::builder()
> + .body("hello world".into())
maybe a mini html thingy with the API description from above + links to the GET calls would
be nice to have?
> +async fn run() -> Result<(), Error> {
> +
> + // we first have to configure the api environment (basedir etc.)
> +
> + let config = ApiConfig::new(
> + "/var/tmp/",
> + &ROUTER,
> + RpcEnvironmentType::PUBLIC,
> + Arc::new(DummyAuth {}),
> + get_index,
> + )?;
> + let rest_server = RestServer::new(config);
> +
> + // then we have to create a daemon that listens, accepts and serves
> + // the api to clients
> + proxmox_rest_server::daemon::create_daemon(
> + ([127, 0, 0, 1], 65000).into(),
> + move |listener, ready| {
> + let incoming = hyper::server::conn::AddrIncoming::from_listener(listener)?;
> +
> + Ok(ready
> + .and_then(|_| hyper::Server::builder(incoming)
> + .serve(rest_server)
> + .map_err(Error::from)
> + )
> + .map_err(|err| eprintln!("ERR: {}", err))
> + .map(|test| println!("OK: {}", test.is_ok())))
closing parenthesis jungle ^^
Can you at least place the closing one from Ok() one a new line or does rustfmt does not like that?
> + },
> + "example_server",
> + ).await?;
> +
> + Ok(())
> +}
> +
> +fn main() -> Result<(), Error> {
> + pbs_runtime::main(run())
here I agree with Dietmar, avoiding that dependency would be nice for the example.
> +}
>
More information about the pbs-devel
mailing list