Skip to content

Commit

Permalink
implement printSchemaAndCapabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
BenoitRanque committed Sep 25, 2024
1 parent 927c347 commit bbed3bd
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix bug where introspection including interfaces would fail to parse in some circumstances
- Config now defaults to asking for a `GRAPHQL_ENDPOINT` env var
- Fix a bug where default values were not parsed as graphql values, and instead used as string literals
- CLI: Implement `print-schema-and-capabilities` command, allowing local dev to update config & schema without starting a connector instance

## [0.1.3]

Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ci/templates/connector-metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ supportedEnvironmentVariables:
required: true
commands:
update: hasura-ndc-graphql update
printSchemaAndCapabilities: hasura-ndc-graphql print-schema-and-capabilities
cliPlugin:
name: ndc-graphql
version: "${CLI_VERSION}"
Expand Down
5 changes: 5 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ version.workspace = true
edition.workspace = true

[dependencies]
async-trait = "0.1.78"
glob-match = "0.2.1"
graphql_client = "0.14.0"
graphql-parser = "0.4.0"
ndc-sdk = { git = "https://github.com/hasura/ndc-sdk-rs", tag = "v0.1.5", package = "ndc-sdk", features = [
"rustls",
], default-features = false }
reqwest = { version = "0.12.3", features = [
"json",
"rustls-tls",
], default-features = false }
schemars = "0.8.16"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
tokio = "1.36.0"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ndc_sdk::models;

pub fn capabilities() -> models::CapabilitiesResponse {
pub fn capabilities_response() -> models::CapabilitiesResponse {
models::CapabilitiesResponse {
version: "0.1.4".to_string(),
capabilities: models::Capabilities {
Expand Down
9 changes: 4 additions & 5 deletions crates/common/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use config_file::{RequestConfigFile, ResponseConfigFile};
use schema::SchemaDefinition;
use std::collections::BTreeMap;

use crate::{
config_file::{RequestConfigFile, ResponseConfigFile},
schema::SchemaDefinition,
};
pub mod config_file;
pub mod schema;

#[derive(Debug, Clone)]
pub struct ServerConfig {
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod capabilities_response;
pub mod client;
pub mod config;
pub mod config_file;
pub mod schema;
pub mod schema_response;
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
use common::{
config::ServerConfig,
use crate::config::{
schema::{
InputObjectFieldDefinition, ObjectFieldArgumentDefinition, ObjectFieldDefinition, TypeRef,
InputObjectFieldDefinition, ObjectFieldArgumentDefinition, ObjectFieldDefinition,
SchemaDefinition, TypeDef, TypeRef,
},
RequestConfig, ResponseConfig,
};
use ndc_sdk::models;
use std::{collections::BTreeMap, iter};

pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
let forward_request_headers = !configuration.request.forward_headers.is_empty();
let forward_response_headers = !configuration.response.forward_headers.is_empty();
pub fn schema_response(
schema: &SchemaDefinition,
request: &RequestConfig,
response: &ResponseConfig,
) -> models::SchemaResponse {
let forward_request_headers = !request.forward_headers.is_empty();
let forward_response_headers = !response.forward_headers.is_empty();

let mut scalar_types: BTreeMap<_, _> = configuration
.schema
let mut scalar_types: BTreeMap<_, _> = schema
.definitions
.iter()
.filter_map(|(name, typedef)| match typedef {
common::schema::TypeDef::Object { .. }
| common::schema::TypeDef::InputObject { .. } => None,
common::schema::TypeDef::Scalar { description: _ } => Some((
TypeDef::Object { .. } | TypeDef::InputObject { .. } => None,
TypeDef::Scalar { description: _ } => Some((
name.to_owned(),
models::ScalarType {
representation: None,
aggregate_functions: BTreeMap::new(),
comparison_operators: BTreeMap::new(),
},
)),
common::schema::TypeDef::Enum {
TypeDef::Enum {
values,
description: _,
} => Some((
Expand All @@ -44,7 +47,7 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {

if forward_request_headers {
scalar_types.insert(
configuration.request.headers_type_name.to_owned(),
request.headers_type_name.to_owned(),
models::ScalarType {
representation: Some(models::TypeRepresentation::JSON),
aggregate_functions: BTreeMap::new(),
Expand All @@ -53,13 +56,12 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
);
}

let mut object_types: BTreeMap<_, _> = configuration
.schema
let mut object_types: BTreeMap<_, _> = schema
.definitions
.iter()
.filter_map(|(name, typedef)| match typedef {
common::schema::TypeDef::Scalar { .. } | common::schema::TypeDef::Enum { .. } => None,
common::schema::TypeDef::Object {
TypeDef::Scalar { .. } | TypeDef::Enum { .. } => None,
TypeDef::Object {
fields,
description,
} => Some((
Expand All @@ -69,7 +71,7 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
fields: fields.iter().map(map_object_field).collect(),
},
)),
common::schema::TypeDef::InputObject {
TypeDef::InputObject {
fields,
description,
} => Some((
Expand All @@ -90,17 +92,17 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
)),
fields: BTreeMap::from_iter(vec![
(
configuration.response.headers_field.to_owned(),
response.headers_field.to_owned(),
models::ObjectField {
description: None,
r#type: models::Type::Named {
name: configuration.request.headers_type_name.to_owned(),
name: request.headers_type_name.to_owned(),
},
arguments: BTreeMap::new(),
},
),
(
configuration.response.response_field.to_owned(),
response.response_field.to_owned(),
models::ObjectField {
description: None,
r#type: typeref_to_ndc_type(&field.r#type),
Expand All @@ -113,16 +115,16 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {

let mut functions = vec![];

for (name, field) in &configuration.schema.query_fields {
for (name, field) in &schema.query_fields {
let arguments = field.arguments.iter().map(map_argument);
let arguments = if forward_request_headers {
arguments
.chain(iter::once((
configuration.request.headers_argument.to_owned(),
request.headers_argument.to_owned(),
models::ArgumentInfo {
description: None,
argument_type: models::Type::Named {
name: configuration.request.headers_type_name.to_owned(),
name: request.headers_type_name.to_owned(),
},
},
)))
Expand All @@ -132,7 +134,7 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
};

let result_type = if forward_response_headers {
let response_type_name = configuration.response.query_response_type_name(name);
let response_type_name = response.query_response_type_name(name);

object_types.insert(
response_type_name.clone(),
Expand All @@ -156,16 +158,16 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {

let mut procedures = vec![];

for (name, field) in &configuration.schema.mutation_fields {
for (name, field) in &schema.mutation_fields {
let arguments = field.arguments.iter().map(map_argument);
let arguments = if forward_request_headers {
arguments
.chain(iter::once((
configuration.request.headers_argument.to_owned(),
request.headers_argument.to_owned(),
models::ArgumentInfo {
description: None,
argument_type: models::Type::Named {
name: configuration.request.headers_type_name.to_owned(),
name: request.headers_type_name.to_owned(),
},
},
)))
Expand All @@ -175,7 +177,7 @@ pub fn schema_response(configuration: &ServerConfig) -> models::SchemaResponse {
};

let result_type = if forward_response_headers {
let response_type_name = configuration.response.mutation_response_type_name(name);
let response_type_name = response.mutation_response_type_name(name);

object_types.insert(
response_type_name.clone(),
Expand Down
3 changes: 3 additions & 0 deletions crates/ndc-graphql-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ common = { path = "../common" }
graphql_client = "0.14.0"
graphql-introspection-query = "0.2.0"
graphql-parser = "0.4.0"
ndc-sdk = { git = "https://github.com/hasura/ndc-sdk-rs", tag = "v0.1.5", package = "ndc-sdk", features = [
"rustls",
], default-features = false }
schemars = "0.8.16"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
Expand Down
47 changes: 43 additions & 4 deletions crates/ndc-graphql-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
use clap::{Parser, Subcommand, ValueEnum};
use common::{
config::ConnectionConfig,
config_file::{
ConfigValue, ServerConfigFile, CONFIG_FILE_NAME, CONFIG_SCHEMA_FILE_NAME, SCHEMA_FILE_NAME,
capabilities_response::capabilities_response,
config::{
config_file::{
ConfigValue, ServerConfigFile, CONFIG_FILE_NAME, CONFIG_SCHEMA_FILE_NAME,
SCHEMA_FILE_NAME,
},
schema::SchemaDefinition,
ConnectionConfig,
},
schema::SchemaDefinition,
schema_response::schema_response,
};
use graphql::{execute_graphql_introspection, schema_from_introspection};
use graphql_parser::schema;
use ndc_graphql_cli::graphql;
use ndc_sdk::models;
use schemars::schema_for;
use serde::Serialize;
use std::{
env,
error::Error,
Expand Down Expand Up @@ -64,6 +71,7 @@ enum Command {
Update {},
Validate {},
Watch {},
PrintSchemaAndCapabilities {},
}

#[derive(Clone, ValueEnum)]
Expand All @@ -77,6 +85,12 @@ enum LogLevel {
Trace,
}

#[derive(Serialize)]
struct SchemaAndCapabilities {
schema: models::SchemaResponse,
capabilities: models::CapabilitiesResponse,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let args = CliArgs::parse();
Expand Down Expand Up @@ -110,6 +124,31 @@ async fn main() -> Result<(), Box<dyn Error>> {
Command::Watch {} => {
todo!("implement watch command")
}
Command::PrintSchemaAndCapabilities {} => {
let config_file = read_config_file(&context_path)
.await?
.ok_or_else(|| format!("Could not find {CONFIG_FILE_NAME}"))?;
let schema_document = read_schema_file(&context_path)
.await?
.ok_or_else(|| format!("Could not find {SCHEMA_FILE_NAME}"))?;

let request_config = config_file.request.into();
let response_config = config_file.response.into();

let schema =
SchemaDefinition::new(&schema_document, &request_config, &response_config)?;

let schema_and_capabilities = SchemaAndCapabilities {
schema: schema_response(&schema, &request_config, &response_config),
capabilities: capabilities_response(),
};

println!(
"{}",
serde_json::to_string(&schema_and_capabilities)
.expect("Schema and capabilities should serialize to JSON")
)
}
}

Ok(())
Expand Down
13 changes: 8 additions & 5 deletions crates/ndc-graphql/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use self::state::ServerState;
use crate::query_builder::{build_mutation_document, build_query_document};
use async_trait::async_trait;
use common::{
capabilities_response::capabilities_response,
client::{execute_graphql, GraphQLRequest},
config::ServerConfig,
schema_response::schema_response,
};
use indexmap::IndexMap;
use ndc_sdk::{
Expand All @@ -14,11 +16,8 @@ use ndc_sdk::{
json_response::JsonResponse,
models,
};
use schema::schema_response;
use std::{collections::BTreeMap, mem};
use tracing::{Instrument, Level};
pub mod capabilities;
pub mod schema;
pub mod setup;
mod state;

Expand All @@ -45,13 +44,17 @@ impl Connector for GraphQLConnector {
}

async fn get_capabilities() -> JsonResponse<models::CapabilitiesResponse> {
JsonResponse::Value(capabilities::capabilities())
JsonResponse::Value(capabilities_response())
}

async fn get_schema(
configuration: &Self::Configuration,
) -> Result<JsonResponse<models::SchemaResponse>, SchemaError> {
Ok(JsonResponse::Value(schema_response(configuration)))
Ok(JsonResponse::Value(schema_response(
&configuration.schema,
&configuration.request,
&configuration.response,
)))
}

async fn query_explain(
Expand Down
4 changes: 2 additions & 2 deletions crates/ndc-graphql/src/connector/setup.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::{state::ServerState, GraphQLConnector};
use async_trait::async_trait;
use common::{
config::{ConnectionConfig, ServerConfig},
use common::config::{
config_file::{ConfigValue, ServerConfigFile, CONFIG_FILE_NAME, SCHEMA_FILE_NAME},
schema::SchemaDefinition,
ConnectionConfig, ServerConfig,
};
use graphql_parser::parse_schema;
use ndc_sdk::connector::{
Expand Down
Loading

0 comments on commit bbed3bd

Please sign in to comment.