<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wissance</title>
    <description>The latest articles on DEV Community by Wissance (@wissance).</description>
    <link>https://dev.to/wissance</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5452%2F88bfeedb-dc11-4fc9-a0c3-65d18939ec97.png</url>
      <title>DEV Community: Wissance</title>
      <link>https://dev.to/wissance</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wissance"/>
    <language>en</language>
    <item>
      <title>Beyond fmt: Building a Flexible Text Builder in Go with Wissance/stringFormatter</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Tue, 10 Mar 2026 06:18:13 +0000</pubDate>
      <link>https://dev.to/wissance/beyond-fmt-building-a-flexible-text-builder-in-go-with-wissancestringformatter-2ec3</link>
      <guid>https://dev.to/wissance/beyond-fmt-building-a-flexible-text-builder-in-go-with-wissancestringformatter-2ec3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Go is renowned for its performance and simplicity, especially in system programming and web services. Its standard &lt;code&gt;fmt&lt;/code&gt; package is a workhorse for string formatting. However, when building complex text output—like dynamic configuration strings, detailed logs, or formatted reports—developers often find themselves writing repetitive code or wrestling with fmt.Sprintf's verb-based syntax.&lt;/p&gt;

&lt;p&gt;This article explores the &lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;Wissance/stringFormatter&lt;/a&gt; project, an open-source Go module that reimagines text building. It introduces a familiar, template-based approach (think C# or Python) that is not only syntactically convenient but, according to its benchmarks, also outperforms the standard &lt;code&gt;fmt&lt;/code&gt; package in several scenarios. We will dive into its core features, from positional and named argument formatting to advanced data type handling, and see how it positions itself as a true "flexible text builder."&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Features: Template Syntax and Performance
&lt;/h2&gt;

&lt;p&gt;at its heart, &lt;code&gt;stringFormatter&lt;/code&gt; provides a &lt;em&gt;high-performance alternative to fmt for building strings from templates&lt;/em&gt;. Its main appeal is the use of familiar placeholder syntax &lt;code&gt;{0}&lt;/code&gt;, &lt;code&gt;{name}&lt;/code&gt;, which many developers find more readable for complex templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexible Formatting Methods
&lt;/h2&gt;

&lt;p&gt;The library offers two primary methods for text construction, catering to different use cases:&lt;/p&gt;

&lt;h3&gt;
  
  
  Positional Formatting with Format
&lt;/h3&gt;

&lt;p&gt;This function uses indexed placeholders like {0}, {1}. It's straightforward for scenarios where the argument order is clear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {0}, welcome to {1}!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"GoApp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Output: "Hello User, welcome to GoApp!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Named Formatting with &lt;code&gt;FormatComplex&lt;/code&gt;: This method shines when building strings with many parameters or when the template needs to be self-documenting. By passing a &lt;code&gt;map[string]any&lt;/code&gt;, you can use descriptive names like &lt;code&gt;{user}&lt;/code&gt; or &lt;code&gt;{port}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"port"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ssl"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatComplex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Config: user={user}, port={port}, ssl={ssl}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="py"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Config: user=admin, port=8080, ssl=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach makes templates significantly easier to read and maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Argument Formatting
&lt;/h3&gt;

&lt;p&gt;What elevates &lt;code&gt;stringFormatter&lt;/code&gt; from a simple templating tool to a "flexible text builder" is its support for advanced formatting directives directly within the placeholders. You can control the output representation of various data types:&lt;/p&gt;

&lt;p&gt;Numeric Formatting: It supports binary (&lt;code&gt;B&lt;/code&gt;), hexadecimal (&lt;code&gt;X&lt;/code&gt;), and octal (&lt;code&gt;o&lt;/code&gt;) representations, complete with padding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{0:B8} in hex is {0:X2}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nl"&gt;Output:&lt;/span&gt; &lt;span class="err"&gt;"00001111&lt;/span&gt; &lt;span class="nf"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;hex&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Floating-Point Precision: Control decimal places or use scientific notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: {0:F4} or {0:E2}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10.456789&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value: 10.4568 or 1.05e+01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slice Formatting: Join slices with a custom separator effortlessly using the L directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IDs: {0:L-}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Output: "IDs: 1-2-3-4"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code Style Conversion: Dynamically convert between naming conventions like snake_case, camelCase, and kebab-case using the c directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Converted: {0:c:snake}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyVariable"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Output: "Converted: my_variable"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond Formatting: Utility Functions&lt;br&gt;
The project also packages other useful text utilities, reinforcing its role as a comprehensive text manipulation toolkit:&lt;/p&gt;

&lt;p&gt;MapToString: Converts a map into a formatted string, allowing you to define the pattern for each key-value pair.&lt;/p&gt;

&lt;p&gt;SliceToString / SliceSameTypeToString: Provides high-performance slice-to-string conversion, which benchmarks show as significantly faster than manual loops using fmt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;&lt;code&gt;Wissance/stringFormatter&lt;/code&gt;&lt;/a&gt; project offers a compelling alternative for Go developers who frequently engage in complex string building. By combining a clean, template-based syntax with advanced formatting options and a focus on performance, it successfully creates a more flexible and expressive text builder than what's readily available in the standard library.&lt;/p&gt;

&lt;p&gt;Whether you need to generate dynamic configuration files, create human-readable reports, or simply want a faster way to format slices and maps, &lt;code&gt;stringFormatter&lt;/code&gt; provides a robust, well-tested, and high-performance solution. It demonstrates that sometimes, looking beyond the standard library's tools can lead to cleaner code and better performance.&lt;/p&gt;

</description>
      <category>go</category>
      <category>beginners</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Create REST automatically in .Net</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Tue, 02 Sep 2025 18:25:08 +0000</pubDate>
      <link>https://dev.to/wissance/fully-functional-rest-controller-with-one-line-in-net-2d1o</link>
      <guid>https://dev.to/wissance/fully-functional-rest-controller-with-one-line-in-net-2d1o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qxdjicwi2ppr54akf9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1qxdjicwi2ppr54akf9n.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is it and what is it for
&lt;/h3&gt;

&lt;p&gt;Now it is possible to significantly simplify &lt;code&gt;WebAPI&lt;/code&gt; development with the &lt;code&gt;NET&lt;/code&gt; platform (&amp;gt;6). During the last years I was developing my &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;lib&lt;/a&gt; (&lt;strong&gt;Give us a STAR please if you find our solution interesting or useful&lt;/strong&gt;) that allows reducing the amount of code to be written during application development. Among other template processors, this library has the following &lt;strong&gt;&lt;em&gt;differences&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Allows the use of any technology (framework) to work with persistent data (i.e., &lt;code&gt;Entity Framework&lt;/code&gt;, &lt;code&gt;Dapper&lt;/code&gt;, or whatever else) due to separated Core interfaces and one of the built-in implementations; controllers use the &lt;code&gt;IModelManager&lt;/code&gt; interface and do not depend on specific technology at all;&lt;/li&gt;
&lt;li&gt;Fully &lt;code&gt;Swagger-friendly&lt;/code&gt;, and we could display any set of Swagger parameters automatically;&lt;/li&gt;
&lt;li&gt;Contains default implementation of &lt;code&gt;Create&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, and &lt;code&gt;Delete&lt;/code&gt; methods with &lt;code&gt;Entity Framework&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Contains implementation of &lt;code&gt;Bulk Create&lt;/code&gt;, &lt;code&gt;Bulk Update&lt;/code&gt; and &lt;code&gt;Bulk Delete&lt;/code&gt; methods for &lt;code&gt;Entity Framework&lt;/code&gt; implementation;&lt;/li&gt;
&lt;li&gt;Contains an extension that allows you to create any type of controller: &lt;code&gt;ReadOnly&lt;/code&gt; (2 &lt;code&gt;GET&lt;/code&gt; methods), &lt;code&gt;FullCRUD&lt;/code&gt;, or even &lt;code&gt;Bulk&lt;/code&gt; with EntityFramework in just one line of code;&lt;/li&gt;
&lt;li&gt;Contains implementation and examples how to use Manager classes with &lt;code&gt;GRPC&lt;/code&gt; services therefore it is easy to switch from &lt;code&gt;REST&lt;/code&gt; to &lt;code&gt;GRPC&lt;/code&gt; or to have them both in same time with just one Manager class;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generate &lt;code&gt;REST&lt;/code&gt; Controllers in one line
&lt;/h3&gt;

&lt;p&gt;The full example could be find here but very briefly we have the following method that works with ServiceCollection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureWebApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;ServiceProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildServiceProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;stationControllerAssembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSimplifiedAutoController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmptyAdditionalFilters&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ModelContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Station"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ControllerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullCrud&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;
    &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;measureUnitControllerAssembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSimplifiedAutoController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasureUnitEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmptyAdditionalFilters&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ModelContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(),&lt;/span&gt; &lt;span class="s"&gt;"MeasureUnit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ControllerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;
    &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;sensorControllerAssembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSimplifiedAutoController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SensorEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmptyAdditionalFilters&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ModelContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Sensor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ControllerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullCrud&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;
    &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="n"&gt;measurementControllerAssembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSimplifiedAutoController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmptyAdditionalFilters&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
                &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ModelContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Measurement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ControllerType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bulk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILoggerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;

     &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sensorControllerAssembly&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddControllersAsServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stationControllerAssembly&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddControllersAsServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;measureUnitControllerAssembly&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddControllersAsServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddApplicationPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;measurementControllerAssembly&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddControllersAsServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for the visual indentation process of getting Assembly and load controllers from it is separated on 2 lines.&lt;/p&gt;

&lt;p&gt;To implement the following approach, we have to pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DbContext&lt;/code&gt; (Entity Framework), passing generic &lt;code&gt;DbContext&lt;/code&gt; allows you to use any database (&lt;code&gt;Postgres&lt;/code&gt;, &lt;code&gt;MySql&lt;/code&gt;, &lt;code&gt;SqlServer&lt;/code&gt;, …)&lt;/li&gt;
&lt;li&gt;Controller name without suffix Controller&lt;/li&gt;
&lt;li&gt;One of enum value &lt;code&gt;ReadOnly&lt;/code&gt;|&lt;code&gt;FullCrud&lt;/code&gt;|&lt;code&gt;Bullk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filter function (could be null)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ILoggerFactory&lt;/code&gt; for making logs in the controllers
There is only one requirement — every entity class must implement &lt;code&gt;IModelIdentifiable&amp;lt;T&amp;gt;&lt;/code&gt; with property &lt;code&gt;public T Id {get;set;}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What could be done
&lt;/h3&gt;

&lt;p&gt;One-line controllers add simplified logic, but here we lose some control, i.e., we don’t have DTO objects even though Generic &lt;code&gt;IModelManager&lt;/code&gt; does. If you would like &lt;a href="https://github.com/Wissance/WebApiToolkit?tab=readme-ov-file#71-add-new-methods-to-existing-controller" rel="noopener noreferrer"&gt;to add custom methods&lt;/a&gt; to your controller, you should manually create a controller class (this is also very simple with ~10 lines of code; see i.e.). Authentication and authorization could be simply added via attributes, but in one-line controllers we don’t have yet (wait for the new releases).&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This lib was developed by the author and his &lt;a href="https://wissance.com" rel="noopener noreferrer"&gt;LLC&lt;/a&gt;. We also offer our services in quality enterprise software development; please don’t forget to GIVE us a STAR on GitHub.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Override Go app configuration with Environment variable</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Thu, 12 Dec 2024 21:11:17 +0000</pubDate>
      <link>https://dev.to/wissance/override-go-app-configuration-with-environment-variable-50kc</link>
      <guid>https://dev.to/wissance/override-go-app-configuration-with-environment-variable-50kc</guid>
      <description>&lt;h2&gt;
  
  
  How to make containerized applications more flexible ?
&lt;/h2&gt;

&lt;p&gt;For at least 10+ years, we develop applications to work in containers. I won't be considering advantages and disadvantages of this approach but want to focus on the application flexibility. Almost every dependency, i.e. storage containers like &lt;code&gt;Postgres&lt;/code&gt;, &lt;code&gt;MySql&lt;/code&gt;, &lt;code&gt;Redis&lt;/code&gt; a so on, allows us to override most of the configuration properties via environment variables. &lt;code&gt;Docker&lt;/code&gt; containers stimulate us to use environment variables in our containers. But unlike of well-known services programmers develop custom applications on their own approach. I prefer to configure applications using &lt;code&gt;JSON&lt;/code&gt; configuration files. But what should I do if in configuration files 100 and more properties, I can't use Environment variable for each property. Instead of this I decided to use &lt;code&gt;JSON&lt;/code&gt; config file as a template with working default values and override properties at application start if appropriate environment variables were set. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to implement such approach in Go application
&lt;/h2&gt;

&lt;p&gt;Nowadays, we don't use a single Docker image; we prefer to have some orchestration, even something simple like &lt;code&gt;docker-compose&lt;/code&gt;. In &lt;code&gt;docker-compose&lt;/code&gt; we usually create &lt;code&gt;.env&lt;/code&gt;-files. As it was mentioned before, environment variables are working well with well-known images like &lt;code&gt;Postgres&lt;/code&gt; or &lt;code&gt;MySQL&lt;/code&gt;. Consider we are having the following application config (&lt;code&gt;JSON&lt;/code&gt;) that is using as an absolutely working template with the default values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8182&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"http_log"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"http_console_out"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should be able to override any of this value; consider that we should increase log level to debug and enable HTTP logging. For doing this easy, we just have to create technical env variables that have a special name pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;starts with a double underscore __&lt;/li&gt;
&lt;li&gt;contains full property path, i.e. for log level __logging.level .&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using &lt;a href="https://github.com/Wissance/go-config-extender" rel="noopener noreferrer"&gt;this go package,&lt;/a&gt; you could do it absolutely easy, all what you have to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read JSON object from file using  &lt;code&gt;go_config_extender.LoadJSONConfigWithEnvOverride&lt;/code&gt; function (you could see full example in a &lt;a href="https://github.com/Wissance/go-config-extender/blob/master/config_loader_test.go" rel="noopener noreferrer"&gt;test&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Set env file like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# all previous variables
__logging.level="debug"
__logging.http_log=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all, and please give us a &lt;strong&gt;&lt;em&gt;STAR&lt;/em&gt;&lt;/strong&gt; on GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This approach and package could be used not only for containerized applications but for apps running natively too. This package is successfully working on our &lt;a href="https://github.com/Wissance/Ferrum" rel="noopener noreferrer"&gt;authorization server&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>GO writing and reading files with slices</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Thu, 07 Nov 2024 21:10:16 +0000</pubDate>
      <link>https://dev.to/wissance/go-writing-and-reading-files-with-slices-2c8m</link>
      <guid>https://dev.to/wissance/go-writing-and-reading-files-with-slices-2c8m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejtyll9gmury4weu4qe2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejtyll9gmury4weu4qe2.png" alt=" " width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. How possibly we should work with files using slices
&lt;/h3&gt;

&lt;p&gt;Solving my programming tasks recently, I was figured out that there **are no methods that allowed to get slice of lines and save processed lines on disk. Of course, I could split a string into slice of strings and use that slice, but I would like to have some package once and use it easily, whenever I need it.&lt;/p&gt;

&lt;p&gt;Well, I would like to have the following methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ReadAllLines&lt;/code&gt; that reads file content and return a tuple &lt;code&gt;[]string,error&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WriteAllLines&lt;/code&gt; to write slice of strings &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AppendAllLines&lt;/code&gt; to add slice of strings to end of existing file. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.1 New package that meets all requirements
&lt;/h3&gt;

&lt;p&gt;So after I decided what methods such package should have I wrote &lt;code&gt;gfu&lt;/code&gt; (&lt;code&gt;gfu&lt;/code&gt; is stands for Go File Utils) package and would like to share them with, &lt;a href="https://github.com/Wissance/gfu" rel="noopener noreferrer"&gt;see github repo&lt;/a&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1 ReadAllText method
&lt;/h4&gt;

&lt;p&gt;This method does the following:&lt;br&gt;
1 Returns tuple &lt;code&gt;([]string, error)&lt;/code&gt; of result with auto-detect line ending (&lt;code&gt;CR&lt;/code&gt;, &lt;code&gt;LF&lt;/code&gt; or &lt;code&gt;CRLF&lt;/code&gt;);&lt;br&gt;
2 Removes line ending symbols from slice items&lt;br&gt;
3 Removes empty lines if &lt;code&gt;omitEmpty&lt;/code&gt; argument is set to &lt;code&gt;true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gfu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAllLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myFile.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.2 WriteAllText method
&lt;/h4&gt;

&lt;p&gt;This method does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inserts the line separator symbol defined in the 3rd argument of &lt;code&gt;WriteAllLines&lt;/code&gt; func&lt;/li&gt;
&lt;li&gt;Truncates a file if it exists, if not, a file will be created&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: 1,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Michael Ushakov&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"write_all_lines_test.txt"&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gfu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteAllLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2.3 AppendAllText method
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;WriteAllLines&lt;/code&gt; overwrites file content, but what should we do if we need to add some lines portion to an existing file? We should use the &lt;code&gt;AppendAllLines&lt;/code&gt; function that, by signature, is identical to &lt;code&gt;WriteAllLines&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: 1,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Michael Ushakov&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"append_all_lines_test.txt"&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gfu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteAllLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;additionalLines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: 2,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"    &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Alex Petrov&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gfu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppendAllLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Conclusion
&lt;/h3&gt;

&lt;p&gt;All these functions are quite convenient and combined in a small package, also tests were written on all these functions, so we could consider them as reliable. And I go further on my software development journey. don't forget to give us a star if you find this package helpful.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Format a text in GO better than fmt</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Sun, 14 Jan 2024 18:47:23 +0000</pubDate>
      <link>https://dev.to/wissance/format-a-text-in-go-better-than-fmt-do7</link>
      <guid>https://dev.to/wissance/format-a-text-in-go-better-than-fmt-do7</guid>
      <description>&lt;h2&gt;
  
  
  Format a text in GO better then fmt
&lt;/h2&gt;

&lt;p&gt;Looking at the article title, we should clarify what means &lt;strong&gt;better&lt;/strong&gt; and what is &lt;strong&gt;text formatting&lt;/strong&gt;.  Lets start from the last one from these these theses. Text formatting is an important part of programming, prepared text is using in a various tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;description/result of some operations;&lt;/li&gt;
&lt;li&gt;detailed log;&lt;/li&gt;
&lt;li&gt;as a query for data selection in other systems;&lt;/li&gt;
&lt;li&gt;and in many others fields.
Better means that &lt;code&gt;sf&lt;/code&gt; (&lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;wissance.StringFormatter&lt;/a&gt;) has features that &lt;code&gt;fmt&lt;/code&gt; has't (see chapter 1 to see our text formatting approach).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. What can do sf aka wissance.stringFormatter
&lt;/h2&gt;

&lt;p&gt;In our earlier &lt;a href="https://dev.to/evillord666/string-formatting-in-golang-3l7h"&gt;article&lt;/a&gt; we were writing about &lt;code&gt;sf&lt;/code&gt; &lt;strong&gt;&lt;em&gt;convinience&lt;/em&gt;&lt;/strong&gt; (convenience is a thing that is subjective to humans; here, I mean convenience based on my own background). But briefly it is more covnenient to format text like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;userNews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hi &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;{0}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;, see latest news: {1}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"john doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1. You won 1M$ in a lottery, please give us your VISA/MS card data to receive money."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;userNews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hi &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;, see latest news: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"john doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1. You won 1M$ in a lottery, please give us your VISA/MS card data to receive money."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Until&lt;/strong&gt; version &lt;code&gt;1.2.0&lt;/code&gt; &lt;code&gt;sf&lt;/code&gt; was unable to make more precise argument formatting (i.e., use different number notation: &lt;code&gt;bin&lt;/code&gt;, &lt;code&gt;hex&lt;/code&gt;), &lt;strong&gt;starting with 1.2.0 we could do almost all that &lt;code&gt;fmt&lt;/code&gt; supports&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bin number formatting:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{0:B}&lt;/code&gt;, 15 outputs -&amp;gt; &lt;code&gt;1111&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{0:B8}&lt;/code&gt;, 15 outputs -&amp;gt; &lt;code&gt;00001111&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hex number formatting

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{0:X}&lt;/code&gt;, 250 outputs -&amp;gt; &lt;code&gt;fa&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{0:X4}&lt;/code&gt;, 250 outputs -&amp;gt; &lt;code&gt;00fa&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Oct number formatting

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{0:o}&lt;/code&gt;, 11 outputs -&amp;gt; &lt;code&gt;14&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Float point number formatting

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{0:E2}&lt;/code&gt;, 191.0478 outputs -&amp;gt; &lt;code&gt;1.91e+02&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{0:F}&lt;/code&gt;, 10.4567890 outputs -&amp;gt;  &lt;code&gt;10.456789&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{0:F4}&lt;/code&gt;, 10.4567890 outputs -&amp;gt; &lt;code&gt;10.4568&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{0:F8}&lt;/code&gt;, 10.4567890 outputs -&amp;gt; &lt;code&gt;10.45678900&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Percentage output

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{0:P100}&lt;/code&gt;, 12 outputs -&amp;gt; &lt;code&gt;12%&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;sf&lt;/code&gt; has 2 string format methods - &lt;code&gt;Format&lt;/code&gt; and &lt;code&gt;FormatComplex&lt;/code&gt;. Latter also allows passing argument formatting, like for &lt;code&gt;Format&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Let's consider a minimal example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We should build text using the following format &lt;code&gt;"Today tempearture is {temp}, humidity is {hum}&lt;/code&gt; where &lt;code&gt;{temp}&lt;/code&gt; and &lt;code&gt;{hum}&lt;/code&gt; should be replaced with an actual sensor values.&lt;/li&gt;
&lt;li&gt;We would like to specify &lt;code&gt;{temp}&lt;/code&gt; and &lt;code&gt;{hum}&lt;/code&gt; output, i.e., &lt;code&gt;{temp}&lt;/code&gt; should have 4 digits after the dot, and &lt;code&gt;{hum}&lt;/code&gt; must be outputted in percents. After analyzing these requirements, we modified our template as follows: &lt;code&gt;"Today tempearture is {temp:F4}, humidity is {hum:P100}"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Passing &lt;code&gt;12.3456&lt;/code&gt; and &lt;code&gt;60&lt;/code&gt; like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;   &lt;span class="n"&gt;sf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatComplex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Today tempearture is {temp:F4}, humidity is {hum:P100}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"temp"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;12.3456&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hum"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More examples could be found in a &lt;code&gt;FormatComplex&lt;/code&gt; unit test, see in repo and below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestFormatComplexWithArgFormatting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;     &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;
        &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="s"&gt;"numeric_test_1"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: scientific - {mass} / {mass : e2}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"mass"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;191.0784&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: scientific - 191.0784 / 1.91e+02"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"numeric_test_2"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: binary - {bin:B} / {bin : B8}, hexadecimal - {hex:X} / {hex : X4}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"bin"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hex"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: binary - 1111 / 00001111, hexadecimal - fa / 00fa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"numeric_test_3"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: decimal - {float:F} / {float : F4} / {float:F8}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"float"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10.5467890&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the text with an only number formatting: decimal - 10.546789 / 10.5468 / 10.54678900"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatComplex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is clear that &lt;strong&gt;we've got convenient&lt;/strong&gt; (for people with &lt;code&gt;C#&lt;/code&gt;, &lt;code&gt;Python&lt;/code&gt; background) &lt;strong&gt;library for text formatting&lt;/strong&gt;. But we have another advantage - &lt;strong&gt;&lt;em&gt;performance&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;sf&lt;/code&gt; makes formatting **FASTER&lt;/strong&gt; than &lt;code&gt;fmt&lt;/code&gt;**.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Perforamnce Benefits
&lt;/h2&gt;

&lt;p&gt;There is one more important thing that could distinguish a &lt;code&gt;sf&lt;/code&gt; library: it has performance advances, both in formatting cases with argument format specifications and without them. But &lt;code&gt;FormatComplex&lt;/code&gt; is twice faster than &lt;code&gt;fmt&lt;/code&gt;, see picture below with the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8byhrmyz81n7jcb4la7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8byhrmyz81n7jcb4la7.png" alt="sf vs fmt performance comparison" width="800" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Conclusion
&lt;/h2&gt;

&lt;p&gt;Today we could say that there is &lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;one more text formatting utility/lib&lt;/a&gt; that has all &lt;code&gt;fmt&lt;/code&gt; features, and this library processes text faster, which in some cases could be important. Please give us a star on GitHub and subscribe.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>My C# REST run now 250 times faster</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Mon, 29 May 2023 08:33:49 +0000</pubDate>
      <link>https://dev.to/wissance/faster-faster-make-you-api-really-faster-rest-api-with-c-3j95</link>
      <guid>https://dev.to/wissance/faster-faster-make-you-api-really-faster-rest-api-with-c-3j95</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This article is about how to make you API work really faster (&lt;strong&gt;&lt;em&gt;i've got 250 times faster&lt;/em&gt;&lt;/strong&gt;) using &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;our library&lt;/a&gt;, we are going to show it with &lt;a href="https://github.com/Wissance/WeatherControl" rel="noopener noreferrer"&gt;our well-known example of Weather Control REST API&lt;/a&gt;. But in particular, we consider &lt;code&gt;Create&lt;/code&gt; and &lt;code&gt;Update&lt;/code&gt; operations of a standard &lt;code&gt;CRUD&lt;/code&gt; controls. We made previously mentioned library &lt;strong&gt;&lt;em&gt;to reduce amount of code and make a result of the same wrapping DTO&lt;/em&gt; (standartize the data contract)&lt;/strong&gt;. Today, &lt;strong&gt;&lt;em&gt;we need just only &amp;lt; 10 lines&lt;/em&gt;&lt;/strong&gt; of code &lt;strong&gt;&lt;em&gt;to create any controller&lt;/em&gt;&lt;/strong&gt; with &lt;strong&gt;&lt;em&gt;all standard CRUD&lt;/em&gt;&lt;/strong&gt; methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we could speed up REST API
&lt;/h2&gt;

&lt;p&gt;We could make API to perform faster if we are going to &lt;strong&gt;&lt;em&gt;create/update multiple objects at once&lt;/em&gt;&lt;/strong&gt; (&lt;em&gt;bulk api&lt;/em&gt;), sometimes it is possible and &lt;em&gt;could be crucial to achieve a higher performance&lt;/em&gt;. In the mentioned above example, we are using Controller class with Bulk Api (derives from &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;&lt;code&gt;BasicBulkCrudController&lt;/code&gt;&lt;/a&gt;) could be easily created as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Wissance.WeatherControl.WebApi.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MeasurementsSeriesController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BasicBulkCrudController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MeasurementsEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MeasurementsSeriesController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MeasurementsManager&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// this is for basic operations&lt;/span&gt;
            &lt;span class="n"&gt;_manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// this for extended operations&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;MeasurementsManager&lt;/span&gt; &lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code automatically contains 4 mehods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /api/MeasurementsSeries&lt;/code&gt; for getting multiple measurements with paging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /api/MeasurementsSeries/{id}&lt;/code&gt; to get one measurements by id&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /api/bulk/MeasurementsSeries&lt;/code&gt; for creating multiple objects (bulk API);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT /api/bulk/MeasurementsSeries&lt;/code&gt; for updating multiple objects (bulk API);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE /api/bulk/MeasurementsSeries/{idList}&lt;/code&gt; for removing multiple object (bulk API), could be called like &lt;code&gt;~/api/bulk/MeasurementsSeries/id=1&amp;amp;id=2&amp;amp;id=5&lt;/code&gt;
A full example of Manager class with all bulk operations &lt;a href="https://github.com/Wissance/WeatherControl/blob/master/WeatherControl/Wissance.WeatherControl/Managers/MeasurementsManager.cs" rel="noopener noreferrer"&gt;you could see here&lt;/a&gt;. Here i show non-optimal but working example with EntityFramework, even this impl make my code working 250 times faster for creating 10 items (see performance check below method code). So i just add array of MeasurementsEntity and add them to DbSet and after all &lt;strong&gt;&lt;em&gt;make one Save instead of multiple for each object&lt;/em&gt;&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;BulkCreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;measurements&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MeasurementsFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Measurements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRangeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;measurements&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;measurements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MeasurementsFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"An unknown error occurred during measurements creation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MeasurementsDto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;$"An error occurred during measurements update: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;strong&gt;we claim that we made our API working faster&lt;/strong&gt;, let’s &lt;strong&gt;&lt;em&gt;check performance using Python&lt;/em&gt;&lt;/strong&gt;. For a very rough view we made comparison of time elapse for query single bulk endpoint vs sequential call of non-bulk endpoint (worst case) for POST new items as a result &lt;strong&gt;&lt;em&gt;we’got ~250x time performance raise&lt;/em&gt;&lt;/strong&gt; (see Python test &lt;a href="https://github.com/Wissance/WeatherControl/blob/master/perfTests/bulk_api_tests/api_perf_test.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;), see picture below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdnw0ln5cu956uydqmml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdnw0ln5cu956uydqmml.png" alt="Performance Bulk VS Non-bulk comparison" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote simple tests using Python that shows following results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Elapsed time in Non-Bulk REST API with EF is 0.9759984016418457 secs.
Elapsed time in Bulk API with EF is 0.004002094268798828 secs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So just using such a simple technique we made API working faster in a better case (for non-bulk API example) all request could be made parallel in time, but this isn’t solving bottleneck issue with persistence manager (EntityFramework in this current case).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Therefore, we could conclude that REST resources that allow to use bulk operations could be made working faster, and we have prepared boilerplate reusable solution (Wissance.WebApiToolkit). We would be very appreciated if you could &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;give us a star on Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>api</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>programming</category>
    </item>
    <item>
      <title>Make you Go code work 1.5x faster OR even more</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Wed, 12 Oct 2022 04:55:31 +0000</pubDate>
      <link>https://dev.to/wissance/make-you-go-code-work-15x-faster-or-even-more-5fjj</link>
      <guid>https://dev.to/wissance/make-you-go-code-work-15x-faster-or-even-more-5fjj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Performance is &lt;strong&gt;a key thing of everything&lt;/strong&gt;, we (humans) don't like to wait and waste our time. Therefore, sometimes quick solution &lt;strong&gt;as most of the managers&lt;/strong&gt; suppose are better than slow but with good engineering and design. But &lt;strong&gt;&lt;em&gt;today we are not speaking about management&lt;/em&gt;&lt;/strong&gt;, but about code performance. We have a &lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;small text formatting library&lt;/a&gt; that allows us to format text using a template in convenient on our view way. These &lt;a href="https://dev.to/evillord666/string-formatting-in-golang-3l7h"&gt;not only formatting function do what &lt;code&gt;fmt.Sprintf&lt;/code&gt; does in more convenient way but also provide an additional features&lt;/a&gt;. &lt;strong&gt;Previous versions&lt;/strong&gt; of our module were loose in performance to &lt;code&gt;fmt.Sprintf&lt;/code&gt;, but since &lt;strong&gt;&lt;em&gt;1.0.1&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;we are better&lt;/strong&gt;. And today we are going to tell &lt;strong&gt;&lt;em&gt;how to make any golang code work faster&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameters and return values
&lt;/h2&gt;

&lt;p&gt;There are two options to pass either arguments and/or get function result - by pointer and, by value, consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getItemAsStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="c"&gt;// 1st variant&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getItemAsStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;   &lt;span class="c"&gt;// 2nd variant&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getItemAsStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// 3rd variant&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getItemAsStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// 4th variant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to our performance tests, we could conclude the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We've got small performance rise when we pass arguments by pointer because we've got rid of arguments copying.&lt;/li&gt;
&lt;li&gt;We've got performance decrease when we return a pointer to function local variable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, the most optimal variant is the 1st variant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strings
&lt;/h2&gt;

&lt;p&gt;Strings are immutable like in many other programming languages, therefore string concatenation using + operator is a bad idea, i.e. code like this is a very slow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;getItemAsStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every "+" creates a new string object as a result memory usage rise, performance significantly decreases due to spending sufficient time on allocations on new variables.&lt;/p&gt;

&lt;p&gt;There is a better solution for string concat - use strings.Builder, but for a better performance you should initially enlarge buffer (using &lt;code&gt;Grow&lt;/code&gt; function) to prevent it from some / all re-allocs, but if buffer size will be very large there will be a penalty to performance due to initial memory allocation will be slow, therefore you should choose initial buffer size wisely, i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;formattedStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;formattedStr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;templateLen&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cycles
&lt;/h2&gt;

&lt;p&gt;There are 2 ways to iterate over collection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using &lt;code&gt;range&lt;/code&gt; expression
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c"&gt;// do some staff here&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;using traditional &lt;code&gt;for&lt;/code&gt; with 3 expressions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;templateLen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c"&gt;// do some staff here&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2nd variant is better by performance. But there are additional advantages of usage &lt;code&gt;for&lt;/code&gt; with 3 expressions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reduce number of iterations, more iteration code is slower, 
therefore, if you could affect your loop value, do it. This 
can't be achieved with &lt;code&gt;range&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;set initial value for iteration much higher if it is possible, 
i.e. in our case:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;formattedStr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;templateLen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c"&gt;// iterate over i&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using such simple techniques we made our code run 1.5 times faster than it was, and now it works faster even than fmt.Sprintf, see our performance measurements:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3j7nytafa4htelyr8i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3j7nytafa4htelyr8i9.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
. We also suggest you to use &lt;a href="https://github.com/Wissance/stringFormatter" rel="noopener noreferrer"&gt;our library&lt;/a&gt; instead of &lt;code&gt;fmt.Sprintf&lt;/code&gt;, because if you prepare strings for sql queries or something like this, it is important to make them as faster, as it possible. We would be thankful if you give us a star on Github and start to follow our organization here and on Github too.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>go</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>Ferrum is a NextGen Auth Server (almost)</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Thu, 29 Sep 2022 12:09:49 +0000</pubDate>
      <link>https://dev.to/wissance/easily-add-authorization-in-you-apps-in-1-2-min-34n5</link>
      <guid>https://dev.to/wissance/easily-add-authorization-in-you-apps-in-1-2-min-34n5</guid>
      <description>&lt;h2&gt;
  
  
  Authorization and Why we created &lt;code&gt;Ferrum&lt;/code&gt; project
&lt;/h2&gt;

&lt;p&gt;Nowadays, almost all distributed, web or client-server systems have authorization to restrict access only to those users who have rights,&lt;strong&gt;&lt;code&gt;OAuth2.0&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;OpenId-Connect&lt;/code&gt;&lt;/strong&gt; are &lt;strong&gt;&lt;em&gt;most popular and convenient technologies for users authorization&lt;/em&gt;&lt;/strong&gt;. There are some well-known authorization servers, i.e. &lt;code&gt;KeyCloak&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Personally, I like &lt;code&gt;KeyCloak&lt;/code&gt; and &lt;strong&gt;&lt;em&gt;use it where it is possible&lt;/em&gt;&lt;/strong&gt;. About 2 years ago I had to expand my technology stack and I started to write apps using &lt;code&gt;Golang&lt;/code&gt;. These apps are &lt;code&gt;WEB API&lt;/code&gt; that use &lt;code&gt;Authorization&lt;/code&gt; on &lt;code&gt;KeyCloak&lt;/code&gt; server. When &lt;code&gt;API&lt;/code&gt; grows and &lt;strong&gt;&lt;em&gt;become more complicated, it is very important to make automated integration tests&lt;/em&gt;&lt;/strong&gt;. For authorization we using separate from &lt;strong&gt;&lt;em&gt;demo/production&lt;/em&gt;&lt;/strong&gt; server, and it is important to &lt;strong&gt;&lt;em&gt;make code portable&lt;/em&gt;&lt;/strong&gt; to any machine, therefore the most convenient way is &lt;strong&gt;&lt;em&gt;to start all infrastructure before any test and stop when test ends with any persistent data cleanup at the end&lt;/em&gt;&lt;/strong&gt;. Such approach &lt;strong&gt;&lt;em&gt;can't be easily and fast implemented using &lt;code&gt;Keycloak&lt;/code&gt;&lt;/em&gt;&lt;/strong&gt;. Therefore, we created &lt;a href="https://github.com/Wissance/Ferrum" rel="noopener noreferrer"&gt;&lt;code&gt;Ferrum&lt;/code&gt;&lt;/a&gt; authorization server that could be run and stopped from code and with API compatible with  &lt;code&gt;KeyCloak&lt;/code&gt; (with similar behavior and endpoints). Ferrum could be used &lt;strong&gt;&lt;em&gt;not only for tests purposes but also like a full-fledged authorization server&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;&lt;em&gt;a tutorial how easily&lt;/em&gt;&lt;/strong&gt; (in 1-2 minutes) &lt;strong&gt;&lt;em&gt;add authorization&lt;/em&gt;&lt;/strong&gt; to your solutions or how &lt;strong&gt;&lt;em&gt;to write integrational tests&lt;/em&gt;&lt;/strong&gt; on &lt;code&gt;golang&lt;/code&gt; web api also in &lt;strong&gt;1-2 min&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build, configure, and run authorization server
&lt;/h2&gt;

&lt;p&gt;To use &lt;code&gt;Ferrum&lt;/code&gt; as a standalone authorization server, you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build it with &lt;code&gt;go build&lt;/code&gt; (optionally re-generate SSL 
Certificates using &lt;code&gt;go generate&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;Edit very simple &lt;code&gt;config.json&lt;/code&gt; file and specify application 
endpoint;&lt;/li&gt;
&lt;li&gt;Configure you server &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;clients&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; data (for 
more details see next paragraph) in &lt;code&gt;data.json&lt;/code&gt; file (in future 
we'll add store data in NO SQL and user register feature);&lt;/li&gt;
&lt;li&gt;Run executable &lt;code&gt;./Ferrum&lt;/code&gt;, you authorization server is up. 
That's all.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configure server data
&lt;/h2&gt;

&lt;p&gt;Let's consider data configuration more detailed. Data is similar to what we are having on &lt;code&gt;Keycloak&lt;/code&gt;. We have 3 types of objects for version &lt;code&gt;0.1.0&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;realm&lt;/code&gt; = &lt;code&gt;organization&lt;/code&gt; or &lt;code&gt;solution&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client&lt;/code&gt; = project / application inside realm;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every &lt;code&gt;realm&lt;/code&gt; could contain as many &lt;code&gt;clients&lt;/code&gt; and &lt;code&gt;users&lt;/code&gt; as you wish. Realm structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token_expiration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;330&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"refresh_expiration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clients"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"d4dc483d-7d0d-4d2e-a0a0-2d34b55e5a14"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test-service-app-client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"confidential"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fb6Z4RsOadVycQoeQiN57xpu8w8wplYz"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"667ff6a7-3f6b-449b-a217-6fc5d9ac0723"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"email_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"roles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin sys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"preferred_username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"given_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"family_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sys"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"credentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1s2d3f4g90xs"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Restrictions:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For data compatibility with &lt;code&gt;Keycloak&lt;/code&gt; we must have &lt;code&gt;"info"&lt;/code&gt; 
struct in every user with &lt;code&gt;preferred_username&lt;/code&gt; property as a 
login;&lt;/li&gt;
&lt;li&gt;We must have &lt;code&gt;credentials&lt;/code&gt; struct and &lt;code&gt;password&lt;/code&gt; property for
a password check, in future we will store only password 
hashes, and won't store opened passwords.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We could have userinfo of &lt;strong&gt;&lt;em&gt;any complexity&lt;/em&gt;&lt;/strong&gt;  (info structure 
in every user, see upper json) and we should not make some 
changes in the code. I.e. we like to add phone number, easy:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+79996663322"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;props&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"credentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;props&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Simple configuration, it enough 1-2 minutes to prepare server 
data and use;&lt;/li&gt;
&lt;li&gt;Could be running from other application for tests purposes or 
as part of development / production solution.&lt;/li&gt;
&lt;li&gt;API compatible with KeyCloak, you could easily switch to one 
technological stack in future when Ferrum will have all 
necessary features.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Ferrum REST API
&lt;/h2&gt;

&lt;p&gt;For version &lt;code&gt;v0.1.0&lt;/code&gt; we have only 2 endpoints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For issuing a new token 
&lt;code&gt;{baseUrl}/auth/realms/{realm}/protocol/openid-connect/token/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For getting user info that issued this token 
&lt;code&gt;{baseUrl}/auth/realms/{realm}/protocol/openid-connect/userinfo/&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All these REST API  &lt;/p&gt;

&lt;h2&gt;
  
  
  Write integrational tests with go
&lt;/h2&gt;

&lt;p&gt;A full working example could be found in our integation test &lt;a href="https://github.com/Wissance/Ferrum/blob/master/application_test.go" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
Minimal code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// 1. init app, appConfig, testServerData and testKey are variables&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CreateAppWithData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;testServerData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;testKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// 2. start the app&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;// 3. issue new token (taken from func)&lt;/span&gt;
&lt;span class="c"&gt;// baseUrl, realm and other token issue params are variables&lt;/span&gt;
&lt;span class="n"&gt;tokenUrlTemplate&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"{0}/auth/realms/{1}/protocol/openid-connect/token/"&lt;/span&gt;
&lt;span class="n"&gt;tokenUrl&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenUrlTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"grant_type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getTokenData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// 4. get a token and use&lt;/span&gt;
&lt;span class="n"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stationEndpointTemplate&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"{0}/api/station/"&lt;/span&gt;
&lt;span class="n"&gt;getStationsUrl&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stringFormatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stationEndpointTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseServiceUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;getStationsUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// todo(UMV): parse response&lt;/span&gt;
&lt;span class="c"&gt;// 5. stop app&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading, please help our project grow, please add us a github &lt;a href="https://github.com/wissance/Ferrum" rel="noopener noreferrer"&gt;star&lt;/a&gt;&lt;br&gt;
Our project will grow anyway, we are planning to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data store in one of NoSQL databases;&lt;/li&gt;
&lt;li&gt;secure credential store;&lt;/li&gt;
&lt;li&gt;integrations with external users provider like &lt;code&gt;LDAP&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;integrations with social providers like google;&lt;/li&gt;
&lt;li&gt;possibility to authorize using biometrical data.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>github</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>REST API with .Net Easily</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Fri, 24 Jun 2022 08:01:09 +0000</pubDate>
      <link>https://dev.to/wissance/dry-your-web-api-net-core-with-our-toolkit-cbb</link>
      <guid>https://dev.to/wissance/dry-your-web-api-net-core-with-our-toolkit-cbb</guid>
      <description>&lt;h3&gt;
  
  
  1. A short introduction to how to build Web Applications
&lt;/h3&gt;

&lt;p&gt;REST API is a well-known approach &lt;strong&gt;to designing and structuring Web Applications&lt;/strong&gt;. REST is not a protocol or framework it is &lt;strong&gt;a set of concepts&lt;/strong&gt;. Although &lt;strong&gt;there are other approaches&lt;/strong&gt; i.e. it could be used stateful services with one HTTP method verb (SOAP) or use specific full duplex GRPC or WebSockets connection. REST is a very popular approach: it allows us &lt;strong&gt;to use the same methodology for different resources&lt;/strong&gt; (which usually maps on persistent objects, entities). As engineers, we try to optimize our work: we attempt not to repeat ourselves (DRY), simplify (KISS) and so on. Therefore, today i, as a part of the &lt;a href="https://wissance.com" rel="noopener noreferrer"&gt;&lt;code&gt;Wissance&lt;/code&gt;&lt;/a&gt; team, would like to share yet another boilerplate to write REST API easily &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;see our WebAPI Toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. What is REST
&lt;/h3&gt;

&lt;p&gt;REST is a set of concepts that allows us to build a robust API (&lt;a href="https://restfulapi.net/" rel="noopener noreferrer"&gt;for example see this article&lt;/a&gt;).&lt;br&gt;
REST operates with the term "resource" which usually has persistence nature i.e. mapped to database table and so on. Let's see if &lt;strong&gt;&lt;em&gt;we have a user as a resource&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
In REST we have separate HTTP methods to perform different operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CREATE this operation implements with POST HTTP method to resource i.e. &lt;em&gt;&lt;code&gt;POST {base_url}/api/resource&lt;/code&gt;&lt;/em&gt; (i.e. if {base_url} is &lt;a href="http://10.0.0.10/myservice" rel="noopener noreferrer"&gt;http://10.0.0.10/myservice&lt;/a&gt; and resource is &lt;code&gt;user&lt;/code&gt; full uri could look like: &lt;strong&gt;&lt;a href="http://10.0.0.10/myservice/api/user" rel="noopener noreferrer"&gt;http://10.0.0.10/myservice/api/user&lt;/a&gt;&lt;/strong&gt;) During creation we are passing user data as DTO in request body and getting back created user with set identifier and other generated on server fields.&lt;/li&gt;
&lt;li&gt;READ this operation impelements with GET HTTP method and it  usually contains 2 independent endpoints to get collection of entity items and to get one by id i.e. for &lt;code&gt;user&lt;/code&gt; resource:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET {base_url}/api/user&lt;/code&gt; to get a collection&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET {base_url}/api/user/{id}&lt;/code&gt; to get a single item by {id}&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UPDATE this operation implements with PUT HTTP method (in this article PATCH method don't be considered). During a update we are passing resource as DTO through request body i.e. for user resource via url &lt;code&gt;PUT {base_url}/api/user/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DELETE this operation implements with DELETE HTTP method i.e for user resource via url &lt;code&gt;DELETE {base_url}/api/user/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing REST API Service one by one i finally understood what could be made common. We created open source library with this coomon code and it helps us ti significantly reduce amount of any project code. This is our (Wissance LLC) project &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;WebApiToolkit&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Our approach and concepts
&lt;/h3&gt;

&lt;p&gt;First of all we have following REST application architecture concepts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All resources are storing in Entity classes that have required property Id (&lt;code&gt;IModelIdentifiable&amp;lt;T&amp;gt;&lt;/code&gt; &lt;a href="https://github.com/Wissance/WebApiToolkit/blob/master/Wissance.WebApiToolkit/Wissance.WebApiToolkit.Data/Entity/IModelIdentifiable.cs" rel="noopener noreferrer"&gt;interface&lt;/a&gt; in our repo).&lt;/li&gt;
&lt;li&gt;Controllers are just &lt;code&gt;facades&lt;/code&gt; with some preliminary input data processing and validation, all application logic is implementing in appropriate &lt;code&gt;Manager&lt;/code&gt; classes (Those we could use the same Managers for i.e. &lt;code&gt;Signalr&lt;/code&gt; too not only for a REST API). &lt;code&gt;Manager&lt;/code&gt; is an entry point to all complicated operation i.e. integration with other Web services and applications, with persistent storages like &lt;code&gt;Databases&lt;/code&gt; and &lt;code&gt;Queues&lt;/code&gt; and many others and so on is carrying on Manager classes. Controllers could only set Http Status codes and other things like setting some HTTP headers.&lt;/li&gt;
&lt;li&gt;End user interacts with Web API using DTO which could have differences in number of fields in comparison with Entity i.e. we don't like to expose some fields or we do calculation for database fields during processing DTO by Manager.&lt;/li&gt;
&lt;li&gt;We have Factory classes that allow to get DTO from Entity and vise versa.&lt;/li&gt;
&lt;li&gt;All DTO classes are isolated from Entities and others application projects into separate project/assembly this allows us to easily distribute data contract as set of DTO as a Nuget package or directly by Add assembly manually to project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We analyzed all OUR Net Core projects with REST API and &lt;a href="https://github.com/Wissance/WebApiToolkit" rel="noopener noreferrer"&gt;created package with common code&lt;/a&gt;. If you like our package please &lt;strong&gt;&lt;em&gt;don't forget to give us a star, it is important for us&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Let's see how it works in details
&lt;/h3&gt;

&lt;p&gt;Lets consider that we are having a Weather station REST application. &lt;a href="https://github.com/Wissance/WeatherControl" rel="noopener noreferrer"&gt;A full working code example is here&lt;/a&gt;, please don't forget to give a star to a this project too. In this application we have 2 REST resources that associated with 2 database tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;weather station (meta info about where measurements were taken)&lt;/li&gt;
&lt;li&gt;measurements (a set of weather control values: temperature, humidity, atmosphere pressure, e.t.c.) with set of sensors and sensors itself. Lets see how our controllers looks like and what could us give the &lt;code&gt;Wissance.WebToolkit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  4.1 Controllers
&lt;/h4&gt;

&lt;p&gt;In our Toolkit we have 2 base Controller classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For read-only resources - &lt;code&gt;BasicReadController&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;For resources that could be changed or deleted (Full CRUD) - 
&lt;code&gt;BasicCrudController&lt;/code&gt;;
In mentioned upper demo project we used &lt;code&gt;BasicCrudController&lt;/code&gt; as a base class for &lt;code&gt;Weather station&lt;/code&gt; and &lt;code&gt;Measurements&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Wissance.WeatherControl.WebApi.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StationController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BasicCrudController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StationController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StationManager&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// this is for basic operations&lt;/span&gt;
            &lt;span class="n"&gt;_manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// this for extended operations&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;StationManager&lt;/span&gt; &lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As a result we have got:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lightweight controllers, less code as it is possible;&lt;/li&gt;
&lt;li&gt;We don't care about method declaration, routing, status codes processing;&lt;/li&gt;
&lt;li&gt;Create and Update operations wraps response in &lt;code&gt;OperationResultDto&lt;/code&gt; which allow to pass message what was wrong;&lt;/li&gt;
&lt;li&gt;Get resource collection allowes to use pagination&lt;/li&gt;
&lt;li&gt;We could use different identitifer type (int, string, guid) becuse it passed to controller class as a generic type.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This controller expose 5 endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET ~/api/station/[?page={page}&amp;amp;size={size}]&lt;/code&gt; to get collection 
of station where &lt;code&gt;page&lt;/code&gt; and 
&lt;code&gt;size&lt;/code&gt; are optional parameters if they not provided default 
values is used (page=1, size=25);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET ~/api/station/{id}&lt;/code&gt; to get one station by {id};&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST ~/api/station/&lt;/code&gt; to create new station;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT ~/api/station/{id}&lt;/code&gt; to update station with id = {id};&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE ~/api/station/{id}&lt;/code&gt; to delete station with id = {id};&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  4.2 Managers
&lt;/h4&gt;

&lt;p&gt;In our library we have base abstract class &lt;code&gt;ModelManager&lt;/code&gt; that implements &lt;code&gt;IModelManager&lt;/code&gt; interface. To work with &lt;code&gt;BaseCrudController&lt;/code&gt; we should use Manager classes (they should implement IModelManager interface) i.e. StationManager looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StationManager&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ModelManager&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StationManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelContext&lt;/span&gt; &lt;span class="n"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILoggerFactory&lt;/span&gt; &lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loggerFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_modelContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;StationEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"An unknown error occurred during station creation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"An error occurred during station creation: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;UpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationDto&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;StationEntity&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;StationEntity&lt;/span&gt; &lt;span class="n"&gt;existingEntity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existingEntity&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"Station with id: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; does not exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Copy only name, description and positions, create measurements if necessary from MeasurementsManager&lt;/span&gt;
                &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Latitude&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Latitude&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Longitude&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existingEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Longitude&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StationFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"An unknown error occurred during station update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"An error occurred during station update: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OperationResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ModelContext&lt;/span&gt; &lt;span class="n"&gt;_modelContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it is not small as Controller class but it still quite small. We also should mention that we have in &lt;code&gt;ModelManager&lt;/code&gt; abstract classes following additional methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public async Task&amp;lt;OperationResultDto&amp;lt;TRes&amp;gt;&amp;gt; GetAsync(DbSet&amp;lt;TObj&amp;gt; dbSet, TId id, Func&amp;lt;TObj, TRes&amp;gt; createFunc)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public async Task&amp;lt;OperationResultDto&amp;lt;IList&amp;lt;TRes&amp;gt;&amp;gt;&amp;gt; GetAsync&amp;lt;TKey&amp;gt;(DbSet&amp;lt;TObj&amp;gt; dbSet, int page, int size, 
                                                  Func&amp;lt;TObj, bool&amp;gt; filter, Func&amp;lt;TObj, TKey&amp;gt; sort,
                                                  Func&amp;lt;TObj, TRes&amp;gt; createFunc)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;public async Task&amp;gt; DeleteAsync(DbContext context, DbSet dbSet, TId id)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Methods that we mentioned above did not used as a IModelContext methods implementations for one particular reason - we cannot implement univesal authorization to perform all sets of operations in the abstract class due to real cases could very complicated, therefore additional methods were created to help us to implement all required operations in any custom manager class like &lt;code&gt;StationManager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ModelManager abstract class additional features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collection of objects could be &lt;strong&gt;filtered&lt;/strong&gt; using delegate param -  &lt;code&gt;Func&amp;lt;TObj, bool&amp;gt; filter&lt;/code&gt; of &lt;code&gt;GetAsync&lt;/code&gt; method;&lt;/li&gt;
&lt;li&gt;collection of objects could be &lt;strong&gt;sorted&lt;/strong&gt; using delegate param - Func sorted of &lt;code&gt;GetAsync&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We still have what to do (this is not the final version) and in one future release there will be a possibility to pass filter &amp;amp; sort params to appropriate controller and manager methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Additional Wissance.WebToolkit features
&lt;/h3&gt;

&lt;p&gt;In our example project we did not consider following important things and we are trying to describe them here briefly (if this articles get 50 likes we will make second chapter):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication and authorization;&lt;/li&gt;
&lt;li&gt;additional controller methods that expands controller interface 
over a just CRUD controller. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5.1 Authentication and authorization
&lt;/h4&gt;

&lt;p&gt;We could use &lt;code&gt;IHttpContextAccessor _httpContext&lt;/code&gt; to check whether user has access to resource or not, we could get Claim value like this where &lt;code&gt;claimTypeId&lt;/code&gt; is a const like Username and so on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;claimTypeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ClaimsPrincipal&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Claim&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;claimTypeId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claim&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to inject IHttpContextAccessor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IHttpContextAccessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpContextAccessor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5.2 Additional controller methods
&lt;/h4&gt;

&lt;p&gt;There is nothing complicated about extending controllers, if i.e. we have to search weather station in pseudo code we should add in controller something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]/search"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchInTaxServiceAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;FromQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StationDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SearchAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InternalServerError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Conclusion
&lt;/h3&gt;

&lt;p&gt;Thank for reading bro, please rise you star on our github projects (&lt;code&gt;WebApiToolkit&lt;/code&gt; &amp;amp;&amp;amp; &lt;code&gt;WeatherControl&lt;/code&gt;) if you find that they are helpful for you. As a conclusion we also would like to say just a fact: we significantly reduce amount of code and copy-paste code using our &lt;code&gt;WebApiToolkit&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>architecture</category>
      <category>dotnet</category>
      <category>api</category>
    </item>
    <item>
      <title>Easy Websockets testing</title>
      <dc:creator>Ushakov Michael</dc:creator>
      <pubDate>Mon, 28 Mar 2022 17:57:16 +0000</pubDate>
      <link>https://dev.to/wissance/easy-websockets-testing-3d1d</link>
      <guid>https://dev.to/wissance/easy-websockets-testing-3d1d</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Nowadays surfing the web we are used to variety of modern conveniences, one of which is an &lt;em&gt;&lt;strong&gt;ability to contact customer support in real time using online chat&lt;/strong&gt;&lt;/em&gt;. The chat allows you to ask a question about certain product or service, request status and details of your order, consult a technician or file a complaint. All that without ever having to leave the web site.&lt;br&gt;
Of course, such a thing was possible long before the introduction of the WebSocket protocol. Technically you could achieve something like that using Comet, which is a term for a bunch of hacky techniques to implement two-way interaction such as hidden iframe and http polling. Let’s just say this way of doing it was far from ideal. Fortunately, we got WebSocket, which unlike Comet was specifically designed for persistent two-way communication. In this article we are going to briefly consider the protocol’s intricacies and eventually learn how to test it. One more significant addition: this tools should work from private networks, therefore online services are not suitable for us. Dear reader, if you would like to support our cause, please:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subscribe to our &lt;a href="https://medium.com/@m-ushakov" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; channel;&lt;/li&gt;
&lt;li&gt;Star our WebSocket interface testing application’s repository (&lt;a href="https://github.com/Wissance/wstester" rel="noopener noreferrer"&gt;https://github.com/Wissance/wstester&lt;/a&gt;);
Ok, let’s proceed!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The difference between WebSocket and HTTP
&lt;/h2&gt;

&lt;p&gt;In the very beginning the web relied entirely on HTTP which was designed to be stateless and as such &lt;strong&gt;&lt;em&gt;work in the request-response fashion&lt;/em&gt;&lt;/strong&gt;. Basically what it means is, every time you send a request your browser establishes a new connection with the server and once you receive the response &lt;strong&gt;&lt;em&gt;the connection gets terminated&lt;/em&gt;&lt;/strong&gt;. So in case you need to receive notifications or updates from the server there is no way to retain the connection. Your only option is or more accurately was so-called HTTP polling, which is a technique, where your browser repeatedly sends the HTTP request to the server(polls the server) to determine if there was some kinda change. The server either responds immediately or holds the connection until there is an update, the former is known as HTTP long polling.&lt;br&gt;
If you have an online chat on your web site which for whatever reason employs any kinda polling, the client (your browser) has to constantly send HTTP requests in order to check for new messages. Such an approach generates a lot of unnecessary traffic and affects the server load which worsens its performance.&lt;/p&gt;

&lt;p&gt;Now that WebSocket is around you no longer have to build such a monstrosity. Unlike HTTP WebSocket &lt;strong&gt;&lt;em&gt;allows you to establish a persistent full-duplex(both ways) TCP connection which is gonna be alive for as long as you need&lt;/em&gt;&lt;/strong&gt;. So, you can use WebSocket to send and receive messages from the server as if it was a regular TCP connection, which it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The testing tools
&lt;/h2&gt;

&lt;p&gt;So how do we test it?&lt;br&gt;
WebSocket requires an open TCP connection, besides, often frontend and backend are being developed separately and sometimes by different teams. I was tasked with WebSocket interface development many times and as there was no tool to test it I had to do it manually. I always wanted some kinda universal utility I could use regardless of the backend.&lt;br&gt;
Actually it’s possible that I wasn’t looking hard enough for these things. But I assure you, there aren’t a lot of them out there to date. Recently I found out that new versions of Postman support WebSocket protocol. Sounds great, but unfortunately, Postman, just like any tool really &lt;strong&gt;&lt;em&gt;got few disadvantages which make it not necessarily ideal for every situation&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There is something wrong with the way Postman stores its collections. One day something weird happened and I lost all of mine. All the requests just disappeared.&lt;/li&gt;
&lt;li&gt;Postman is a single window application (what if i want to establish many (10+) connections &lt;strong&gt;&lt;em&gt;is it possible or not&lt;/em&gt;&lt;/strong&gt;, i have not check);&lt;/li&gt;
&lt;li&gt;Postman is bloated and heavy;
We developed our solution long before Postman added WebSocket support and considering all the aforementioned Postman flaws it’s still great in its own way.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wstester, our tool to test WebSocket
&lt;/h2&gt;

&lt;p&gt;When we were designing it we decided to make it as simple as possible. You could find it &lt;a href="https://github.com/Wissance/wstester" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key features are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;No need for bundlers, package managers and so on&lt;/em&gt;&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;The code has only &lt;strong&gt;&lt;em&gt;one dependency&lt;/em&gt;&lt;/strong&gt;, which is JQuery and iy could be easily removed;&lt;/li&gt;
&lt;li&gt;No heavy CSS frameworks like Bootstrap, only &lt;strong&gt;&lt;em&gt;one css file&lt;/em&gt;&lt;/strong&gt; (Pure.css);&lt;/li&gt;
&lt;li&gt;Application automatically prepends WebSocket protocol ws:// to 
the address you enter;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Intuitive&lt;/em&gt;&lt;/strong&gt; UI;&lt;/li&gt;
&lt;li&gt;Portable (could be used in any private networks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what the web interface looks like (to test it open tester.html file in your browser):&lt;br&gt;
Here is a little video tutorial (Ru language) with a bit of theory and the testing &lt;a href="https://youtu.be/0s9KrEfjDes" rel="noopener noreferrer"&gt;process demonstration&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The application could use some work. There are few minor issues with the interface a*&lt;em&gt;&lt;em&gt;nd it lacks certain features such as request storage and so on&lt;/em&gt;&lt;/em&gt;&lt;em&gt;. If there were enough people interested in this project (&lt;/em&gt;&lt;em&gt;&lt;em&gt;at least 30 stars on github&lt;/em&gt;&lt;/em&gt;*) we would be willing to spend our time on its further development. Thanks for reading and good luck!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
