diff --git a/README.md b/README.md index 0866ef7a..6dc83af6 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,9 @@ The Library will try to follow the following standards and documents: var graphQLClient = new GraphQLHttpClient("https://api.example.com/graphql", new NewtonsoftJsonSerializer()); ``` +> [!NOTE] +> *GraphQLHttpClient* is meant to be used as a single longlived instance per endpoint (i.e. register as singleton in a DI system), which should be reused for multiple requests. + ### Create a GraphQLRequest: #### Simple Request: ```csharp @@ -64,7 +67,10 @@ var personAndFilmsRequest = new GraphQLRequest { }; ``` -Be careful when using `byte[]` in your variables object, as most JSON serializers will treat that as binary data! If you really need to send a *list of bytes* with a `byte[]` as a source, then convert it to a `List` first, which will tell the serializer to output a list of numbers instead of a base64-encoded string. +> [!WARNING] +> Be careful when using `byte[]` in your variables object, as most JSON serializers will treat that as binary data. +> +> If you really need to send a *list of bytes* with a `byte[]` as a source, then convert it to a `List` first, which will tell the serializer to output a list of numbers instead of a base64-encoded string. ### Execute Query/Mutation: @@ -100,6 +106,11 @@ var graphQLResponse = await graphQLClient.SendQueryAsync(personAndFilmsRequest, var personName = graphQLResponse.Data.person.Name; ``` +> [!IMPORTANT] +> Note that the field in the GraphQL response which gets deserialized into the response object is the `data` field. +> +> A common mistake is to try to directly use the `PersonType` class as response type (because thats the *thing* you actually want to query), but the returned response object contains a property `person` containing a `PersonType` object (like the `ResponseType` modelled above). + ### Use Subscriptions ```csharp @@ -141,6 +152,16 @@ var subscription = subscriptionStream.Subscribe(response => subscription.Dispose(); ``` +## Syntax Highlighting for GraphQL strings in IDEs + +.NET 7.0 introduced the [StringSyntaxAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.stringsyntaxattribute?view=net-8.0) to have a unified way of telling what data is expected in a given `string` or `ReadOnlySpan`. IDEs like Visual Studio and Rider can then use this to provide syntax highlighting and checking. + +From v6.0.4 on all GraphQL string parameters in this library are decorated with the `[StringSyntax("GraphQL")]` attribute. + +Currently, there is no native support for GraphQL formatting and syntax highlighting in Visual Studio, but the [GraphQLTools Extension](https://marketplace.visualstudio.com/items?itemName=codearchitects-research.GraphQLTools) provides that for you. + +For Rider, JetBrains provides a [Plugin](https://plugins.jetbrains.com/plugin/8097-graphql), too. + ## Useful Links: * [StarWars Example Server (GitHub)](https://github.com/graphql/swapi-graphql) diff --git a/src/GraphQL.Primitives/StringSyntaxAttribute.cs b/src/GraphQL.Primitives/StringSyntaxAttribute.cs index 76e5b5e4..8be2e889 100644 --- a/src/GraphQL.Primitives/StringSyntaxAttribute.cs +++ b/src/GraphQL.Primitives/StringSyntaxAttribute.cs @@ -1,21 +1,72 @@ #if !NET7_0_OR_GREATER +// ReSharper disable InconsistentNaming // ReSharper disable once CheckNamespace namespace System.Diagnostics.CodeAnalysis; -/// -/// Stub -/// +/// Stub version of the StringSyntaxAttribute, which was introduced in .NET 7 public sealed class StringSyntaxAttribute : Attribute { - // ReSharper disable once InconsistentNaming + /// Initializes the with the identifier of the syntax used. + /// The syntax identifier. + public StringSyntaxAttribute(string syntax) + { + Syntax = syntax; + Arguments = Array.Empty(); + } + + /// Initializes the with the identifier of the syntax used. + /// The syntax identifier. + /// Optional arguments associated with the specific syntax employed. + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + /// Gets the identifier of the syntax used. + public string Syntax { get; } + + /// Optional arguments associated with the specific syntax employed. + public object?[] Arguments { get; } + + /// The syntax identifier for strings containing composite formats for string formatting. #pragma warning disable IDE1006 public const string CompositeFormat = nameof(CompositeFormat); -#pragma warning restore IDE1006 -#pragma warning disable IDE0060 - public StringSyntaxAttribute(string syntax) - { } -#pragma warning restore IDE0060 + /// The syntax identifier for strings containing date format specifiers. + public const string DateOnlyFormat = nameof(DateOnlyFormat); + + /// The syntax identifier for strings containing date and time format specifiers. + public const string DateTimeFormat = nameof(DateTimeFormat); + + /// The syntax identifier for strings containing format specifiers. + public const string EnumFormat = nameof(EnumFormat); + + /// The syntax identifier for strings containing format specifiers. + public const string GuidFormat = nameof(GuidFormat); + + /// The syntax identifier for strings containing JavaScript Object Notation (JSON). + public const string Json = nameof(Json); + + /// The syntax identifier for strings containing numeric format specifiers. + public const string NumericFormat = nameof(NumericFormat); + + /// The syntax identifier for strings containing regular expressions. + public const string Regex = nameof(Regex); + + /// The syntax identifier for strings containing time format specifiers. + public const string TimeOnlyFormat = nameof(TimeOnlyFormat); + + /// The syntax identifier for strings containing format specifiers. + public const string TimeSpanFormat = nameof(TimeSpanFormat); + + /// The syntax identifier for strings containing URIs. + public const string Uri = nameof(Uri); + + /// The syntax identifier for strings containing XML. + public const string Xml = nameof(Xml); +#pragma warning restore IDE1006 } + #endif