1use crate::KnownError;
2use itertools::Itertools;
3use serde::Serialize;
4use serde_json::json;
5use std::{borrow::Cow, error, fmt};
6
7#[derive(Debug, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct ValidationError {
12 kind: ValidationErrorKind,
13 #[serde(skip)]
14 message: String,
15 #[serde(flatten)]
16 meta: Option<serde_json::Value>,
17}
18
19impl ValidationError {
20 pub fn kind(&self) -> &ValidationErrorKind {
21 &self.kind
22 }
23
24 pub fn message(&self) -> &str {
25 &self.message
26 }
27}
28
29impl fmt::Display for ValidationError {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.write_str(&self.message)
32 }
33}
34
35#[derive(Debug, Serialize)]
36pub enum ValidationErrorKind {
37 UnexpectedRuntimeError,
39 EmptySelection,
41 InvalidArgumentType,
43 InvalidArgumentValue,
45 SomeFieldsMissing,
47 TooManyFieldsGiven,
49 SelectionSetOnScalar,
51 RequiredArgumentMissing,
54 Union,
56 UnknownArgument,
58 UnknownInputField,
60 UnknownSelectionField,
62 ValueTooLarge,
64}
65
66impl ValidationErrorKind {
67 pub fn code(&self) -> &'static str {
76 match self {
77 ValidationErrorKind::RequiredArgumentMissing => "P2012",
78 _ => "P2009",
79 }
80 }
81}
82
83impl From<ValidationError> for crate::KnownError {
84 fn from(err: ValidationError) -> Self {
85 KnownError {
86 message: err.message.clone(),
87 meta: serde_json::to_value(&err).expect("Failed to render validation error to JSON"),
88 error_code: Cow::from(err.kind.code()),
89 }
90 }
91}
92
93impl From<ValidationError> for crate::Error {
94 fn from(err: ValidationError) -> Self {
95 KnownError::from(err).into()
96 }
97}
98
99impl ValidationError {
100 pub fn unexpected_runtime_error(message: String) -> Self {
103 ValidationError {
104 kind: ValidationErrorKind::UnexpectedRuntimeError,
105 message,
106 meta: None,
107 }
108 }
109
110 pub fn empty_selection(selection_path: Vec<&str>, output_type_description: OutputTypeDescription) -> Self {
123 let message = String::from("Expected a minimum of 1 field to be present, got 0");
124 ValidationError {
125 kind: ValidationErrorKind::EmptySelection,
126 message,
127 meta: Some(json!({ "outputType": output_type_description, "selectionPath": selection_path })),
128 }
129 }
130
131 pub fn invalid_argument_type(
153 selection_path: Vec<&str>,
154 argument_path: Vec<&str>,
155 argument_description: ArgumentDescription<'_>,
156 inferred_argument_type: String,
157 ) -> Self {
158 let message = format!(
159 "Invalid argument type. `{}` should be of any of the following types: `{}`",
160 argument_description.name,
161 argument_description.type_names.join(", ")
162 );
163 ValidationError {
164 kind: ValidationErrorKind::InvalidArgumentType,
165 message,
166 meta: Some(
167 json!({"argumentPath": argument_path, "argument": argument_description, "selectionPath": selection_path, "inferredType": inferred_argument_type }),
168 ),
169 }
170 }
171
172 pub fn invalid_argument_value(
196 selection_path: Vec<&str>,
197 argument_path: Vec<&str>,
198 value: String,
199 expected_argument_type: &str,
200 underlying_err: Option<Box<dyn error::Error>>,
201 ) -> Self {
202 let argument_name = argument_path.last().expect("Argument path cannot not be empty");
203 let (message, meta) = if let Some(err) = underlying_err {
204 let err_msg = err.to_string();
205 let message = format!(
206 "Invalid argument agument value. `{}` is not a valid `{}`. Underlying error: {}",
207 value, expected_argument_type, &err_msg
208 );
209 let argument = ArgumentDescription::new(*argument_name, vec![Cow::Borrowed(expected_argument_type)]);
210 let meta = json!({"argumentPath": argument_path, "argument": argument, "selectionPath": selection_path, "underlyingError": &err_msg});
211 (message, Some(meta))
212 } else {
213 let message = format!(
214 "Invalid argument agument value. `{}` is not a valid `{}`",
215 value, &expected_argument_type
216 );
217 let argument = ArgumentDescription::new(*argument_name, vec![Cow::Borrowed(expected_argument_type)]);
218 let meta = json!({"argumentPath": argument_path, "argument": argument, "selectionPath": selection_path, "underlyingError": serde_json::Value::Null});
219 (message, Some(meta))
220 };
221 ValidationError {
222 kind: ValidationErrorKind::InvalidArgumentValue,
223 message,
224 meta,
225 }
226 }
227
228 pub fn some_fields_missing(
231 selection_path: Vec<&str>,
232 argument_path: Vec<&str>,
233 min_field_count: Option<usize>,
234 max_field_count: Option<usize>,
235 required_fields: Option<Vec<Cow<'_, str>>>,
236 provided_field_count: usize,
237 input_type_description: &InputTypeDescription,
238 ) -> Self {
239 let constraints =
240 InputTypeConstraints::new(min_field_count, max_field_count, required_fields, provided_field_count);
241 let message = format!("Some fields are missing: {constraints}");
242 ValidationError {
243 kind: ValidationErrorKind::SomeFieldsMissing,
244 message,
245 meta: Some(
246 json!({ "inputType": input_type_description, "argumentPath": argument_path, "selectionPath": selection_path, "constraints": constraints }),
247 ),
248 }
249 }
250
251 pub fn too_many_fields_given(
254 selection_path: Vec<&str>,
255 argument_path: Vec<&str>,
256 min_field_count: Option<usize>,
257 max_field_count: Option<usize>,
258 required_fields: Option<Vec<Cow<'_, str>>>,
259 provided_field_count: usize,
260 input_type_description: &InputTypeDescription,
261 ) -> Self {
262 let constraints =
263 InputTypeConstraints::new(min_field_count, max_field_count, required_fields, provided_field_count);
264 let message = format!("Too many fields given: {constraints}");
265 ValidationError {
266 kind: ValidationErrorKind::TooManyFieldsGiven,
267 message,
268 meta: Some(
269 json!({ "inputType": input_type_description, "argumentPath": argument_path, "selectionPath": selection_path, "constraints": constraints }),
270 ),
271 }
272 }
273
274 pub fn required_argument_missing(
288 selection_path: Vec<&str>,
289 argument_path: Vec<&str>,
290 input_type_descriptions: &[InputTypeDescription],
291 ) -> Self {
292 let message = format!("`{}`: A value is required but not set", argument_path.join("."));
293 ValidationError {
294 kind: ValidationErrorKind::RequiredArgumentMissing,
295 message,
296 meta: Some(
297 json!({ "inputTypes": input_type_descriptions, "argumentPath": argument_path, "selectionPath": selection_path }),
298 ),
299 }
300 }
301
302 pub fn conditionally_required_argument_missing(
323 selection_path: &[&str],
324 argument_path: &[&str],
325 dependent_argument_path: &[&str],
326 input_type_descriptions: &[InputTypeDescription],
327 ) -> Self {
328 let message = format!(
329 "`{}`: A value is required but not set. It is required because `{}` was provided.",
330 argument_path.join("."),
331 dependent_argument_path.join(".")
332 );
333 ValidationError {
334 kind: ValidationErrorKind::RequiredArgumentMissing,
335 message,
336 meta: Some(json!({
337 "inputTypes": input_type_descriptions,
338 "argumentPath": argument_path,
339 "dependentArgumentPath": dependent_argument_path,
340 "selectionPath": selection_path,
341 })),
342 }
343 }
344
345 pub fn unknown_argument(
364 selection_path: Vec<&str>,
365 argument_path: Vec<&str>,
366 valid_argument_descriptions: Vec<ArgumentDescription<'_>>,
367 ) -> Self {
368 let message = String::from("Argument does not exist in enclosing type");
369 ValidationError {
370 kind: ValidationErrorKind::UnknownArgument,
371 message,
372 meta: Some(
373 json!({"argumentPath": argument_path, "arguments": valid_argument_descriptions, "selectionPath": selection_path}),
374 ),
375 }
376 }
377
378 pub fn unknown_input_field(
407 selection_path: Vec<&str>,
408 argument_path: Vec<&str>,
409 input_type_description: InputTypeDescription,
410 ) -> Self {
411 let message = format!(
412 "`{}.{}`: Field does not exist in enclosing type.",
413 selection_path.join("."),
414 argument_path.join("."),
415 );
416 ValidationError {
417 kind: ValidationErrorKind::UnknownInputField,
418 message,
419 meta: Some(
420 json!({ "inputType": input_type_description, "argumentPath": argument_path, "selectionPath": selection_path }),
421 ),
422 }
423 }
424
425 pub fn unknown_selection_field(selection_path: Vec<&str>, output_type_description: OutputTypeDescription) -> Self {
441 let message = format!(
442 "Field '{}' not found in enclosing type '{}'",
443 selection_path.last().expect("Selection path must not be empty"),
444 output_type_description.name
445 );
446 ValidationError {
447 kind: ValidationErrorKind::UnknownSelectionField,
448 message,
449 meta: Some(json!({ "outputType": output_type_description, "selectionPath": selection_path })),
450 }
451 }
452
453 pub fn selection_set_on_scalar(field_name: String, selection_path: Vec<&str>) -> Self {
472 let message = format!("Cannot select over scalar field '{}'", &field_name);
473 ValidationError {
474 kind: ValidationErrorKind::SelectionSetOnScalar,
475 message,
476 meta: Some(json!({ "fieldName": field_name, "selectionPath": selection_path })),
477 }
478 }
479
480 pub fn union(errors: Vec<ValidationError>) -> Self {
482 let message = format!(
483 "Unable to match input value to any allowed input type for the field. Parse errors: [{}]",
484 errors.iter().map(|err| format!("{err}")).collect::<Vec<_>>().join(", ")
485 );
486 ValidationError {
487 message,
488 kind: ValidationErrorKind::Union,
489 meta: Some(json!({ "errors": errors })),
490 }
491 }
492
493 pub fn value_too_large(selection_path: Vec<&str>, argument_path: Vec<&str>, value: String) -> Self {
515 let argument_name = argument_path.last().expect("Argument path cannot not be empty");
516 let message = format!(
517 "Unable to fit float value (or large JS integer serialized in exponent notation) '{value}' into a 64 Bit signed integer for field '{argument_name}'. If you're trying to store large integers, consider using `BigInt`",
518 );
519 let argument = ArgumentDescription::new(*argument_name, vec![Cow::Borrowed("BigInt")]);
520 ValidationError {
521 kind: ValidationErrorKind::ValueTooLarge,
522 message,
523 meta: Some(json!({"argumentPath": argument_path, "argument": argument, "selectionPath": selection_path})),
524 }
525 }
526}
527
528impl std::error::Error for ValidationError {}
529
530#[derive(Debug, Serialize)]
531#[serde(rename_all = "camelCase")]
532pub struct OutputTypeDescription {
533 name: String,
534 fields: Vec<OutputTypeDescriptionField>,
535}
536
537impl OutputTypeDescription {
538 pub fn new(name: String, fields: Vec<OutputTypeDescriptionField>) -> Self {
539 OutputTypeDescription { name, fields }
540 }
541}
542
543#[derive(Debug, Serialize)]
544#[serde(rename_all = "camelCase")]
545pub struct OutputTypeDescriptionField {
546 name: String,
547 type_name: String,
548 is_relation: bool,
549}
550
551impl OutputTypeDescriptionField {
552 pub fn new(name: String, type_name: String, is_relation: bool) -> Self {
553 Self {
554 name,
555 type_name,
556 is_relation,
557 }
558 }
559}
560#[derive(Debug, Serialize, Clone)]
561#[serde(tag = "kind", rename_all = "camelCase", rename_all_fields = "camelCase")]
562pub enum InputTypeDescription {
563 Object {
564 name: String,
565 fields: Vec<InputTypeDescriptionField>,
566 },
567 Scalar {
568 name: String,
569 },
570 List {
571 element_type: Box<InputTypeDescription>,
572 },
573 Enum {
574 name: String,
575 },
576}
577
578impl InputTypeDescription {
579 pub fn new_object(name: String, fields: Vec<InputTypeDescriptionField>) -> Self {
580 Self::Object { name, fields }
581 }
582}
583
584#[derive(Debug, Serialize, Clone)]
585#[serde(rename_all = "camelCase")]
586pub struct InputTypeDescriptionField {
587 name: String,
588 type_names: Vec<String>,
589 required: bool,
590}
591
592impl InputTypeDescriptionField {
593 pub fn new(name: String, type_names: Vec<String>, required: bool) -> Self {
594 Self {
595 name,
596 type_names,
597 required,
598 }
599 }
600}
601
602#[derive(Debug, Serialize, Clone)]
603pub struct InputTypeConstraints<'a> {
604 #[serde(rename = "minFieldCount")]
605 min: Option<usize>,
606 #[serde(rename = "maxFieldCount")]
607 max: Option<usize>,
608 #[serde(rename = "requiredFields")]
609 fields: Option<Vec<Cow<'a, str>>>,
610 #[serde(skip)]
611 got: usize,
612}
613
614impl<'a> InputTypeConstraints<'a> {
615 fn new(min: Option<usize>, max: Option<usize>, fields: Option<Vec<Cow<'a, str>>>, got: usize) -> Self {
616 Self { min, max, fields, got }
617 }
618}
619
620impl fmt::Display for InputTypeConstraints<'_> {
623 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
624 match &self.fields {
625 None => match (self.min, self.max) {
626 (Some(1), Some(1)) => {
627 write!(f, "Expected exactly one field to be present, got {}.", self.got)
628 }
629 (Some(min), Some(max)) => write!(
630 f,
631 "Expected a minimum of {} and at most {} fields to be present, got {}.",
632 min, max, self.got
633 ),
634 (Some(min), None) => write!(
635 f,
636 "Expected a minimum of {} fields to be present, got {}.",
637 min, self.got
638 ),
639 (None, Some(max)) => write!(f, "Expected at most {} fields to be present, got {}.", max, self.got),
640 (None, None) => write!(f, "Expected any selection of fields, got {}.", self.got),
641 },
642 Some(fields) => match (self.min, self.max) {
643 (Some(1), Some(1)) => {
644 write!(
645 f,
646 "Expected exactly one field of ({}) to be present, got {}.",
647 fields.iter().join(", "),
648 self.got
649 )
650 }
651 (Some(min), Some(max)) => write!(
652 f,
653 "Expected a minimum of {} and at most {} fields of ({}) to be present, got {}.",
654 min,
655 max,
656 fields.iter().join(", "),
657 self.got
658 ),
659 (Some(min), None) => write!(
660 f,
661 "Expected a minimum of {} fields of ({}) to be present, got {}.",
662 min,
663 fields.iter().join(", "),
664 self.got
665 ),
666 (None, Some(max)) => write!(
667 f,
668 "Expected at most {} fields of ({}) to be present, got {}.",
669 max,
670 fields.iter().join(", "),
671 self.got
672 ),
673 (None, None) => write!(f, "Expected any selection of fields, got {}.", self.got),
674 },
675 }
676 }
677}
678
679#[derive(Debug, Serialize)]
680#[serde(rename_all = "camelCase")]
681pub struct ArgumentDescription<'a> {
682 name: Cow<'a, str>,
683 type_names: Vec<Cow<'a, str>>,
684}
685
686impl<'a> ArgumentDescription<'a> {
687 pub fn new(name: impl Into<Cow<'a, str>>, type_names: Vec<Cow<'a, str>>) -> Self {
688 Self {
689 name: name.into(),
690 type_names,
691 }
692 }
693}