router_bridge/
api_schema.rs

1/*!
2# Generate an API schema from an sdl.
3*/
4
5use crate::error::Error;
6use crate::js::Js;
7use serde::{Deserialize, Serialize};
8use std::fmt::Display;
9use thiserror::Error;
10
11/// An error which occurred during JavaScript api schema generation.
12///
13/// The shape of this error is meant to mimick that of the error created within
14/// JavaScript, which is a [`GraphQLError`] from the [`graphql-js`] library.
15///
16/// [`graphql-js']: https://npm.im/graphql
17/// [`GraphQLError`]: https://github.com/graphql/graphql-js/blob/3869211/src/error/GraphQLError.js#L18-L75
18#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq, Clone)]
19pub struct ApiSchemaError {
20    /// A human-readable description of the error that prevented api schema generation.
21    pub message: Option<String>,
22}
23
24impl Display for ApiSchemaError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.write_str(self.message.as_deref().unwrap_or("UNKNOWN"))
27    }
28}
29
30/// Options for generating the API schema.
31#[derive(Debug, Serialize, Deserialize, Clone)]
32pub struct ApiSchemaOptions {
33    /// Whether to validate the GraphQL input string.
34    pub graphql_validation: bool,
35}
36
37/// The type returned when invoking `api_schema`
38pub type ApiSchemaResult = Result<String, Vec<ApiSchemaError>>;
39
40/// The `api_schema` function receives a [`string`] representing the SDL and invokes JavaScript
41/// functions to parse, convert to apiSchema and print to string.
42pub fn api_schema(sdl: &str, options: ApiSchemaOptions) -> Result<ApiSchemaResult, Error> {
43    Js::new("api_schema".to_string())
44        .with_parameter("sdl", sdl)?
45        .with_parameter("graphqlValidation", options.graphql_validation)?
46        .execute::<ApiSchemaResult>("do_api_schema", include_str!("../bundled/do_api_schema.js"))
47}
48
49#[cfg(test)]
50mod tests {
51    use crate::api_schema::{api_schema, ApiSchemaError, ApiSchemaOptions};
52
53    #[test]
54    fn it_works() {
55        let raw_sdl = include_str!("testdata/contract_schema.graphql");
56
57        let api_schema = api_schema(
58            raw_sdl,
59            ApiSchemaOptions {
60                graphql_validation: true,
61            },
62        )
63        .unwrap();
64        insta::assert_snapshot!(&api_schema.unwrap());
65    }
66
67    #[test]
68    fn invalid_sdl() {
69        let expected_error = ApiSchemaError {
70            message: Some(r#"Unknown type "Query"."#.to_string()),
71        };
72        let response = api_schema(
73            "schema {
74                query: Query
75            }",
76            ApiSchemaOptions {
77                graphql_validation: true,
78            },
79        )
80        .expect("an uncaught deno error occured");
81
82        assert_eq!(response.err().unwrap(), vec![expected_error]);
83    }
84}