Skip to content

Commit f279bf7

Browse files
committed
Implement a CLI for introspection
1 parent 1b0630e commit f279bf7

File tree

8 files changed

+310
-5
lines changed

8 files changed

+310
-5
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ members = [
1616
".",
1717
"examples/github",
1818
"graphql_query_derive",
19+
"graphql_client_cli",
1920
]

graphql_client_cli/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "graphql_client_cli"
3+
version = "0.1.0"
4+
authors = ["Tom Houlé <[email protected]>"]
5+
6+
[dependencies]
7+
failure = "*"
8+
reqwest = "*"
9+
graphql_client = { path = ".." }
10+
structopt = "*"
11+
serde = "1.0"
12+
serde_derive = "1.0"
13+
serde_json = "1.0"

graphql_client_cli/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://developer.deutschebahn.com/free1bahnql/graphql
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
query IntrospectionQuery {
2+
__schema {
3+
queryType {
4+
name
5+
}
6+
mutationType {
7+
name
8+
}
9+
subscriptionType {
10+
name
11+
}
12+
types {
13+
...FullType
14+
}
15+
directives {
16+
name
17+
description
18+
locations
19+
args {
20+
...InputValue
21+
}
22+
}
23+
}
24+
}
25+
26+
fragment FullType on __Type {
27+
kind
28+
name
29+
description
30+
fields(includeDeprecated: true) {
31+
name
32+
description
33+
args {
34+
...InputValue
35+
}
36+
type {
37+
...TypeRef
38+
}
39+
isDeprecated
40+
deprecationReason
41+
}
42+
inputFields {
43+
...InputValue
44+
}
45+
interfaces {
46+
...TypeRef
47+
}
48+
enumValues(includeDeprecated: true) {
49+
name
50+
description
51+
isDeprecated
52+
deprecationReason
53+
}
54+
possibleTypes {
55+
...TypeRef
56+
}
57+
}
58+
59+
fragment InputValue on __InputValue {
60+
name
61+
description
62+
type {
63+
...TypeRef
64+
}
65+
defaultValue
66+
}
67+
68+
fragment TypeRef on __Type {
69+
kind
70+
name
71+
ofType {
72+
kind
73+
name
74+
ofType {
75+
kind
76+
name
77+
ofType {
78+
kind
79+
name
80+
ofType {
81+
kind
82+
name
83+
ofType {
84+
kind
85+
name
86+
ofType {
87+
kind
88+
name
89+
ofType {
90+
kind
91+
name
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
schema {
2+
query: Query
3+
}
4+
5+
type Query {
6+
__schema: __Schema
7+
}
8+
9+
type __Schema {
10+
types: [__Type!]!
11+
queryType: __Type!
12+
mutationType: __Type
13+
subscriptionType: __Type
14+
directives: [__Directive!]!
15+
}
16+
17+
type __Type {
18+
kind: __TypeKind!
19+
name: String
20+
description: String
21+
22+
# OBJECT and INTERFACE only
23+
fields(includeDeprecated: Boolean = false): [__Field!]
24+
25+
# OBJECT only
26+
interfaces: [__Type!]
27+
28+
# INTERFACE and UNION only
29+
possibleTypes: [__Type!]
30+
31+
# ENUM only
32+
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
33+
34+
# INPUT_OBJECT only
35+
inputFields: [__InputValue!]
36+
37+
# NON_NULL and LIST only
38+
ofType: __Type
39+
}
40+
41+
type __Field {
42+
name: String!
43+
description: String
44+
args: [__InputValue!]!
45+
type: __Type!
46+
isDeprecated: Boolean!
47+
deprecationReason: String
48+
}
49+
50+
type __InputValue {
51+
name: String!
52+
description: String
53+
type: __Type!
54+
defaultValue: String
55+
}
56+
57+
type __EnumValue {
58+
name: String!
59+
description: String
60+
isDeprecated: Boolean!
61+
deprecationReason: String
62+
}
63+
64+
enum __TypeKind {
65+
SCALAR
66+
OBJECT
67+
INTERFACE
68+
UNION
69+
ENUM
70+
INPUT_OBJECT
71+
LIST
72+
NON_NULL
73+
}
74+
75+
type __Directive {
76+
name: String!
77+
description: String
78+
locations: [__DirectiveLocation!]!
79+
args: [__InputValue!]!
80+
}
81+
82+
enum __DirectiveLocation {
83+
QUERY
84+
MUTATION
85+
SUBSCRIPTION
86+
FIELD
87+
FRAGMENT_DEFINITION
88+
FRAGMENT_SPREAD
89+
INLINE_FRAGMENT
90+
SCHEMA
91+
SCALAR
92+
OBJECT
93+
FIELD_DEFINITION
94+
ARGUMENT_DEFINITION
95+
INTERFACE
96+
UNION
97+
ENUM
98+
ENUM_VALUE
99+
INPUT_OBJECT
100+
INPUT_FIELD_DEFINITION
101+
}

graphql_client_cli/src/main.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
extern crate failure;
2+
extern crate reqwest;
3+
#[macro_use]
4+
extern crate structopt;
5+
#[macro_use]
6+
extern crate graphql_client;
7+
#[macro_use]
8+
extern crate serde_derive;
9+
extern crate serde;
10+
extern crate serde_json;
11+
12+
use std::path::PathBuf;
13+
use structopt::StructOpt;
14+
15+
const INTROSPECTION_QUERY: &'static str = include_str!("introspection_query.graphql");
16+
17+
#[derive(GraphQLQuery)]
18+
#[GraphQLQuery(
19+
schema_path = "src/introspection_schema.graphql", query_path = "src/introspection_query.graphql"
20+
)]
21+
struct IntrospectionQuery;
22+
23+
#[derive(StructOpt)]
24+
enum Cli {
25+
#[structopt(name = "introspect-schema")]
26+
IntrospectSchema {
27+
/// The URL of a GraphQL endpoint to introspect.
28+
schema_location: String,
29+
/// Where to write the JSON for the introspected schema.
30+
#[structopt(parse(from_os_str))]
31+
#[structopt(long = "output")]
32+
output: Option<PathBuf>,
33+
},
34+
#[structopt(name = "generate")]
35+
Generate {
36+
// should be a glob
37+
paths: String,
38+
#[structopt(parse(from_os_str))]
39+
schema: PathBuf,
40+
#[structopt(parse(from_os_str))]
41+
output: PathBuf,
42+
},
43+
}
44+
45+
fn main() -> Result<(), failure::Error> {
46+
let cli = Cli::from_args();
47+
match cli {
48+
Cli::IntrospectSchema {
49+
schema_location,
50+
output,
51+
} => introspect_schema(schema_location, output),
52+
Cli::Generate {
53+
paths: _,
54+
schema: _,
55+
output: _,
56+
} => unimplemented!(),
57+
}
58+
}
59+
60+
fn introspect_schema(location: String, output: Option<PathBuf>) -> Result<(), failure::Error> {
61+
use reqwest::header::*;
62+
use reqwest::mime;
63+
64+
// let dest_file = ::std::fs::File::open(&output)?;
65+
66+
let request_body: graphql_client::GraphQLQueryBody<()> = graphql_client::GraphQLQueryBody {
67+
variables: (),
68+
query: INTROSPECTION_QUERY,
69+
};
70+
71+
let client = reqwest::Client::new();
72+
let mut res = client
73+
.post(&location)
74+
.header(Accept(vec![qitem(mime::APPLICATION_JSON)]))
75+
.json(&request_body)
76+
.send()?;
77+
78+
if res.status().is_success() {
79+
} else if res.status().is_server_error() {
80+
println!("server error!");
81+
} else {
82+
println!("Something else happened. Status: {:?}", res.status());
83+
}
84+
85+
let json: graphql_client::GraphQLResponse<introspection_query::ResponseData> = res.json()?;
86+
87+
println!("{:?}", json);
88+
89+
Ok(())
90+
}

graphql_query_derive/src/enums.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,18 @@ impl GqlEnum {
3434
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
3535
ser.serialize_str(match *self {
3636
#(#constructors => #variant_str,)*
37-
#name::Other(ref s) => s.as_str(),
37+
#name::Other(ref s) => &s,
3838
})
3939
}
4040
}
4141

4242
impl<'de> ::serde::Deserialize<'de> for #name {
4343
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
44-
let s = <&'de str>::deserialize(deserializer)?;
44+
let s = <String>::deserialize(deserializer)?;
4545

46-
match s {
46+
match s.as_str() {
4747
#(#variant_str => Ok(#constructors),)*
48-
_ => Ok(#name::Other(s.to_string())),
48+
_ => Ok(#name::Other(s)),
4949
}
5050
}
5151
}

graphql_query_derive/src/schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl Schema {
163163

164164
#variables_struct
165165

166-
#[derive(Deserialize)]
166+
#[derive(Debug, Deserialize)]
167167
pub struct ResponseData {
168168
#(#response_data_fields)*,
169169
}

0 commit comments

Comments
 (0)