question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Rewrite JsonQueryResultSerializer to not serialize to string

See original GitHub issue

Introduction

Currently our JSON query result serializer uses Json.NET and serializes the result to a string and then writes that into a byte stream.

In order to save memory and improve performance we want to build a specialized serializer that only serializes IQueryResult objects and writes the JSON directly into the byte stream without the need of manifesting the JSON first as .NET string object.

Result Object

The IQueryResult represents the execution result of a GraphQL Query or Mutation. The GraphQL Result structure is detailed on more detail in the GraphQL Spec (Response Format).

Our serializer IQueryResultSerializer has one public method SerializeAsync(IReadOnlyQueryResult result, Stream stream).

The result object is a read-only result and has the following structure:

public interface IExecutionResult
{
    IReadOnlyCollection<IError> Errors { get; }

    IReadOnlyDictionary<string, object> Extensions { get; }
}

public interface IReadOnlyQueryResult
    : IExecutionResult
{
    IReadOnlyDictionary<string, object> Data { get; }
}

Data

The data property represents the query result and contains the data that was requested. The data dictionary is ordered correctly, so the serializer does not have to worry puting entries into the correct order.

Spec: Serialized Map Ordering

Since the result of evaluating a selection set is ordered, the serialized Map of results should preserve this order by writing the map entries in the same order as those fields were requested as defined by query execution.

The data property can be empty but will never be null. If the data property is empty than the serializer should NOT write a data entry.

The data property represents a graph. The graph consists of the following three types:

  • Objects Objects are represented as IReadOnlyDictionary<string, object> and each dictionary is guarnteed to be orderd as descriped in the Serialized Map Ordering-section.

  • Lists Lists are represented as IReadOnlyList<object>

  • Scalars and Enums All scalars will serialize to simple .NET value types.

    Apart from .NET value types we also have to handle enum types here as a special case.

    In our first implementation we should look more at the performance site and not think to much about exensibility here.

Extensions

The extension property is organized like the data property. So, we can handle this one the same way. The extension map is reserved for custom extensions like the Apollo Tracing Protocol.

Errors

The errors property is a collection of IError. If this collection is empty it should not be written into the output. Since, IError is a fixed structure appart from the Extensions-property we should be able to write a very simple logic with this one.

Root Property Order

If the error collection has any entry than we will serialize the error property first and the data property second.

Spec Recomendation:

When errors is present in the response, it may be helpful for it to appear first when serialized to make it more clear when errors are present in a response during debugging.

When there is no error than the data property has to be serialized first.

The extension property should always come last.

Implementation

Performance

We do not want to use Linq for this one. So, if we want to check if something is empty use Count. If we need some algorithms we will implement them classically without the need for IEnumerable. So, basicallay for(int i …).

We will need to put some constants asside. Insead of putting the char for braces aside we should do something like the following:

private const byte _leftBrace = (byte)'{';

The cast is safe as long as we are in the ASCII set. Strings have to be converted with Encoding.UTF8.GetBytes().

State

The serializer mustn’t have state and will be used by several threads at the same time.

Further reading: JSON

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
michaelstaibcommented, Jan 15, 2019

One more thing for the implementation… we do not want to serialize numbers with ToString. We have to decompose the numbers into their digits by using basic math and not by serializing it to string or anything. Every digit can then be written as byte to the output stream.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Rewrite JsonQueryResultSerializer to not serialize to string
Currently our JSON query result serializer uses Json.NET and serializes the result to a string and then writes that into a byte stream....
Read more >
Making a property deserialize but not serialize with json.net
Apply a [JsonIgnore] attribute to the property that you do not want to be serialized. Add an alternate, private property setter to the...
Read more >
Migrate from Newtonsoft.Json to System.Text.Json - .NET
Allow or write numbers in quotes. Newtonsoft.Json can serialize or deserialize numbers represented by JSON strings (surrounded by quotes). For ...
Read more >
Jackson – Decide What Fields Get Serialized/Deserialized
We now expect the stringValue field to be serializable, while the other private field not to be, as it has no getter:
Read more >
How to serialize properties of derived classes with System. ...
Learn how to serialize polymorphic objects while serializing to and deserializing from JSON in .NET.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found