# CRUD API's in an instant

> Generating fully working CRUD API's in seconds!

2022-03-31 · Tim Cadenbach · https://www.tcdev.de/blog/crud-apis-in-an-instant/

---

<h2>Want an easy way to build a CRUD API?</h2>
<p>Building an API with .NET can be quite time consuming as there is a lot of boilerplate code you usually have to deal with. Controllers, EntityFramework, Models, Routes....<br />and whatever else comes to your mind. However, it doesn't have to be like this and can actually be done lightning fast!</p>
<p><br />What if someone told you, this snippet of just a class is already a fully working API:<br /><br /></p>
<pre class="language-csharp"><code>    [Api("/courses")]
    public class Course : IObjectBase&lt;int&gt;
    {
        public int Id { get; set; }
        public List&lt;Student&gt; Students { get; set; }
        public Teacher Teacher { get; set; }
        public List&lt;DateTime&gt; Schedule { get; set; }
    }</code></pre>
<p></p>
<p>Yes, this is the FULL code you have to write to get a working CRUD API with everything handled out of the box and working magically. Database, Routing, Caching, OpenAPI Definition...its all there, just based on this class.</p>
<p></p>
<p>The same can be done with pure JSON as well!<strong></strong></p>
<pre class="language-javascript"><code>  {
    "name": "Car",
    "route": "/cars",
    "idType": "int",
    "Fields": [
      {
        "name": "Name",
        "type": "String"
      },
      {
        "name": "Description",
        "type": "String"
      },
      {
        "name": "Year",
        "type": "int"
      },
      {
        "name": "Make",
        "type": "virtual Make"
      },
      {
        "name": "MakeId",
        "type": "int"
      }
    ]
  }</code></pre>
<h2>How is this done? What is this magic?</h2>
<p>Creating APIs that fast and simple can be done using my OS Project "APIGenerator". You can find it on Github here -&gt; https://github.com/DeeJayTC/net-dynamic-api<br />A few more details can also be found here -&gt; https://www.tcdev.de/instant-crud-apis-with-net<br /><br />The APIGenerator basically turns any class or JSON Definition that follows my schema, into a full blown API with everything working out of the box.&nbsp;<br />It can be used with any Database supported by EntityFramework.<br /><br /></p>
<h2>Getting Started</h2>
<p><br />Start either a new WebAPI or WebApp project with .NET 6</p>
<p>Download the package:</p>
<pre class="language-csharp"><code>dotnet add package TCDev.ApiGenerator</code></pre>
<p>The APIGenerator comes with a few optional dependencies out of which you need to pick at least the database ones to use the API properly.&nbsp;</p>
<p>Install either of these for the matching database:</p>
<pre class="language-csharp"><code>TCDev.APIGenerator.Data.SQL
TCDev.APIGenerator.Data.SQLite
TCDev.APIGenerator.Data.Postgres
TCDev.APIGenerator.Data.InMemory</code></pre>
<p>And highly recommended to use the OData package as well</p>
<pre class="language-csharp"><code>dotnet add package TCDev.APIGenerator.OData</code></pre>
<h2><br />Setting things up:</h2>
<p>Add the library to program.cs (or startup.cs if you're using the old way!)</p>
<pre class="language-csharp"><code>builder.Services.AddApiGeneratorServices()
                .AddConfig(NameOfRootNodeInAppSettings)
                or
                .AddConfig(new ApiGeneratorConfig() { ... })
                or
                .AddConfig()</code></pre>
<h2><br />Creating your first API</h2>
<p><br /><span data-offset-key="2b011416bb1148cbac9b0ec5ba44a9fd:0">The first and most important thing to note is, you need to implement the "</span><strong data-slate-leaf="true" data-offset-key="2b011416bb1148cbac9b0ec5ba44a9fd:1" class="r-b88u0q">IObjectBase&lt;T&gt;</strong><span data-offset-key="2b011416bb1148cbac9b0ec5ba44a9fd:2" data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMlRoZSUyMGZpcnN0JTIwYW5kJTIwbW9zdCUyMGltcG9ydGFudCUyMHRoaW5nJTIwdG8lMjBub3RlJTIwaXMlMkMlMjB5b3UlMjBuZWVkJTIwdG8lMjBpbXBsZW1lbnQlMjB0aGUlMjAlNUMlMjIlMjIlMkMlMjJtYXJrcyUyMiUzQSU1QiU1RCUyQyUyMnNlbGVjdGlvbnMlMjIlM0ElNUIlNUQlN0QlMkMlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMklPYmplY3RCYXNlJTNDVCUzRSUyMiUyQyUyMm1hcmtzJTIyJTNBJTVCJTdCJTIyb2JqZWN0JTIyJTNBJTIybWFyayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJib2xkJTIyJTJDJTIyZGF0YSUyMiUzQSU3QiU3RCU3RCU1RCUyQyUyMnNlbGVjdGlvbnMlMjIlM0ElNUIlNUQlN0QlMkMlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMiU1QyUyMiUyMGludGVyZmFjZSUyMGZvciUyMHlvdXIlMjBwcmltYXJ5JTIwa2V5LiUyMFRoaXMlMjBpcyUyMG1hZGUlMjB0byUyMGFsbG93JTIweW91JTIwdG8lMjBzZWxlY3QlMjB0aGUlMjB0eXBlJTIwb2YlMjBwcmltYXJ5JTIwa2V5JTIwKGludCUyQyUyMHN0cmluZyUyMG9yJTIwZ3VpZCklMjB5b3UlMjB3YW50JTIwdG8lMjB1c2UlMjBidXQlMjBpcyUyMGFsc28lMjB1c2VkJTIwdG8lMjBnZW5lcmF0ZSUyMHRoZSUyMEFQSSUyMEVuZHBvaW50cyUyMGxhdGVyJTIwb24uJTIwVGhpcyUyMGlzJTIwdGhlJTIwbWluaW11bSUyMHJlcXVpcmVtZW50JTIweW91JTIwaGF2ZSUyMHRvJTIwZG8uJTIwJTIyJTJDJTIybWFya3MlMjIlM0ElNUIlNUQlMkMlMjJzZWxlY3Rpb25zJTIyJTNBJTVCJTVEJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyOTZmYjFmYzMzOWNmNGJkMWJjZDYyMjRkNzU5YmE0MjYlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjI5NDZiNmQ0YTk2ZWY0ZjU4YWUzOTVmNWE1OTY3OGQyMiUyMiU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMjQ4ZDAyODc1YmE0NjQwNGQ5MmFhZmQ5MTk0MzMxMWNmJTIyJTdE">" interface for your primary key. This is made to allow you to select the type of primary key (int, string or guid) you want to use but is also used to generate the API Endpoints later on. This is the minimum requirement you have to do. </span></p>
<p><span data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMkxldHMlMjB3cml0ZSUyMGElMjBjbGFzcyUyMGFzJTIwYSUyMHNhbXBsZSUzQSUyMiUyQyUyMm1hcmtzJTIyJTNBJTVCJTVEJTJDJTIyc2VsZWN0aW9ucyUyMiUzQSU1QiU1RCU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMmNjZTMxNDFhM2I4ZTQ5YzZiYThlNGZjOGRiZDUxZjE3JTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyY2U4MTZkYzU4MDEwNDBkNmI5YmRhYmQ0OTZjZTBiZGUlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjI5ZmY3N2Y0YjAxOWQ0MWFhOWE3YjZlZDNmZWVjYjdmMyUyMiU3RA==">Lets write a class as a sample:</span></p>
<pre class="language-csharp"><code>public class Person : IObjectBase&lt;int&gt; {

    public int Id {get;set;}
    public string Name {get;set;}
    public DateTime DateOfBirth {get;set;}
}</code></pre>
<div>
<div data-rnw-media-class="1472-195__1470-_b1430-195" class="css-1dbjc4n r-1ro0kt6 r-18u37iz r-16y2uox r-1wbh5a2 r-1777fci">
<div class="css-1dbjc4n r-1ro0kt6 r-16y2uox r-1wbh5a2 r-1l5ssaz">
<div data-rnw-media-class="1471-__1469" class="css-1dbjc4n">
<div class="css-1dbjc4n">
<div data-key="d70274fca8d1439a80ff6b00fef39fd0" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1mlwlqe r-eqz5dr r-1q142lx r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-xd6kpl r-tskmnb r-1yzf0co r-bnwqim r-417010">
<div data-block-content="d70274fca8d1439a80ff6b00fef39fd0" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1ro0kt6 r-eqz5dr r-16y2uox r-1wbh5a2 r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-bnwqim r-417010">
<div dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"></div>
<p dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"><span data-key="c762ece396914b5cb5adc1e5431001b8">Now, this is enough for our underlying systems to generate the database tables for this specific class and you can theoretically query and store data for it. Yet this is not an API Endpoint yet. </span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div data-rnw-media-class="1472-195__1470-_b1430-195" class="css-1dbjc4n r-1ro0kt6 r-18u37iz r-16y2uox r-1wbh5a2 r-1777fci">
<div class="css-1dbjc4n r-1ro0kt6 r-16y2uox r-1wbh5a2 r-1l5ssaz">
<div data-rnw-media-class="1471-__1469" class="css-1dbjc4n">
<div class="css-1dbjc4n">
<div data-key="0b1f841b486248438bf7a35c17bd29f2" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1mlwlqe r-eqz5dr r-1q142lx r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-xd6kpl r-tskmnb r-1yzf0co r-bnwqim r-417010">
<div data-block-content="0b1f841b486248438bf7a35c17bd29f2" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1ro0kt6 r-eqz5dr r-16y2uox r-1wbh5a2 r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-bnwqim r-417010">
<div dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"><span data-key="60c50a9b251a4b0db5bde5a79433723c">To have a class appear in swagger and have all the needed CRUD endpoints generated you have to actually mark it as an API, this is quite easy thanks to our API Attribute. </span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMk5vdyUyQyUyMHRoaXMlMjBpcyUyMGVub3VnaCUyMGZvciUyMG91ciUyMHVuZGVybHlpbmclMjBzeXN0ZW1zJTIwdG8lMjBnZW5lcmF0ZSUyMHRoZSUyMGRhdGFiYXNlJTIwdGFibGVzJTIwZm9yJTIwdGhpcyUyMHNwZWNpZmljJTIwY2xhc3MlMjBhbmQlMjB5b3UlMjBjYW4lMjB0aGVvcmV0aWNhbGx5JTIwcXVlcnklMjBhbmQlMjBzdG9yZSUyMGRhdGElMjBmb3IlMjBpdC4lMjBZZXQlMjB0aGlzJTIwaXMlMjBub3QlMjBhbiUyMEFQSSUyMEVuZHBvaW50JTIweWV0LiUyMCUyMiUyQyUyMm1hcmtzJTIyJTNBJTVCJTVEJTJDJTIyc2VsZWN0aW9ucyUyMiUzQSU1QiU1RCU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMmEwZTc3MmIxMjM2MDRmNGQ4NjMwMDMxNmE0ZWQ1Y2VhJTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyNWZkNzgzMWNhN2Y2NGVkZjkxODY2YjY1YmMxNjQ0NzUlMjIlN0QlMkMlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMlRvJTIwaGF2ZSUyMGElMjBjbGFzcyUyMGFwcGVhciUyMGluJTIwc3dhZ2dlciUyMGFuZCUyMGhhdmUlMjBhbGwlMjB0aGUlMjBuZWVkZWQlMjBDUlVEJTIwZW5kcG9pbnRzJTIwZ2VuZXJhdGVkJTIweW91JTIwaGF2ZSUyMHRvJTIwYWN0dWFsbHklMjBtYXJrJTIwaXQlMjBhcyUyMGFuJTIwQVBJJTJDJTIwdGhpcyUyMGlzJTIwcXVpdGUlMjBlYXN5JTIwdGhhbmtzJTIwdG8lMjBvdXIlMjBBUEklMjBBdHRyaWJ1dGUuJTIwJTIyJTJDJTIybWFya3MlMjIlM0ElNUIlNUQlMkMlMjJzZWxlY3Rpb25zJTIyJTNBJTVCJTVEJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyNjBjNTBhOWIyNTFhNGIwZGI1YmRlNWE3OTQzMzcyM2MlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjIwYjFmODQxYjQ4NjI0ODQzOGJmN2EzNWMxN2JkMjlmMiUyMiU3RCUyQyU3QiUyMm9iamVjdCUyMiUzQSUyMmJsb2NrJTIyJTJDJTIydHlwZSUyMiUzQSUyMnBhcmFncmFwaCUyMiUyQyUyMmlzVm9pZCUyMiUzQWZhbHNlJTJDJTIyZGF0YSUyMiUzQSU3QiU3RCUyQyUyMm5vZGVzJTIyJTNBJTVCJTdCJTIyb2JqZWN0JTIyJTNBJTIydGV4dCUyMiUyQyUyMmxlYXZlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMmxlYWYlMjIlMkMlMjJ0ZXh0JTIyJTNBJTIyTGV0cyUyMGZ1cnRoZXIlMjBleHRlbmQlMjB0aGUlMjBjbGFzcyUyMHRvJTIwd29yayUyMGFzJTIwYW4lMjBBUEklMjIlMkMlMjJtYXJrcyUyMiUzQSU1QiU1RCUyQyUyMnNlbGVjdGlvbnMlMjIlM0ElNUIlNUQlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjJhY2JiYmUwMzkwNjk0OTk2YTRiM2I1MGZkZjZiOGZmNCUyMiU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMjc5NmNhYzA5MmNmZTQ4NjBiZWQ1NjE3MGQ1YmY2ZDUxJTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyMWFlODFjMzhmNzE2NGI5NDljOWMwMDJkYWJjZjk1NWQlMjIlN0Q=">
<div data-rnw-media-class="1472-195__1470-_b1430-195" class="css-1dbjc4n r-1ro0kt6 r-18u37iz r-16y2uox r-1wbh5a2 r-1777fci">
<div class="css-1dbjc4n r-1ro0kt6 r-16y2uox r-1wbh5a2 r-1l5ssaz">
<div data-rnw-media-class="1471-__1469" class="css-1dbjc4n">
<div class="css-1dbjc4n">
<div data-key="796cac092cfe4860bed56170d5bf6d51" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1mlwlqe r-eqz5dr r-1q142lx r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-xd6kpl r-tskmnb r-1yzf0co r-bnwqim r-417010">
<div data-block-content="796cac092cfe4860bed56170d5bf6d51" class="r-1oszu61 r-1xc7w19 r-1phboty r-1yadl64 r-deolkf r-6koalj r-1ro0kt6 r-eqz5dr r-16y2uox r-1wbh5a2 r-crgep1 r-ifefl9 r-bcqeeo r-t60dpp r-bnwqim r-417010">
<p dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"><span data-key="acbbbe0390694996a4b3b50fdf6b8ff4">Lets further extend the class to work as an API</span></p>
<div dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"><span data-key="acbbbe0390694996a4b3b50fdf6b8ff4"></span></div>
<div dir="auto" class="css-901oao r-z9jf92 r-gg6oyi r-ubezar r-16dba41 r-135wba7 r-fdjqy7 r-1xnzce8"><span data-key="acbbbe0390694996a4b3b50fdf6b8ff4"></span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<pre class="language-csharp"><code>[Api("/people")
public class Person : IObjectBase&lt;int&gt; {

    public int Id {get;set;}
    public string Name {get;set;}
    public DateTime DateOfBirth {get;set;}
}</code></pre>
<p><br /><span data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMlNlZSUyMGhvdyUyMHdlJTIwb25seSUyMGFkZGVkJTIwdGhhdCUyMGF0dHJpYnV0ZSUzRiUyMFllcyUyQyUyMHRoaXMlMjBpcyUyMGVub3VnaCUyMHRvJTIwdHVybiUyMHRoZSUyMGNsYXNzJTIwaW50byUyMGElMjBmdWxsJTIwQVBJISUyMiUyQyUyMm1hcmtzJTIyJTNBJTVCJTVEJTJDJTIyc2VsZWN0aW9ucyUyMiUzQSU1QiU1RCU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMjkxN2FjMGQ1MTIyMDQxNTRiNTk2YTM5YzRlNTMxNWNkJTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyZjA3YzA3YjkyMjljNGY2OWI4ZGIyYjAwNDc1ZGNmYjYlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjIzYWE2MzliZWU1YWM0NDEyYmJmZjRlYWFiNDZlOTk0NiUyMiU3RA==">See how we only added that attribute? Yes, this is enough to turn the class into a full API! If you start your App now you should be greeted by Swagger with a fully working API!</span><br /><br /></p>
<p></p>
<p></p>
<p>For more details and guides just jump straight to the docs! -&gt;</p>
<h2><a href="https://www.tcdev.de" rel="follow">https://www.tcdev.de</a>/</h2>
<p>Let me know what you think, any questions..just jump in the comments below!</p>
<p></p>
