> For the complete documentation index, see [llms.txt](https://bytistan.gitbook.io/baytistan/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bytistan.gitbook.io/baytistan/api-create-read-update-delete-islemleri.md).

# API Create Read Update Delete  İşlemleri

## API Ayağa Kaldırma

İlk olarak uygulamayı terminal üzerinden oluşturuyoruz. Tabi önce bir versiyon kontrolü yapmakta fayda var uyumsuzluk olmaması için.

```bash
dotnet --version
8.0.100
```

```bash
dotnet new web
```

Bu kodu çalıştırdığımızda bize şu şekilde bir ağaç yapısı vermesi lazım.

```bash
├── appsettings.Development.json
├── appsettings.json
├── bin
│   └── Debug
├── obj
│   ├── Debug
│   ├── project.assets.json
│   ├── project.nuget.cache
│   ├── web.csproj.nuget.dgspec.json
│   ├── web.csproj.nuget.g.props
│   └── web.csproj.nuget.g.targets
├── Program.cs
├── Properties
│   └── launchSettings.json
├── req.http
├── r.py
├── web.csproj
└── web.sln
```

Üzerinde çalışacağımız dosya `Program.cs` hızlıca içeriğine bakalım.

```csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
```

Derinlemesine girmeden kısaca buradan bahsedecek olursak uygulamayı oluşturduğumuz yer.

```csharp
app.MapGet("/", () => "Hello World!");
```

Bizi asıl ilgilendiren kısım burası aslında. Oluşturduğumuz `app` objesinin `MapGet` metot'dunu kullanarak bir API ucu oluşturuyoruz ve program GET isteklerini dinliyor. `"/"`  bu bizim API ucumuz eğer buraya bir GET isteği atılırsa `"Hello World!"` yazısı isteği atan makinaya dönderilecek.

```csharp
app.Run()
```

`dotnet run` komutu ile uygulamamızı çalıştırdığımızda `dotnet` `Program.cs` içerisindeki kodları derleyip çalıştıracak. `Run()` komutu uygulamamızın sürekli olarak dinleme yapmasını sağlıyor.

Şimdi uygulamayı çalıştıralım ve ne olduğu hakkında biraz daha bilgi sahibi olalım.

```bash
user@hostname:~/web$ dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5225
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/user/web
```

Uygulamayı `dotnet run` kullanarak çalıştırdığımızda server'dan gelen istekleri dinlemeye hazır. Şimdi uygulamanın bize ne söylediğine tek tek bakalım.

```bash
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5225
```

Uygulama hangi url ve port üzerinde dinleme yaptığını söylüyor. `localhost`'da `5225` port'u dinliyor.&#x20;

```bash
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
```

Uygulamayı nasıl kapatabileceğimizi söylüyor. `Ctrl+C`'ye basarak kapatabiliriz.

```bash
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
```

Uygulamanın `Development` yani geliştirme ortamında çalıştığını söylüyor.

```bash
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/user/web
```

Uygulamanın çalıştığı dizinin ne olduğunu'da buradan öğrenebiliriz mesela benimki `/home/user/web` miş.

Uygulamanı çalıştırdığımıza göre ilk http isteğini atıp ne olduğunu görebiliriz. Tabi bir url'ye istek atmanın bir sürü yolu var ama ben linux kullanıyorum ve python ile istek atmam gerek çünkü racon bu.

```python
import requests as r

def post(url,endpoint,data):
    url = url + "/" + endpoint 
    headers = {"Content-type": "application/json"}
    response = r.post(url,json=data, headers=headers)
    print(response.status_code,response.text)

def get(url,endpoint):
    url = url +  "/" + endpoint 
    response = r.get(url)
    print(f"[+] {response.status_code} \n[+] {response.text}")

def delete(url,endpoint):
    url = url + "/" + endpoint
    response = r.delete(url)
    print(f"[+] {response.status_code} \n[+] {response.text}")
```

Şöyle kısa bir python kodumuz var sunucuya `POST` ,`GET` ve `DELETE` istekleri atmamızı sağlıyor ve sunucudan gelen yanıtı terminal ekranına yazdırıyor. Bu kodu uygulamayı çalıştırdığımız dizine .py uzantılı bir dosya olarak kaydediyoruz. Sonrasında python shell'imizi açıyoruz ve sunucumuza bir `GET` isteği yolluyoruz.

```bash
user@hostname:~/web$ python3 
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import r 
>>> url = "http://localhost:5225"
>>> r.get(url,"")
[+] 200 
[+] Hello World!
```

Artık bir çayı hakettik sunucumuz çalışıyor bize `200` status kodu döndü yani istek başarıyla gerçekleşti ve `Hello World!` yazısını dönderdi. Şimdi CRUD işlemlerini gerçekleştirebilmemiz için gerekli API uçlarını sunucumuzda oluşturabiliriz. Tabi bunları yazmadan önce server'ımızı kısa bir süreliğine `Ctrl+C` ile kapatabiliriz.

## CRUD İşlemleri

```csharp
using Microsoft.AspNetCore.Http.HttpResults;
```

İlk olarak ihtiyacımız olan kütüphaneleri içe aktarıyoruz.

<pre class="language-csharp"><code class="lang-csharp"><strong>public record Todo(int Id, string Name, DateTime DueDate, bool IsCompleted);
</strong></code></pre>

Verilerimizi saklamamızı kolaylaştırması için bir record objesi oluşturuyoruz. &#x20;

<mark style="color:red;">**NOT: Yukarıdaki satırı uygulamanızın en alt satırına yazmanız gerek.**</mark>&#x20;

```csharp
var todos = new List<Todo>();
```

API ucumuza gelen verileri saklamak için bir liste oluşturuyoruz. Liste sadece `Todo` türündeki verileri tutabilir.

### Create

İlk API ucumuzu yazma zamanınmız geldi öncelikle CRUD işlemlerinden Create ile başlayalım. Create adından da anlayabileceğiniz üzere verinin oluşturulduğu yerdir. Verinin oluşturulabilmesi için API ucuna veri gönderilmesi gerekir ve bu da POST istekleri ile yapılır. Şimdi POST isteklerini dinleyen bir API ucu yazalım

```csharp
app.MapPost("/todos", (Todo task) => {
    todos.Add(task);
    return TypedResults.Created("/todos/{id}",task);
});
```

Burada kafanıza yatmayan bir yer kalmaması için tek tek inceleyelim.&#x20;

`app` oluşturduğumuz uygulama `MapPost` içerisinde bulunan bir method ve `POST` isteklerini dinlememizi sağlıyor.&#x20;

`"/todos"` verilerin gönderileceği yer yani istek atılacak adress `http://localhost:5225/todos` olmuş oluyor.

`(Todo task)` gelen verinin bizim oluşturduğumuz objeye uygun olması gerekiyor. Gönderilen veriler bizim `task` objemizdeki değerlerle eşitleniyor. (Bunu birazdan POST isteği attığımız zaman daha iyi anlayacaksınız).

`todos.Add(task);` sonrasında bu değerleri daha önceden oluşturduğumuz `todos` listesine `Add()` methodu ile ekliyoruz.

`return TypedResults.Created("/todos/{id}",task);`  Kullanıcıya 201 yanıtını ve oluşturduğu objeyi dönderiyoruz. Yani verinin başarıyla oluşturulduğunu söylüyoruz.

Veriyi oluşturduğumuza göre artık onu okuyabiliriz.

### Read

Şimdi sakladığımız verileri paylaşma zamanı geldi burada iki api ucu yazacağız birinde verinin tamamını diğerinde ise istenilen veriyi döndereceğiz.

```csharp
app.MapGet("/todos", () => todos);
```

Kısa ve öz GET isteklerini `MapGet` ile dinliyoruz ve eğer `"/todos"` uzantısına bir GET isteği gelirse `todos` listemizin tamamını istek atan makinaya döndeririyoruz.

```csharp
app.MapGet("/todos/{id}", Results<Ok<Todo>, NotFound> (int id) => {
    var targetTodo = todos.SingleOrDefault(t => id == t.Id);
    return targetTodo is null ? TypedResults.NotFound() :TypedResults.Ok(targetTodo);
});
```

`"/todos/{id}"` gördüğünüz üzere id kısmı süslü parantez içerisinde ve `(int id)` olarak fonksiyon içerisine parametre olarak verilmiş yani isteği atan kişi şuna benzer bir istek atacak `"/todos/1"`&#x20;

`SingleOrDefault(t => id == t.Id);` methodu aracılığı ile gönderilen get isteğindeki id ile liste içerisindeki objelerden id'si eşleşen var mı diye. Bu arama sonucunda elimize ne geçerse bunu `targetTodo` içerisinde saklıyoruz. Yani sonuç null veya bir objeye eşit olabilir.

Ve son kısımda eğer `targetTodo` `null` ise `TypedResults.NotFound()` 404 status code dönderiyoruz değilse `TypedResults.Ok(targetTodo)` 200 status code ile bulduğumuz objeyi dönderiyoruz.

### Delete

Evet son API ucumuzu yazma zamanı geldi verilerin silineceği API ucu dadada dan.

```csharp
app.MapDelete("/todos/{id}", (int id) => {
    todos.RemoveAll(t => id == t.Id);
    return TypedResults.NoContent();
});
```

`MapDelete` methodu `DELETE` isteklerini dinliyor.  Mesela bir makina böyle bir istek attı `"/todos/1"` `RemoveAll(t => id == t.Id);` methodu ile bu id'ye sahip bütün objeleri liste içerisinden siliyoruz ve `TypedResults.NoContent();` ile 204 status code dönderiyoruz. &#x20;

Aşağıda kodun tamamını bulabilirsiniz.

```csharp
using Microsoft.AspNetCore.Http.HttpResults;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// app.MapGet("/", () => "Hello World!");

var todos = new List<Todo>();

app.MapGet("/todos", () => todos);

app.MapGet("/todos/{id}", Results<Ok<Todo>, NotFound> (int id) => {
    var targetTodo = todos.SingleOrDefault(t => id == t.Id);
    return targetTodo is null ? TypedResults.NotFound() :TypedResults.Ok(targetTodo);
});

app.MapPost("/todos", (Todo task) => {
    todos.Add(task);
    return TypedResults.Created("/todos/{id}",task);
});

app.MapDelete("/todos/{id}", (int id) => {
    todos.RemoveAll(t => id == t.Id);
    return TypedResults.NoContent();
});

app.Run();

public record Todo(int Id, string Name, DateTime DueDate, bool IsCompleted);
```

## Test

Şimdi uygulamayı test etme zamanı.

```bash
user@hostname:~/web$ dotnet run                                                                                               
Building...                                                                                                                              
info: Microsoft.Hosting.Lifetime[14]                                                                                                     
      Now listening on: http://localhost:5225                                                                                            
info: Microsoft.Hosting.Lifetime[0]                                                                                                      
      Application started. Press Ctrl+C to shut down.                                                                                    
info: Microsoft.Hosting.Lifetime[0]                                                                                                      
      Hosting environment: Development                                                                                                   
info: Microsoft.Hosting.Lifetime[0]                                                                                                      
      Content root path: /home/user/web           
```

Sunucumuzu çalıştırdık.

```bash
user@hostname:~/web$ python3                                                                                                  
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux                                                                       
Type "help", "copyright", "credits" or "license" for more information.                                                                   
>>> import r                                                                                                                             
>>> url = "http://localhost:5225"   
```

`python` shell'imizi açıyoruz r.py dosyamızı import ediyoruz sonrasında url'mizi bir değişken içerisine atıyoruz.

Şimdi veri oluşturalım (Create).

```bash
>>> r.post(url,"todos",{"id":1,"name":"Clear kitchen","dueDate":"2024-03-28T00:00:00","isCompleted":False})                              
201 {"id":1,"name":"Clear kitchen","dueDate":"2024-03-28T00:00:00","isCompleted":false}                                                  
>>> r.post(url,"todos",{"id":2,"name":"Hug your mother","dueDate":"2024-03-28T00:00:00","isCompleted":False})                            
201 {"id":1,"name":"Hug your mother","dueDate":"2024-03-28T00:00:00","isCompleted":false}  
```

İki tane veri ekledik 201 status code başarıyla eklendiği anlamına geliyor.

Şimdi eklediğimiz verileri okuma zamanı (Read).

```bash
>>> r.get(url,"todos")                                                                                                                   
[+] 200                                                                                                                                  
[+] [{"id":1,"name":"Clear kitchen","dueDate":"2024-03-28T00:00:00","isCompleted":false},{"id":2,"name":"Hug your mother","dueDate":"2024
-03-28T00:00:00","isCompleted":false}] 
```

Güzel ikiside bir liste içerisinde geldi şimdi sadece id'si 2 olanı alalım.

```bash
>>> r.get(url,"todos/2")                                                                                                                 
[+] 200                                                                                                                                  
[+] {"id":2,"name":"Hug your mother","dueDate":"2024-03-28T00:00:00","isCompleted":false}    
```

Son olarak eklediğimiz verilerden bir tanesini silelim.

```bash
>>> r.delete(url,"todos/1")                                                                                                              
[+] 204                                                                                                                                  
[+]                                                                                                                                      
>>> r.get(url,"todos")                                                                                                                   
[+] 200                                                                                                                                  
[+] [{"id":2,"name":"Hug your mother","dueDate":"2024-03-28T00:00:00","isCompleted":false}]   
```

## Alıştırma

Farkettiyseniz **UPDATE** 'i yazmadık onu siz yazabilirsiniz :)

## Kaynak

{% embed url="<https://www.youtube.com/playlist?list=PLdo4fOcmZ0oWunQnm3WnZxJrseIw2zSAk>" %}
