cli: introduce the export_graphql_schema command

Split the command line into subcommands `run` and
`export_graphql_schema`.
This commit is contained in:
Valentin Tolmer 2021-08-26 21:46:00 +02:00 committed by nitnelave
parent d2617e08a7
commit a08b9a556d
6 changed files with 103 additions and 8 deletions

View File

@ -21,6 +21,11 @@ jobs:
run: cargo build --verbose --workspace run: cargo build --verbose --workspace
- name: Run tests - name: Run tests
run: cargo test --verbose --workspace run: cargo test --verbose --workspace
- name: Generate GraphQL schema
run: cargo run -- export_graphql_schema -o generated_schema.graphql
- name: Check schema
run: diff schema.graphql generated_schema.graphql
clippy: clippy:
name: cargo clippy name: cargo clippy

38
schema.graphql Normal file
View File

@ -0,0 +1,38 @@
input EqualityConstraint {
field: String!
value: String!
}
type Group {
id: String!
"The groups to which this user belongs."
users: [User!]!
}
"""
A filter for requests, specifying a boolean expression based on field constraints. Only one of
the fields can be set at a time.
"""
input RequestFilter {
any: [RequestFilter!]
all: [RequestFilter!]
not: RequestFilter
eq: EqualityConstraint
}
type Query {
apiVersion: String!
user(userId: String!): User!
users(filters: RequestFilter): [User!]!
}
type User {
id: String!
email: String!
"The groups to which this user belongs."
groups: [Group!]!
}
schema {
query: Query
}

View File

@ -4,6 +4,23 @@ use clap::Clap;
#[derive(Debug, Clap, Clone)] #[derive(Debug, Clap, Clone)]
#[clap(version = "0.1", author = "The LLDAP team")] #[clap(version = "0.1", author = "The LLDAP team")]
pub struct CLIOpts { pub struct CLIOpts {
/// Export
#[clap(subcommand)]
pub command: Command,
}
#[derive(Debug, Clap, Clone)]
pub enum Command {
/// Export the GraphQL schema to *.graphql.
#[clap(name = "export_graphql_schema")]
ExportGraphQLSchema(ExportGraphQLSchemaOpts),
/// Run the LDAP and GraphQL server.
#[clap(name = "run")]
Run(RunOpts),
}
#[derive(Debug, Clap, Clone)]
pub struct RunOpts {
/// Change config file name /// Change config file name
#[clap(short, long, default_value = "lldap_config.toml")] #[clap(short, long, default_value = "lldap_config.toml")]
pub config_file: String, pub config_file: String,
@ -21,6 +38,13 @@ pub struct CLIOpts {
pub verbose: bool, pub verbose: bool,
} }
#[derive(Debug, Clap, Clone)]
pub struct ExportGraphQLSchemaOpts {
/// Output to a file. If not specified, the config is printed to the standard output.
#[clap(short, long)]
pub output_file: Option<String>,
}
pub fn init() -> CLIOpts { pub fn init() -> CLIOpts {
CLIOpts::parse() CLIOpts::parse()
} }

View File

@ -6,7 +6,7 @@ use figment::{
use lldap_model::opaque::{server::ServerSetup, KeyPair}; use lldap_model::opaque::{server::ServerSetup, KeyPair};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::infra::cli::CLIOpts; use crate::infra::cli::RunOpts;
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)] #[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
#[builder( #[builder(
@ -55,7 +55,7 @@ impl Configuration {
self.get_server_setup().keypair() self.get_server_setup().keypair()
} }
fn merge_with_cli(mut self: Configuration, cli_opts: CLIOpts) -> Configuration { fn merge_with_cli(mut self: Configuration, cli_opts: RunOpts) -> Configuration {
if cli_opts.verbose { if cli_opts.verbose {
self.verbose = true; self.verbose = true;
} }
@ -110,7 +110,7 @@ fn get_server_setup(file_path: &str) -> Result<ServerSetup> {
} }
} }
pub fn init(cli_opts: CLIOpts) -> Result<Configuration> { pub fn init(cli_opts: RunOpts) -> Result<Configuration> {
let config_file = cli_opts.config_file.clone(); let config_file = cli_opts.config_file.clone();
let config: Configuration = Figment::from(Serialized::defaults(Configuration::default())) let config: Configuration = Figment::from(Serialized::defaults(Configuration::default()))

View File

@ -2,6 +2,7 @@ use crate::{
domain::handler::BackendHandler, domain::handler::BackendHandler,
infra::{ infra::{
auth_service::{check_if_token_is_valid, ValidationResults}, auth_service::{check_if_token_is_valid, ValidationResults},
cli::ExportGraphQLSchemaOpts,
tcp_server::AppState, tcp_server::AppState,
}, },
}; };
@ -34,6 +35,26 @@ fn schema<Handler: BackendHandler + Sync>() -> Schema<Handler> {
) )
} }
pub fn export_schema(opts: ExportGraphQLSchemaOpts) -> anyhow::Result<()> {
use crate::domain::sql_backend_handler::SqlBackendHandler;
use anyhow::Context;
let output = schema::<SqlBackendHandler>().as_schema_language();
match opts.output_file {
None => println!("{}", output),
Some(path) => {
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
let path = Path::new(&path);
let mut file =
File::create(&path).context(format!("unable to open '{}'", path.display()))?;
file.write_all(output.as_bytes())
.context(format!("unable to write in '{}'", path.display()))?;
}
}
Ok(())
}
async fn graphiql_route() -> Result<HttpResponse, Error> { async fn graphiql_route() -> Result<HttpResponse, Error> {
graphiql_handler("/api/graphql", None).await graphiql_handler("/api/graphql", None).await
} }

View File

@ -6,7 +6,7 @@ use crate::{
handler::BackendHandler, sql_backend_handler::SqlBackendHandler, handler::BackendHandler, sql_backend_handler::SqlBackendHandler,
sql_opaque_handler::register_password, sql_tables::PoolOptions, sql_opaque_handler::register_password, sql_tables::PoolOptions,
}, },
infra::{configuration::Configuration, db_cleaner::Scheduler}, infra::{cli::*, configuration::Configuration, db_cleaner::Scheduler},
}; };
use actix::Actor; use actix::Actor;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
@ -65,14 +65,13 @@ async fn run_server(config: Configuration) -> Result<()> {
Ok(()) Ok(())
} }
fn main() -> Result<()> { fn run_server_command(opts: RunOpts) -> Result<()> {
let cli_opts = infra::cli::init(); let config = infra::configuration::init(opts.clone())?;
let config = infra::configuration::init(cli_opts.clone())?;
infra::logging::init(config.clone())?; infra::logging::init(config.clone())?;
info!("Starting LLDAP...."); info!("Starting LLDAP....");
debug!("CLI: {:#?}", cli_opts); debug!("CLI: {:#?}", opts);
debug!("Configuration: {:#?}", config); debug!("Configuration: {:#?}", config);
actix::run( actix::run(
@ -82,3 +81,11 @@ fn main() -> Result<()> {
info!("End."); info!("End.");
Ok(()) Ok(())
} }
fn main() -> Result<()> {
let cli_opts = infra::cli::init();
match cli_opts.command {
Command::ExportGraphQLSchema(opts) => infra::graphql::api::export_schema(opts),
Command::Run(opts) => run_server_command(opts),
}
}