Graphql Vs Rest Api
Graphql Vs Rest Api
Graphql Vs Rest Api
1. Introduction 6
1.1 Background 6
1.2 Related work 7
1.3 Problem formulation 8
1.4 Motivation 8
1.5 Result 8
1.6 Scope/Limitation 8
1.7 Target group 9
1.8 Outline 9
2. Method 10
2.1 Controlled Experiment 10
2.1.1 Dependent and independent variables 10
2.2.1 Hypothesis statement 10
2.2 Other Method Considerations 12
2.3 Reliability and Validity 12
2.4 Ethical Considerations 13
3. Theoretical Background 14
3.1 REST 14
3.2 GraphQL 14
3.3 Clean Architecture 15
3.4 CQRS 16
3.5 Mediator 17
4. Implementation 18
4.1 Software and Hardware 18
4.2 General structure 18
4.3 ScroW.Api 19
4.4 ScroW.Application 21
4.5 ScroW.Infrastructure 21
4.6 ScroW.Api.PerformanceTests 22
4.7 ScroW.Api.IntegrationTests 24
5. Results 25
5.1 General result of implementation 25
5.2 Code reviews 26
5.3 Results of experiments 26
6. Analysis 30
6.1 Performance benchmarks 30
6.1.1 Testing of the endpoint BasicInformation (no modification) 30
6.1.2 Testing of the endpoint BasicInformation (over-fetching) 31
6.1.3 Testing of the endpoint BasicInformation (under-fetching) 32
6.1.4 Testing of the endpoint CreateToken (no modification) 33
6.2 Statistical test considerations 33
6.3 Statistical tests 34
6.4 Null hypotheses 36
7. Discussion 38
7.1 REST vs GraphQL for .NET 38
7.2 REST vs HotChocolate 39
References 42
1.1 Background
Sweden is currently ranked the third most digital country in the European Union,
according to a press release made by the Swedish government [3]. One example of
where Sweden is looking to become even more digital is how the Swedish Companies
Registration Office was taxed by the Swedish government to implement digital
registration of annual reports and auditor reports [4][5]. There are currently ten
independent public integrators capable of digital registration [6]. This is suggested to be
problematic since the Swedish Companies Registration Office petitioned the Swedish
government to make digital filing of annual reports (including auditor reports)
mandatory by limited companies starting their fiscal year 2021-07-01 [7]. It is probably
unlikely that the government will approve such a petition with so little time left in the
fiscal year for companies to prepare. However, ten integrators are supposed to handle
the total load of, at the time of writing, around 600 000 annual reports (limited
companies with or without auditors reports) per year for digital registrations [8].
Performance and reliability of service is important when dealing with financial services
required by law and when the reporting is used so broadly [9]. To this end, new ways of
integrating to the Swedish Companies Registration Office is needed.
One way of integrating would be to create an API (application programming
interface), used together with the commonly used architecture style REST
(REpresentational State Transfer) to communicate through the HTTP protocol [10],
[11]. This is, however, not the only alternative, where a relatively newer technology,
GraphQL (a query language), originally developed by Facebook, was created to solve
issues commonly faced in REST APIs [12]. These include, among other, issues like
over-fetching (e.g. requesting too much data, or in other words requesting data that is
not used) or under-fetching (e.g. requesting to little data, or in other words not receiving
enough data from one endpoint, forcing another call to another) [12].
The choice of architectural style is important, since requesting too little or too much
data, or relying on a separate engine to execute and validate incoming requests, causes
implications on the response time needed to perform a request of data [12] [13]. This
thesis aims at evaluating the performance of APIs when implementing traditional REST
versus GraphQL, while integrating to the Swedish Companies Registration Office. Two
different frameworks are used to implement GraphQL, HotChocolate [14] and GraphQL
for .NET [15] and are evaluated together with REST. While the two frameworks in the
end are producing responses in the same way, they are different in the way they require
configuration (as presented in 5.1 General result of implementation and 7. Discussion),
available features, as well as the inner workings of the GraphQL frameworks [14], [15].
The REST API is developed by the author as a part of 4. Implementation using the
ASP.NET framework [16]. There are already a few studies related to the performance
6
implications in general when using the two different architectural types, however,
research is limited on the specific area of .NET Web APIs. By conducting an
experiment on performance of APIs between REST and GraphQL, this thesis aims to
provide detailed knowledge on which architectural style is better suited in an .NET Web
API.
The project is conducted in collaboration with one of the big four accounting firms in
the world (undisclosed at the accounting firms discretion).
7
1.3 Problem formulation
There has been considerable interest on the topic of REST APIs and GraphQL over the
years, however, the specific case of performance analysis in an .NET Web API
environment has gained little to no interest. In consequence, any developer, company or
other interest party looking to choose between one of the two architectural models will
have limited research data to support their decisions. The fact that environments are
ever changing also makes it clear that performance analysis needs to be done in a more
defined environment to better give assurance to any decision maker evaluating the two
architectural models. This thesis therefore will answer the following questions:
1. What are the performance implications when using GraphQL over REST in Web
APIs?
Focusing on the arithmetic mean of the response time, four different REST requests
will be compared with GraphQL:
1. Unmodified GET requests
2. Over-fetching of GET requests
3. Under-fetching of GET requests
4. Unmodified POST requests
1.4 Motivation
Digitalisation is without doubt something that has and continues to change the world as
we know it. By partnering with one of the big four accounting firms in the world the
author intends to integrate to the Swedish Companies Registration Offices APIs as a test
case for this thesis, meaning that this thesis at the same time will solve an issue of future
digital registration needs, potentially caused by slow adoption and availability of
technology. Furthermore as pointed out in the related work there currently are limited
contributions on the topic GraphQL vs REST in an .NET environment, meaning that
this thesis would contribute scientifically in that area. The reason why .NET was chosen
as the implementation was due to the fact that the partnered auditing firm currently is
using .NET in their development.
1.5 Result
This thesis evaluates the performance implications of using GraphQL over REST by
implementing an application in an .NET 6 Web API that integrates to the Swedish
Companies Registration Office. By conducting a controlled experiment using a well
known and respected framework for benchmark testing, BenchmarkDotNet, the results
are presented in graphs and tables and later analyzed and compared to the result of other
related work. The purpose and main contribution of the performed testing was to
analyze the performance implications of two different frameworks (GraphQL for .NET
and HotChocolate) compared to REST. This in order to provide a knowledge base for
the partnered accounting firm, developers and other stakeholders that are evaluating the
use of GraphQL in their future applications.
1.6 Scope/Limitation
Due to the complexity of creating a GraphQL execution engine, one usually uses
publicly available frameworks to create a separate server that handles all GraphQL
related queries. For this contribution, GraphQL for .NET [15] and HotChocolate [14]
have been chosen for implementation and testing. The reason being that these two
frameworks are the two most popular in the .NET environment, and also pointed out as
8
the most valuable by the partnered accounting firm [23]. The author also intends to
remove external dependencies when performing testing (e.g. the external API to the
Swedish Companies Registration Office), making the study focus on internal
performance. Due to the fact that the Swedish Companies Registration Office is only
using GET and POST requests in their API the conducted experiment only focuses on
those two methods. Furthermore due to time constraints the selected four cases for
comparison are not covering all possible scenarios of an API (e.g only testing
unmodified POST requests).
1.8 Outline
The rest of the thesis is organized as follows. Chapter 2 describes the chosen research
methodology and hypothesis statements, including any reliability, validity and ethical
considerations. Chapter 3 presents a theoretical background on REST and GraphQL, as
well as important design principles chosen in the implementation. Chapter 4 describes
how the implementation of the application under test has been performed. Chapter 5
contains all the detailed results retrieved through BenchmarkDotNet, summarized in
tables. Additionally the general result of the implementation is presented together with a
result of the performed code reviews. Chapter 6 analyses the result and presents box
plots and tables of all benchmark data. Furthermore statistical analysis is performed to
conclude if the data is statistically significant or not. In chapter 7 the result is compared
to the related work of other studies as well as analyzing potential differences between
the actual result and the hypotheses. Lastly, chapter 8 presents conclusions as well as
proposals for possible future work.
9
2. Method
The research method used in this project is a controlled experiment, a well known
research strategy for computer science and used in other theses as well as related work
to test hypotheses [17], [22], [24]. In order to conduct the experiments an application
was implemented to test the performance of GraphQL versus REST. See 4.
Implementation. This chapter is divided into several subsections, ranging from an
explanation of the method, different hypotheses statement to ethical considerations
taken into account for this thesis.
10
requesting only a subsample of the data that a REST API is exposing (GraphQL
avoids over-fetching).
3. GraphQL can reduce the need to make multiple round trip requests (GraphQL
avoids under-fetching) and is thus faster than REST APIs if multiple endpoints
need to be called to fetch the required data.
4. Since there are minor differences in response time between GET and POST
requests, the response time of REST APIs are faster than that of GraphQL when
performing a REST POST request and requesting identical data.
Based on the above informal hypotheses the following formal statements have been
designed:
1. Null hypothesis, 𝐻0: REST APIs (RAPI) GET requests are slower or identical in
response time (mean time measured in microseconds) compared to GraphQL
(GQL) POST requests when requesting the exact data that is available from one
endpoint.
𝐻0: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) ≥ 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when requesting the exact
data that is available from one endpoint.
Alternative hypothesis, 𝐻1: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) < 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when
requesting the exact data that is available from one endpoint.
Measures needed: architectural type (RAPI or GQL) and time (TIME) in
microseconds.
2. Null hypothesis, 𝐻0: GraphQL (GQL) POST requests are slower or identical in
response time (mean time measured in microseconds) compared to REST APIs
(RAPI) GET requests when requesting less data than available from one
endpoint.
𝐻0: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) ≤ 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when requesting less data
than available from one endpoint.
Alternative hypothesis, 𝐻1: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) > 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when
requesting less data than available from one endpoint.
Measures needed: architectural type (RAPI or GQL) and time (TIME) in
microseconds.
3. Null hypothesis, 𝐻0: GraphQL (GQL) POST requests are slower or identical in
response time (mean time measured in microseconds) compared to REST APIs
(RAPI) GET requests when requesting more data than available from one
endpoint.
𝐻0: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) ≤ 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when requesting more data
than available from one endpoint.
Alternative hypothesis,
𝐻1: 𝑇𝐼𝑀𝐸(𝐺𝐸𝑇(𝑅𝐴𝑃𝐼)) > 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿(𝐺𝐸𝑇))) when requesting more
data than available from one endpoint.
Measures needed: architectural type (RAPI or GQL) and time (TIME) in
microseconds.
4. Null hypothesis, 𝐻0: REST APIs (RAPI) POST requests are slower or identical
in response time (mean time measured in microseconds) compared to GraphQL
(GQL) POST requests when requesting the exact data that is available from one
endpoint.
11
𝐻0: 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝑅𝐴𝑃𝐼)) ≥ 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿)) when requesting the exact
data that is available from one endpoint.
Alternative hypothesis, 𝐻1: 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝑅𝐴𝑃𝐼)) < 𝑇𝐼𝑀𝐸(𝑃𝑂𝑆𝑇(𝐺𝑄𝐿))
when requesting the exact data that is available from one endpoint..
Measures needed: architectural type (RAPI or GQL) and time (TIME) in
microseconds.
12
MediatR, GraphQL for .NET, and HotChocolate [26]. Furthermore, the framework is
built using best practice principles as outlined in [31], including but not limited to
determining the appropriate number of method invocations, warm-up iterations and
calculating statistics [26]. This argues that the framework BenchmarkDotNet is well
suited for use in this application and that its result can be trusted.
The environment where the tests are executed can also be considered a risk if it is not
isolated before running the code. To mitigate this risk the author intends to isolate the
environment as much as possible and shut down any application not needed before
performing the tests.
13
3. Theoretical Background
This section gives a theoretical background on important design principles and terms
used in the development of the application used for testing, named Swedish Companies
Registration Office Wrapper (ScroW), and aims to give the reader a deeper
understanding of the choices used in the implementation of the .NET 6 Web API built to
integrate to the Swedish Companies Registration Office.
3.1 REST
REST (REpresentational State Transfer) is a software architectural style and a contract
that defines a set of constraints of how an API (application programming interface)
client can interact with a server [10], [11], using the http protocol. There are basically
four parts that should make up a REST request, (1) the endpoint (or URL) to access the
data, (2) the HTTP method used to access the data, (3) the header data and lastly (4) the
body data [10].
Each datapoint is accessed/requested through an URL, commonly called an endpoint,
which returns a specific set of data defined on the server side [10]. A request is made to
the server through several methods, where the most common are GET (get access to a
resource), POST (create a new resource), PUT (update a resource), PATCH (partially
update a resource) and DELETE (delete a resource) [10]. The Swedish Companies
Registration Office is only using/providing GET and POST requests through their APIs
which in turn is mimicked by the developed application. The header provides
information to both the client and server and is used to decorate a response with e.g.
which content type is expected, or proof that the client has access to the particular
endpoint. Lastly, in some cases (e.g. for the POST requests used in the Swedish
Companies Registration Office API) the server expects a body to be included in the
request with additional information needed to process the request [10].
The illustration below is the body of a POST request to an endpoint with the
URL“/api/scro/createtoken” from the built application where the required values are
provided for the fields “organizationNumber” and “socialSecurityNumber”.
{
"organizationNumber": "1234567890",
"socialSecurityNumber": "1234567890"
}
Figure 3.1: Body of a POST request
3.2 GraphQL
In short GraphQL can be described as a query language and a runtime which is capable
of executing and resolving incoming queries [12]. The responsibility of control is
shifted from the server to client, enabling a more dynamic handling compared to e.g.
REST, which provides defined accessible resources that always return the same data
[32]. As mentioned in chapter 1.1 Background, some of GraphQL’s strengths include
solving issues in REST, like over-fetching and under-fetching, but in addition, it can
also retrieve data from all kinds of different sources through one request and using only
a single endpoint [12].
For GraphQL to work, mapping (or referencing) of the GraphQL type objects has to
be made to the actual object, and its properties, which varies depending on the
implementation or framework used [33]. In turn, the different types need to be mapped
14
to a schema definition for the execution and validation to be made [33]. This can be
done in several ways and is dependent on the framework used to implement GraphQL.
E.g. HotChocolate allows annotation, code-first, and a schema-first approach when
implementing, while GraphQl for .NET only supports code-first and a schema-first
approach [14], [15].
In essence, to request data through GraphQL, a REST API POST request is made to
the server containing a body with a query, operation type (e.g. query or mutation) and
root object with chosen fields to define what is to be resolved and from which defined
area [34]. The GraphQL execution engine interpers the query (either a query or
mutation) and provides the data requested in a response back to the client [34]. To
receive data using the defined type system, the queries are executed by a GraphQL
server which resolves each field using a defined resolver. The resolver can fetch data
from any data source (ranging from external APIs to databases), repeating this process
until all the fields in the query have been fulfilled, and lastly returning the data into a
response [32].
The illustration below is the body of a POST request, containing a query requesting
data for the fields “organizationNumber” and “name” in the defined root object/type
“basicInformation” taking the string input parameter “$organizationNumber”.
{
"query": "query($organizationNumber: String!) {
basicInformation (organizationNumber:$organizationNumber) {
organizationNumber
name
}
}"
"variables": {
"organizationNumber": "1234567890"
}
}
Figure 3.2: Body of a POST request, containing a query
15
Figure 3.3: A simplified representation of the different separation of concerns used in Clean Architecture
As shown in figure, the Application Core focuses on and contains interfaces, entities,
and business logic, the Infrastructure contains external dependencies (e.g. a database)
depends on the Core, and implements interfaces from the Core, while lastly the outer
layer User Interface (e.g. a Web API or Frontend application) also depends on the Core
[29].
Dependencies are pointed inwards, which means that e.g. the User Interface can
depend on the Application Core, but the Application Core cannot depend on the User
Interface [29].
3.4 CQRS
The CQRS (Command Query Responsibility Segregation) is a way to separate read and
update operations by using different models to handle each task [36]. This means that
each task is separated into its own isolated part, independent of other features,
commands or queries. Commands are specifically used for performing actions (e.g.
updating or modifying a database), while queries instead are used to retrieve data. The
CQRS design pattern brings the benefit of (1) scalability - making it easy to add or
modify features in an application, (2) performance -being able to specifically improve a
specific area of code (with e.g. caching), and lastly (3) added simplicity - by making
sure that each model does only one thing and is only used by that specific part of the
code [37]. Nevertheless, there are a few drawbacks, one being the risk that projects
easily become unnecessarily large with an increased risk of redundant/duplicate code.
16
3.5 Mediator
Another way of promoting loose coupling in an application is by using a behavioral
design pattern called the mediator pattern. This pattern manages interactions between
objects through a coordinator, while maintaining isolation between the classes [38]. In
.NET the most popular implementation of the mediator pattern is MediatR, also
commonly used together with the CQRS design pattern (see above 3.4 CQRS) [39].
17
4. Implementation
The following section will present the implementation of the application, called ScroW
(Swedish Companies Registration Office Wrapper), which aims at integrating with the
Swedish Companies Registration Office using both REST and GraphQL. Design
choices for the application will be presented in addition to the test written to evaluate
performance.
Furthermore, all implementations have been performed using the framework .NET 6.
Regarding GraphQL, the frameworks used and tested were GraphQL (or GraphQL for
.Net/GraphQL.Net) version 5.1.1 [40] and HotChocolate version 12.7.1 [41]. All of
which, at the time of the applications implementation, were the latest versions.
BenchmarkDotNet version 0.13.1 [42] was used together with Moq version 4.17.2
for the performance testing[43]. Please note that these packages are not comprehensive
for the actual implementation of the application. For a full list of packages used please
see Appendix B - Repository and benchmark outputs for the repository containing all
public code.
When running the benchmark application to run the tests, the computer was started
with only the necessary applications needed to run the operating system and the tests
itself. All other background applications were shut down to not cause any interference
while running the tests, as pointed out by through the code review performed (see
Appendix A - Developer backgrounds and Code reviews)
18
ScroW
src
Api
ScroW.Api
Core
ScroW.Application
Infrastructure
ScroW.Infrastructure
tests
ScroW.Api.PerformanceTests
ScroW.Api.IntegrationTests
Figure 4.1: Structure of the ScroW project.
4.3 ScroW.Api
The presentation layer of the application, ScroW.Api, was created using a .NET 6
version of the Web API SDK to ease development and make use of the built-in
functionality provided by .NET [44]. Using the Mediator pattern, the different
controllers/GraphQL query executors did not include any core logic but instead used the
Mediator to send through the data to its correct area in the core project, see code
snippets in figure 4.2 and 4.3.
The REST and GraphQL for .NET implementations require the creation of separate
controllers, handling logic e.g. endpoint definition and input parameters. Unlike the
framework HotChocolate which only needs registering in the Startup class due to its
behind the scenes working, setting everything up automatically. The code snippet in
figure 4.2 shows how implementation is made with REST (only showing one method
and limiting applied attributes for brevity) and subsequently, GraphQL for .NET in the
code snippet in figure 4.3.
[Route("api/[controller]")]
[Produces("application/json")]
public class ScroController : ControllerBase
{
public readonly IMediator mediator;
[HttpGet("BasicInformation/{organizationNumber}")]
[ProducesResponseType(typeof(BasicInformationResponse), 200)]
public async Task<IActionResult> BasicInformationAsync(
[Required][FromRoute] string organizationNumber)
{
return Ok(await mediator.Send(new BasicInformationQuery
{
OrganizationNumber = organizationNumber
}));
}
}
Figure 4.2: Controller class showing a method for a REST endpoint..
19
[Route("api/[controller]")]
[Produces("application/json")]
public class GraphQLController : ControllerBase
{
private readonly ISchema schema;
private readonly IDocumentExecuter executer;
[HttpPost("graphqlnet")]
public async Task<IActionResult> GraphQL([FromBody] GraphQLRequest r)
{
var result = await executer.ExecuteAsync(s =>
{
s.Schema = schema;
s.Variables = r?.Variables;
s.Query = r?.Query;
s.OperationName = r?.OperationName;
s.RequestServices = HttpContext.RequestServices;
s.CancellationToken = HttpContext.RequestAborted;
});
The two GraphQL implementations differ in how they are set up. GraphQL for .NET
requires the most setup by using the code-first approach, with a need to define each
object type and how they interact through queries/mutations and finally the schema
[45]. This is, however, automatically set up by HotChocolate. The only thing needed for
the HotChocolate implementation is defining the different queries/mutations so
HotChocolate can register each object type (queries/mutations) and create a schema
automatically using an annotation based approach [46], [47]. The following code
presens how GraphQL for .NET and subsequently HotChocolate was added to the
service collection in the Startup class as well as the mapping of endpoints to either the
controller (REST and GraphQL for .NET) or its separate endpoint (HotChocolate).
20
services.AddGraphQL(builder => builder
AddSelfActivatingSchema<ScroWSchema>()
.AddClrTypeMappings()
.AddSystemTextJson()
.AddGraphTypes(typeof(ScroWSchema).Assembly)
);
services.AddHttpContextAccessor();
services.AddGraphQLServer()
.AddQueryType<HotChocolate.Query>()
.AddMutationType<HotChocolate.Mutation>()
.ModifyRequestOptions(opt =>
{
opt.IncludeExceptionDetails = true;
}
);
Figure 4.4: Service registration for both GraphQL for .NET and subsequently HotChocolate.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGraphQL()
.WithOptions(new GraphQLServerOptions
{
EnableGetRequests = false
});
});
Figure 4.5: Registering Controllers (REST and GraphQL for .NET) and HotChocolate to a middleware.
4.4 ScroW.Application
In a .NET class project, using Mediator and CQRS the business logic was separated
from the presentation layer. The ScroW.Application project is the core of the application,
this is also shown by the folder structure. The application project contains contracts
(e.g. interfaces without the actual implementation), models used by the Swedish
Companies Registration Office API, mapping profiles between models and data transfer
objects (DTOs), serialization/deserialization logic etc. Even though there are
frameworks handling CQRS, CQRS was implemented using a folder structure. Mapping
between models and DTOs was handled using the library AutoMapper, which is
commonly used in .NET projects for this purpose [48].
4.5 ScroW.Infrastructure
Since the core layer of the application is oblivious as to how data is retrieved, it is
common to break out external dependencies (e.g. a database, frameworks, etc) to its
separate project. The only identified external dependency is the API to the Swedish
Companies Registration Office contacted to retrieve data processed in the core layer.
Using a contract from the core layer, a typed HttpClient [49] was created that was
specialized in retrieving the data from the Swedish Companies Registration Office.
21
4.6 ScroW.Api.PerformanceTests
The benchmark tests have been performed using a separate .NET console project
focused on benchmark tests called ScroW.Api.PerformanceTests (see Appendix B -
Repository and benchmark outputs for a reference to the repository, including the raw
test results). In order to test at a level that includes the application’s supporting
infrastructure (e.g. HttpRequests, Controllers, GraphQL executor engine, Mediator etc)
throughout the whole application, a generic custom WebApplicationFactory was used,
see below in figure 4.6. This allows the web host configurations to be modified as
needed when creating an in memory version of the application [50].
base.ConfigureWebHost(builder);
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.UseContentRoot(Directory.GetCurrentDirectory());
return base.CreateHost(builder);
}
}
Figure 4.6: A custom WebApplicationFactory used to modify the web host by adding a mocked mediator
The most important configuration of the custom factory was the setup of a mock
Mediator using Moq, a framework to mock different areas of the application [51]. The
Mediator was mocked in order to control the results that were sent back when calling
different endpoints through REST and GraphQL. Since the application was contacting
the Swedish Companies Registration Office through an API this dependency was
removed since it only created uncertainty, increased latency and wouldn’t help nor
affect the benchmarking of REST and GraphQL. Using the WebApplicationFactory an
HttpClient was created which enabled making API calls to the application, just as if it
would have been an external application. However, all dependencies and eventual
overhead caused by contacting the different endpoint types was retained, allowing for
benchmarking REST vs GraphQL. Since the Mediator was mocked and configured to
return known data, the above ScroW.Application project was circumvented entirely and
was not important for the result of the benchmarking, but needed for running the
application.
The benchmark testing was performed with the framework BenchmarkDotNet. Not
much was needed in terms of configuration, which is also one of the key strengths of the
framework [26]. The code was structured as illustrated in the below figure 4.7, using all
common setup in an abstract base class, which each test class inherited from.
22
[InProcess]
[MemoryDiagnoser]
[MinColumn, MaxColumn]
[Config(typeof(TestConfig))]
public abstract class BenchmarkBase
{
public HttpClient client;
public Mock<IMediator> mockMediator;
[GlobalSetup]
public void GlobalSetup()
{
var factory = new CustomWebApplicationFactory<Startup>();
client = factory.CreateClient();
var scope = factory.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
mockMediator = scope.ServiceProvider.GetRequiredService<Mock<IMediator>>();
mockMediator
.Setup(m => m.Send(It.IsAny<BasicInformationQuery>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(() => expectedBasicInformationResult);
mockMediator
.Setup(m => m.Send(It.IsAny<CaseStatusQuery>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(() => expectedCaseStatusResponse);
mockMediator
.Setup(m => m.Send(It.IsAny<CreateTokenCommand>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(() => expectedCreateTokenResponse);
}
}
Figure 4.7: Benchmark setup class registering mocked data to be retrieved when performing the different calls to the API.
Each separate test type was structured in its own class and was requesting exactly the
same data but from different endpoints, ultimately calling either GraphQL or REST.
Below figure 4.8 is an example of the “BasicInformation” tests with REST (GraphQL
methods have been omitted for brevity, see Appendix B for a reference to the test
repository).
23
4.7 ScroW.Api.IntegrationTests
The integration test project was structured in the exact same way as the performance test
project, however, without mocking the Mediator. This was due to the goal of the project,
testing the integration between ScroW and the Swedish Companies Registration Office
API. The tests were designed in the same way as the above performance tests, with the
only exception being the usage of asserts to be able to verify the correctness of what is
being returned from the API.
24
5. Results
This chapter is divided into three subsections. First presenting the results from
implementing ScroW using REST, HotChocolate or GraphQL for .NET. Secondly
presenting the result of the code review performed on the author's implemented
solution. Lastly presenting the performance results after running BenchmarkDotNet.
Table 5.1: Number of Classes and Lines of Code related to each architectural type
Method Classes Lines of Code
Rest 2 79
HotChocolate 3 81
GraphQLNet 21 373
Examples of code that has been removed from the calculation can be seen in the below
figures 5.1, 5.2 and 5.3.
[ProducesResponseType(typeof(ErrorMessage), 400)]
[ProducesResponseType(typeof(ErrorMessage), 403)]
[ProducesResponseType(typeof(ErrorMessage), 404)]
[ProducesResponseType(typeof(ErrorMessage), 500)]
[ProducesResponseType(typeof(ErrorMessage), 503)]
[ProducesResponseType(typeof(ErrorMessage), 504)]
Figure 5.1: Attributes in the REST controller.
options.Filters.Add<HttpResponseExceptionFilter>();
Figure 5.2: Exception filter registration in the Startup class.
25
services.AddGraphQLServer()
.AddQueryType<HotChocolate.Query>()
.AddMutationType<HotChocolate.Mutation>()
.ModifyRequestOptions(opt =>
{
opt.IncludeExceptionDetails = true;
});
Figure 5.3: HotChocolate service registration, adding more verbose error messaging.
26
Table 5.2: Execution time of GET REST request and POST GraphQL requests without modification.
Run Rest (μs) HotChocolate (μs) GraphQLNet (μs)
1 291.43 239.24 428.76
2 293.90 237.52 428.49
3 291.00 239.48 429.80
4 287.30 237.78 429.96
5 294.20 237.30 428.99
6 291.69 237.68 428.81
7 289.30 238.52 429.86
8 286.92 238.50 428.63
9 286.90 237.76 430.45
10 290.10 238.53 431.30
11 293.46 237.73 430.21
12 285.51 237.77 430.74
13 287.27 238.19 430.29
14 285.58 238.63
15 286.39 239.52
MEAN 289.40 238.28 429.71
N 15 15 13
The results presented in table 5.2 show that HotChocolate was faster than the two others
on average, while REST was faster than GraphQL for .NET.
Experiment 2 was performed to test hypothesis 2 using an over-fetching of GET
requests configuration.
Table 5.3: Execution time of GET REST request and POST GraphQL requests when requesting less data than what is provided from
a one REST endpoint.
Run Rest (μs) HotChocolate GraphQLNet
1 273.32 208.74 306.16
2 276.88 209.17 308.89
3 282.66 207.98 308.52
4 275.33 209.78 308.34
5 270.50 208.11 306.12
6 268.18 211.30 305.65
7 280.16 209.70 305.87
8 282.72 211.38 306.77
9 283.34 208.92 311.10
10 274.60 210.25 312.39
11 279.40 209.68 312.78
12 280.96 210.37 312.58
13 278.35 211.54 311.43
14 280.90 211.89 314.27
15 278.38 211.50 313.77
MEAN 277.71 210.02 309.64
N 15 15 15
27
The results presented in table 5.3 show that HotChocolate was faster than the two
others on average, while REST was faster than GraphQL for .NET. However the
average response time of GraphQL for .NET was decreased when compared to
experiment 1.
Experiment 3 was performed to test hypothesis 3 using an under-fetching of GET
requests configuration.
Table 5.4: Execution time of GET REST request and POST GraphQL requests when data must be retrieved from two REST
endpoints.
Run Rest (μs) HotChocolate (μs) GraphQLNet (μs)
1 544.72 319.48 522.98
2 561.17 319.07 524.18
3 542.83 318.19 526.78
4 546.10 317.68 527.24
5 557.09 316.09 524.27
6 545.70 316.57 523.87
7 542.62 317.18 526.35
8 536.53 318.49 525.73
9 537.64 316.36 526.21
10 556.12 315.41 531.56
11 561.96 316.43 532.93
12 547.25 315.94 529.66
13 537.30 316.89 529.85
14 549.97 320.48 528.54
15 315.04 528.07
MEAN 547.64 317.29 527.21
N 14 15 15
The results presented in table 5.4 show that HotChocolate was faster than the two
others on average, while GraphQL for .NET was faster than REST.
Lastly, experiment 4 was performed to test hypothesis 4 using an unmodified POST
requests configuration.
28
Table 5.5: Execution time of POST REST request and POST GraphQL requests without modification.
Run Rest (μs) HotChocolate (μs) GraphQLNet (μs)
1 276.84 210.13 325.41
2 287.00 210.01 325.55
3 283.46 213.35 326.75
4 279.43 211.00 327.49
5 287.01 209.90 327.65
6 280.75 211.24 327.77
7 284.82 212.03 326.55
8 278.44 208.84 328.53
9 283.24 210.03 326.37
10 280.35 211.35 325.86
11 277.14 213.07 326.17
12 287.23 210.82 325.36
13 280.28 210.74
14 294.02 212.02
15 291.19 210.60
MEAN 283.41 211.01 326.62
N 15 15 12
The results presented in table 5.5 show that HotChocolate was faster than the two others
on average, while, similar to experiment 1, REST was faster than GraphQL for .NET.
29
6. Analysis
In the below chapter, the result will be analyzed using BenchmarkDotNet to present
box plots and tables of data. Furthermore, the statistical methods Levene’s test and the
Kruskal–Wallis one-way analysis of variance tests are applied to the data retrieved
from the benchmark analysis to consider if the performance between REST and
GraphQL is statistically significant and to what significance level.
Figure 6.1: Execution time of GET REST request and POST GraphQL requests without modification. Generated by
BenchmarkDotNet.
30
Table 6.1: Execution time and memory benchmarks of GET REST request and POST GraphQL requests without modification.
Method Mean (μs) Min (μs) Max (μs) Ratio Rank Gen 0 Gen 1 Allocated (KB)
Rest 289.398 285.508 294.202 1 2 3.4180 1.4648 28
HotChocolate 238.276 237.301 239.515 0.82 1 4.3945 0.9766 34
GraphQLNet 429.714 428.488 431.304 1.48 3 6.8359 1.4648 52
Figure 6.2: Execution time of GET REST request and POST GraphQL requests when requesting less data than what is provided
from a one REST endpoint. Generated by BenchmarkDotNet.
Table 6.2: Execution time and memory benchmarks of GET REST and POST GraphQL requests when requesting less data than
what is provided from a one REST endpoint.
Method Mean (μs) Min (μs) Max (μs) Ratio Rank Gen 0 Gen 1 Allocated (KB)
Rest 277.712 268.184 283.337 1 2 3.4180 1.4648 28
HotChocolate 210.020 207.979 211.889 0.76 1 3.1738 0.7324 25
GraphQLNet 309.642 305.648 314.271 1.12 3 4.3945 0.9766 37
31
6.1.3 Testing of the endpoint BasicInformation (under-fetching)
Figure 6.3: Execution time of GET REST request and POST GraphQL requests when data must be retrieved from two REST
endpoints. Generated by BenchmarkDotNet.
Table 6.3: Execution time and memory benchmarks of GET REST request and POST GraphQL requests must be retrieved from two
REST endpoints.
Method Mean (μs) Min (μs) Max (μs) Ratio Rank Gen 0 Gen 1 Allocated (KB)
Rest 547.645 536.534 561.960 1 3 6.8359 2.9297 54
HotChocolate 317.285 315.038 320.481 0.58 1 4.8828 1.4648 38
GraphQLNet 527.215 522.979 532.931 0.96 2 7.8125 1.9531 61
32
6.1.4 Testing of the endpoint CreateToken (no modification)
Figure 6.4: Execution time of POST REST request and POST GraphQL requests without modification. Generated by
BenchmarkDotNet.
Table 6.4: Execution time and memory benchmarks of POST REST request and POST GraphQL requests without modification.
Method Mean (μs) Min (μs) Max (μs) Ratio Rank Gen 0 Gen 1 Allocated (KB)
Rest 283.413 276.836 294.025 1 2 3.9063 1.9531 30
HotChocolate 211.008 208.837 213.347 0.74 1 4.1504 0.9766 31
GraphQLNet 326.622 325.364 328.533 1.16 3 4.8828 0.9766 39
33
Table 6.5: Results of Levene’s test for the different groups of population
34
Table 6.6: Statistical results of the One-way Kruskal–Wallis test for the test GetBasicInformation
Test GetBasicInformation
Table 6.7: Statistical results of the One-way Kruskal–Wallis test for the test GetBasicInformationOverFetching
Test GetBasicInformationOverFetching
Table 6.8: Statistical results of the One-way Kruskal–Wallis test for the test GetBasicInformationUnderFetching
Test GetBasicInformationUnderFetching
35
Table 6.9: Statistical results of the One-way Kruskal–Wallis test for the test PostCreateToken
Test PostCreateToken
Table 6.10: Null hypothesis results when comparing REST to GraphQL for .NET
𝐻0: REST APIs (RAPI) GET requests are slower or identical in response time (mean false
time measured in microseconds) compared to GraphQL (GQL) POST requests
when requesting the exact data that is available from one endpoint.
𝐻0: GraphQL (GQL) POST requests are slower or identical in response time (mean true
time measured in microseconds) compared to REST APIs (RAPI) GET requests
when requesting less data than available from one endpoint.
𝐻0: GraphQL (GQL) POST requests are slower or identical in response time (mean false
time measured in microseconds) compared to REST APIs (RAPI) GET requests
when requesting more data than available from one endpoint.
𝐻0: REST APIs (RAPI) POST requests are slower or identical in response time false
(mean time measured in microseconds) compared to GraphQL (GQL) POST
requests when requesting the exact data that is available from one endpoint.
36
Testing in 6.1.1 GET - BasicInformation - No modification concluded that, as opposed
to the testing of GraphQL for .NET, HotChocolates is faster (238.3 μs) compared to
REST (289.4 μs). The testing in 6.1.2 GET - BasicInformation - Over fetching and 6.1.3
GET - BasicInformation - Under fetching follows the defined hypotheses and seems to
suggest that GraphQL is faster (210.0 respectively 317.3 μs) compared to REST (277.7
respectively 547.6 μs). Lastly, tests in 6.1.4 POST - CreateToken - No modification
noted that GraphQL (211.0 μs) was faster than REST (283.4 μs) unlike testing
performed on GraphQL for .NET which showed opposite results. The different results
are all significant on the 0.0125 level (as concluded in 6.3 Statistical tests) and can be
summarized in the below table. The null hypotheses that were not rejected were the
testing conducted on the GET and POST requests with no modification to the response.
𝐻0: REST APIs (RAPI) GET requests are slower or identical in response time (mean true
time measured in microseconds) compared to GraphQL (GQL) POST requests
when requesting the exact data that is available from one endpoint.
𝐻0: GraphQL (GQL) POST requests are slower or identical in response time (mean false
time measured in microseconds) compared to REST APIs (RAPI) GET requests
when requesting less data than available from one endpoint.
𝐻0: GraphQL (GQL) POST requests are slower or identical in response time (mean false
time measured in microseconds) compared to REST APIs (RAPI) GET requests
when requesting more data than available from one endpoint.
𝐻0: REST APIs (RAPI) POST requests are slower or identical in response time true
(mean time measured in microseconds) compared to GraphQL (GQL) POST
requests when requesting the exact data that is available from one endpoint.
37
7. Discussion
This thesis aimed at comparing the response time of GraphQL versus REST when
implementing an .NET Web API. To this end four different tests were conducted and
analyzed within an experiment to gain insights.
Results display that variance in response time is much larger when contacting an
REST endpoint compared to GraphQL, see Figure 6.1 to 6.4. This means that even
though REST in some cases is faster than GraphQL, there is a more consistent response
from GraphQL which can be an important factor depending on the use case.
Furthermore, the general memory allocation is much larger in GraphQL compared to
REST which could be explained by the extra layers and work needed for GraphQL to
evaluate and execute queries.
The performance benchmark results are mostly not comparable with the result found
in other contributions and as such it does not correlate to previous research. This is due
to testing being performed in different ways and using a variety of internally/externally
used GraphQL servers as well as different applications and development environments.
With that said, inconsistencies have also been presented in research before. REST has
been presented both as faster than GraphQl [18], as well as inconsistent in terms of
response time [19], [22].
38
GraphQL, which means that if the REST response is sufficiently large and the GraphQL
response is slimmed down enough the GraphQL could become faster than REST.
39
8. Conclusions and Future Work
This thesis has presented how the implementation of two GraphQL frameworks
(GraphQL for .NET and HotChocolate) behaves compared to REST in an .NET 6
environment. By conducting a controlled experiment, containing five different
hypotheses, the experiment intended to answer the following research questions: What
are the performance implications when using GraphQL over REST in Web APIs? The
author partnered with one of the big four accounting firms in the world to implement an
application to act as a test case and at the same time solve the problem of digitally
integrating to the Swedish Companies Registration Office and to register auditor reports
through an API.
When looking at performance, HotChocolate outperforms both GraphQL for .NET
and REST, in a .NET 6 Web API which was a surprising finding since other related
work suggest that REST is faster than GraphQL when requesting the same data. With
the testing performed using BenchmarkDotNet the results indicate that there are several
factors that play a role in performance and code maintainability, with perhaps the most
important finding being the importance of which framework is used in the
implementation. The inner workings of a GraphQL engine is without doubt complex,
adding extra layers that need to receive, validate and resolve queries and what is to be
returned/dropped, causing an overhead which will need to be handled for GraphQL to
be feasible to use over REST. The different frameworks also implement GraphQL in
different ways, allowing e.g. different methods to make mapping of types easier, as well
as different optimizations which in turn affects both performance and code
maintainability (compare e.g. the code first approach in GraphQL for .NET with the
annotation based approach in HotChocolate). The previous related work does not focus
on testing different GraphQL frameworks within the same development environment,
but instead focus on only comparing REST to GraphQL, which makes this an
interesting finding in not only a .NET environment, but potentially to other
development environments as well.
40
and responses, as suggested by the performance benchmarks performed by
HotChocolate in its own comparison between other frameworks. A separate view to this
would be to find the exact threshold limit in request/response size, to see when
GraphQL outperforms REST. Moreover, this thesis has only focused on testing
performed on GraphQL POST requests since this is considered standard. Another
interesting research area would be to also get a sense of how GraphQL GET requests
are behaving from a performance perspective. Lastly, this thesis concluded that the
framework used is an important factor in deciding what architectural type is more
performant. Testing has only been performed on the two most popular GraphQL
frameworks that exists for C# while other frameworks could have called for a different
implementation to GraphQL, making it better or worse in different situations.
41
References
[1] E. Spjut and M. Ulfhielm, “Revisionsberättelser : Vilka faktorer har ett samband
med orena revisionsberättelser?,” Dissertation, Handelshögskolan vid Umeå
universitet, Umeå, 2008. Accessed: Feb. 11, 2022. [Online]. Available:
http://urn.kb.se/resolve?urn=urn:nbn:se:umu:diva-1710
[2] Riksdagsförvaltningen, “Årsredovisningslag (1995:1554) Svensk
författningssamling 1995:1995:1554 t.o.m. SFS 2021:1216 - Riksdagen.”
https://www.riksdagen.se/sv/dokument-lagar/dokument/svensk-forfattningssamli
ng/arsredovisningslag-19951554_sfs-1995-1554 (accessed Feb. 11, 2022).
[3] “Sverige i toppen i ny rankning över EU:s mest digitaliserade länder,”
Regeringskansliet, Nov. 12, 2021.
https://www.regeringen.se/pressmeddelanden/2021/11/sverige-i-toppen-i-ny-rank
ning-over-eus-mest-digitaliserade-lander/ (accessed Feb. 11, 2022).
[4] Uppdrag att införa en tjänst för ingivning av finansiell information avseende
årsredovisningar m.m. Regeringen och Regeringskansliet, 2016. Accessed: Feb.
11, 2022. [Online]. Available:
https://www.regeringen.se/regeringsuppdrag/2016/08/uppdrag-att-infora-en-tjanst
-for-ingivning-av-finansiell-information-avseende/
[5] Uppdrag att utveckla tjänsten för digital ingivning av årsredovisningar m.m. för
alla företagsformer. Regeringen och Regeringskansliet, 2018. Accessed: Feb. 11,
2022. [Online]. Available:
https://www.regeringen.se/regeringsuppdrag/2018/03/uppdrag-att-utveckla-tjanst
en-for-digital-ingivning-av-arsredovisningar-m.m.-for-alla-foretagsformer/
[6] “Programvara och leverantörer – Lämna in årsredovisningen digitalt,”
Bolagsverket.
https://bolagsverket.se/pb/etjanster/lamna-in-arsredovisning/programvara-och-lev
erantorer-lamna-in-arsredovisningen-digitalt-1.17543 (accessed Feb. 11, 2022).
[7] S. Hadjipetri Glantz, “Obligatorisk digital årsredovisning rör upp känslor,”
Balans, Jun. 07, 2021.
https://tidningenbalans.se/artikel/obligatorisk-digital-arsredovisning-ror-upp-kans
lor (accessed Feb. 11, 2022).
[8] “Företagsregistret,” Statistiska Centralbyrån.
http://www.scb.se/vara-tjanster/bestall-data-och-statistik/foretagsregistret/
(accessed Feb. 11, 2022).
[9] “Vad gör en revisor?,” FAR.
https://www.far.se/kunskap/branschens-yrkesroller/vad-gor-en-revisor/ (accessed
May 14, 2022).
[10] M. Lo, “RESTful API 101,” Geek Culture, Aug. 25, 2021.
https://medium.com/geekculture/restful-api-101-b61671e5a3ea (accessed Apr.
28, 2022).
[11] S. B. Avraham, “What is REST — A Simple Explanation for Beginners, Part 1:
Introduction,” Extend, Sep. 05, 2017.
https://medium.com/extend/what-is-rest-a-simple-explanation-for-beginners-part-
1-introduction-b4a072f8740f (accessed Apr. 28, 2022).
[12] “GraphQL | A query language for your API.” https://graphql.org/ (accessed Apr.
26, 2022).
[13] W. Trocki, “GraphQL Performance Explained,” Medium, Nov. 15, 2019.
https://medium.com/@wtr/graphql-performance-explained-cb4b43412fb4
(accessed May 17, 2022).
42
[14] ChilliCream GraphQL Platform. ChilliCream, 2022. Accessed: Apr. 25, 2022.
[Online]. Available: https://github.com/ChilliCream/hotchocolate
[15] GraphQL for .NET. graphql-dotnet, 2022. Accessed: Apr. 25, 2022. [Online].
Available: https://github.com/graphql-dotnet/graphql-dotnet
[16] R. Anderson, D. Roth, and S. Luttin, “Overview of ASP.NET Core.”
https://docs.microsoft.com/en-us/aspnet/core/introduction-to-aspnet-core
(accessed Jun. 02, 2022).
[17] G. Brito and M. T. Valente, “REST vs GraphQL: A Controlled Experiment,” in
2020 IEEE International Conference on Software Architecture (ICSA), Mar.
2020, pp. 81–91. doi: 10.1109/ICSA47634.2020.00016.
[18] D. A. Hartina, A. Lawi, and B. L. E. Panggabean, “Performance Analysis of
GraphQL and RESTful in SIM LP2M of the Hasanuddin University,” in 2018
2nd East Indonesia Conference on Computer and Information Technology
(EIConCIT), Nov. 2018, pp. 237–240. doi: 10.1109/EIConCIT.2018.8878524.
[19] M. Seabra, M. F. Nazário, and G. Pinto, “REST or GraphQL? A Performance
Comparative Study,” in Proceedings of the XIII Brazilian Symposium on Software
Components, Architectures, and Reuse, New York, NY, USA, Sep. 2019, pp.
123–132. doi: 10.1145/3357141.3357149.
[20] O. Hartig and J. Pérez, “Semantics and Complexity of GraphQL,” in Proceedings
of the 2018 World Wide Web Conference, Republic and Canton of Geneva, CHE,
Apr. 2018, pp. 1155–1164. doi: 10.1145/3178876.3186014.
[21]. “NET and .NET Core official support policy,” Microsoft.
https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core (accessed
Feb. 11, 2022).
[22] S. L. Vadlamani, B. Emdon, J. Arts, and O. Baysal, “Can GraphQL Replace
REST? A Study of Their Efficiency and Viability,” in 2021 IEEE/ACM 8th
International Workshop on Software Engineering Research and Industrial
Practice (SER IP), Jun. 2021, pp. 10–17. doi: 10.1109/SER-IP52554.2021.00009.
[23] “GraphQL Code Libraries, Tools and Services.” https://graphql.org/code/#c-net
(accessed Apr. 25, 2022).
[24] A. Gupta and P. Jalote, “An Experimental Evaluation of the Effectiveness and
Efficiency of the Test Driven Development,” in First International Symposium on
Empirical Software Engineering and Measurement (ESEM 2007), Sep. 2007, pp.
285–294. doi: 10.1109/ESEM.2007.41.
[25] C. Wohlin, P. Runeson, M. Höst, M. C. Ohlsson, B. Regnell, and A. Wesslén,
Experimentation in Software Engineering. Springer, 2012. doi:
10.1007/978-3-642-29044-2.
[26] dotnet/BenchmarkDotNet. .NET Platform, 2022. Accessed: Apr. 23, 2022.
[Online]. Available: https://github.com/dotnet/BenchmarkDotNet
[27] “Independent t-test in SPSS Statistics - Procedure, output and interpretation of
the output using a relevant example | Laerd Statistics.”
https://statistics.laerd.com/spss-tutorials/independent-t-test-using-spss-statistics.p
hp (accessed May 15, 2022).
[28] Y. Chan and R. P. Walmsley, “Learning and understanding the Kruskal-Wallis
one-way analysis-of-variance-by-ranks test for differences among three or more
independent groups,” Phys. Ther., vol. 77, no. 12, pp. 1755–1762, Dec. 1997, doi:
10.1093/ptj/77.12.1755.
[29] R. C. Martin, Clean Architecture: A Craftsman’s Guide to Software Structure and
Design, 1st ed. USA: Prentice Hall Press, 2017.
[30] R. C. Martin, J. M. Rabaey, A. P. Chandrakasan, and B. Nikolić, Agile Software
43
Development: Principles, Patterns, and Practices. Pearson Education, 2003.
[31] A. Akinshin, Pro .NET Benchmarking: The Art of Performance Measurement, 1st
ed. edition. Apress, 2019.
[32] G. Mavroudeas et al., “Learning GraphQL Query Cost,” in 2021 36th IEEE/ACM
International Conference on Automated Software Engineering (ASE), Nov. 2021,
pp. 1146–1150. doi: 10.1109/ASE51524.2021.9678513.
[33] “Schemas and Types | GraphQL.” https://graphql.org/learn/schema/ (accessed
May 09, 2022).
[34] “Execution | GraphQL.” https://graphql.org/learn/execution/ (accessed May 09,
2022).
[35] G. Cleeren, “Architecting ASP.NET Core 3 Applications: Best Practices,” Jan.
08, 2021. Accessed: May 13, 2022. [Online]. Available:
https://app.pluralsight.com/library/courses/architecting-asp-dot-net-core-applicati
ons-best-practices
[36] A. Baco, “CQRS Pattern with C#,” Medium, Nov. 16, 2020.
https://abdelmajid-baco.medium.com/cqrs-pattern-with-c-a9aff05aae3f (accessed
Apr. 23, 2022).
[37] S. Kudchikar, “CQRS Design Pattern C#,” Code with Shadman, Mar. 14, 2020.
https://codewithshadman.com/cqrs-design-pattern-csharp/ (accessed Apr. 23,
2022).
[38] S. Kudchikar, “Mediator Pattern C#,” Code with Shadman, Nov. 06, 2019.
https://codewithshadman.com/mediator-pattern-csharp/ (accessed Apr. 23, 2022).
[39] A. Tarek, “Mediator Design Pattern In .NET C#,” Medium, Jan. 08, 2022.
https://levelup.gitconnected.com/mediator-design-pattern-in-net-c-e1bfcc96789d
(accessed Apr. 23, 2022).
[40] “GraphQL 5.1.1.” https://www.nuget.org/packages/GraphQL/ (accessed May 05,
2022).
[41] “HotChocolate 12.7.0.” https://www.nuget.org/packages/HotChocolate/ (accessed
May 05, 2022).
[42] “BenchmarkDotNet 0.13.1.” https://www.nuget.org/packages/BenchmarkDotNet/
(accessed May 05, 2022).
[43] “Moq 4.17.2.” https://www.nuget.org/packages/Moq/ (accessed May 05, 2022).
[44] Rick-Anderson, “Tutorial: Create a web API with ASP.NET Core.”
https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api (accessed
Apr. 24, 2022).
[45] “GraphQL .NET.”
https://graphql-dotnet.github.io/docs/getting-started/introduction (accessed Apr.
24, 2022).
[46] “Queries.” https://chillicream.com/docs/hotchocolate/defining-a-schema/queries
(accessed Apr. 24, 2022).
[47] “Mutations.”
https://chillicream.com/docs/hotchocolate/defining-a-schema/mutations (accessed
Apr. 24, 2022).
[48] AutoMapper/AutoMapper. AutoMapper, 2022. Accessed: Apr. 23, 2022.
[Online]. Available: https://github.com/AutoMapper/AutoMapper
[49] K. Larkin, S. Gordon, G. Condron, and R. Nowak, “Make HTTP requests using
IHttpClientFactory in ASP.NET Core.”
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests
(accessed Apr. 24, 2022).
[50] J. Calvarro Nelson, S. Smith, and J. van der Til, “Integration tests in ASP.NET
44
Core.” https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests
(accessed Apr. 23, 2022).
[51] moq. Moq, 2022. Accessed: Apr. 23, 2022. [Online]. Available:
https://github.com/moq/moq4
[52] K. Larkin, R. Anderson, T. Dykstra, and S. Smith, “Filters in ASP.NET Core.”
https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters (accessed
May 06, 2022).
[53] R. A. Armstrong, “When to use the Bonferroni correction,” Ophthalmic Physiol.
Opt. J. Br. Coll. Ophthalmic Opt. Optom., vol. 34, no. 5, pp. 502–508, Sep. 2014,
doi: 10.1111/opo.12131.
[54] “AI-Therapy | Statistics for Psychologists | ANOVA.”
https://www.ai-therapy.com/psychology-statistics/hypothesis-testing/anova
(accessed May 16, 2022).
[55] M. Staib, “Say hello to Hot Chocolate 12!,” Say hello to Hot Chocolate 12!, Sep.
27, 2021. https://chillicream.com/blog/2021/09/27/hot-chocolate-12 (accessed
May 04, 2022).
45
Appendix A - Developer backgrounds and Code reviews
Max Fiske
Background
A senior architect and backend developer with nine years of combined practical
development experience at different companies (currently at Forefront Consulting
Group AB). Max has worked primarily with C# and has implemented several
applications using Clean Architecture. Some of Max's previous engagements include
Riksrevisionen, Telia, Kronfågeln and many more.
Code review
I think it looks good. I have some general comments regarding the solution.
Daniel Gustafsson
Background
A senior DevOps and backend developer with twelve years of combined practical
development experience at different companies (currently at Netlight Consulting AB
(publ)). Daniel has worked primarily with C# and has implemented countless API based
applications/wrappers in a Web API environment. Some of Daniels previous
engagements include Elgiganten AB, Betsson AB (publ), Universitets- och
högskolerådet (UHR) and BAE Systems AB.
Code review
The code looks good. Please take a look at the below parts:
- The field “Client” in the ScroW.Infrastructure project has been made public, but
is never used outside the ScroClient class. Consider making it private.
- There is no interface for the Query or Mutation class in the ScroW.API project.
How are these classes instantiated?
46
Joakim Ahlén
Background
A senior fullstack developer with 21 years of experience at Digistrada Sweden AB.
Joakim has worked in several different projects as a consultant, Region Stockholm, Alot
Technology Ltd and Norconsult AB to name a few, and has worked in several different
development stacks, ranging from Javascript/Typescript, Java to C#.
Code review
In general I think it looks good. Some comments:
- Clean and easy to understand code base.
- The Swedish Companies Registration Office is exposing their API in Swedish.
To tackle this I would keep the classes' property names in Swedish, but rename
the Class names to English.
- A large part of the code handles logic for instance, moving data from one class
to another. Another way of handling this would be to use attributes in C# to
instead decorate each individual property and keep one set of classes.
- As I see it you are implementing and exposing the Swedish Companies
Registrations Office API through your own set of endpoints without necessarily
changing the response format. Your solution is good for any party choosing to
implement and apply its own logic/authentication to it.
47
Appendix B - Repository and benchmark outputs
Repository:
https://github.com/LNU-Developer/ScroW-Public
Benchmark Outputs:
https://github.com/LNU-Developer/ScroW-Public/tree/master/tests/ScroW.Api.Perform
anceTests/BenchmarkDotNet.Artifacts
48
Appendix C - Summarized results of experiments
GetBasicInformation (μs) GetBasicInformationOverFetching (μs) GetBasicInformationUnderFetching (μs) PostCreateToken (μs)
Run Rest HotChocolate GraphQLNet Rest HotChocolate GraphQLNet Rest HotChocolate GraphQLNet Rest HotChocolate GraphQLNet
1 291.43 239.24 428.76 273.32 208.74 306.16 544.72 319.48 522.98 276.84 210.13 325.41
2 293.90 237.52 428.49 276.88 209.17 308.89 561.17 319.07 524.18 287.00 210.01 325.55
3 291.00 239.48 429.80 282.66 207.98 308.52 542.83 318.19 526.78 283.46 213.35 326.75
4 287.30 237.78 429.96 275.33 209.78 308.34 546.10 317.68 527.24 279.43 211.00 327.49
5 294.20 237.30 428.99 270.50 208.11 306.12 557.09 316.09 524.27 287.01 209.90 327.65
6 291.69 237.68 428.81 268.18 211.30 305.65 545.70 316.57 523.87 280.75 211.24 327.77
7 289.30 238.52 429.86 280.16 209.70 305.87 542.62 317.18 526.35 284.82 212.03 326.55
8 286.92 238.50 428.63 282.72 211.38 306.77 536.53 318.49 525.73 278.44 208.84 328.53
9 286.90 237.76 430.45 283.34 208.92 311.10 537.64 316.36 526.21 283.24 210.03 326.37
10 290.10 238.53 431.30 274.60 210.25 312.39 556.12 315.41 531.56 280.35 211.35 325.86
11 293.46 237.73 430.21 279.40 209.68 312.78 561.96 316.43 532.93 277.14 213.07 326.17
12 285.51 237.77 430.74 280.96 210.37 312.58 547.25 315.94 529.66 287.23 210.82 325.36
13 287.27 238.19 430.29 278.35 211.54 311.43 537.30 316.89 529.85 280.28 210.74
14 285.58 238.63 280.90 211.89 314.27 549.97 320.48 528.54 294.02 212.02
15 286.39 239.52 278.38 211.50 313.77 315.04 528.07 291.19 210.60
MEAN 289.40 238.28 429.71 277.71 210.02 309.64 547.64 317.29 527.21 283.41 211.01 326.62
N 15 15 13 15 15 15 14 15 15 15 15 12
49