Simple CRUD Application using Ktor and Angular


To implement a simple CRUD (Create, Read, Update, Delete) application using Ktor 3 (a Kotlin web framework) for the backend and Angular for the frontend, follow these general steps:

1. Backend Setup (Ktor)

1.1. Create a Ktor 3 Project

First, create a Ktor project. You can use the Ktor project generator (https://start.ktor.io/) or manually set up the project with Gradle or Maven. Ensure you have the required dependencies for Ktor 3, such as:

  • ktor-server-core
  • ktor-server-netty (for the server)
  • ktor-server-content-negotiation (for JSON serialization)
  • ktor-server-cors (for cross-origin requests)

1.2. Install Dependencies

Add the necessary dependencies in the build.gradle.kts file:

plugins {
    kotlin("jvm") version "1.9.0"
    id("io.ktor.plugin") version "3.0.0"
}

dependencies {
    implementation("io.ktor:ktor-server-core:3.0.0")
    implementation("io.ktor:ktor-server-netty:3.0.0")
    implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.0")
    implementation("io.ktor:ktor-server-content-negotiation:3.0.0")
    implementation("io.ktor:ktor-server-cors:3.0.0")
}

1.3. Create Ktor Routes

Next, define the CRUD routes for the backend:

import io.ktor.application.*
import io.ktor.features.ContentNegotiation
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.delete
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.features.ContentNegotiation
import io.ktor.serialization.kotlinx.json
import kotlinx.serialization.Serializable
import io.ktor.application.install

@Serializable
data class Item(val id: Int, val name: String)

val items = mutableListOf<Item>()

fun Application.module() {
    install(ContentNegotiation) {
        json()
    }

    routing {
        route("/items") {
            // Create item
            post {
                val item = call.receive<Item>()
                items.add(item)
                call.respond(HttpStatusCode.Created, item)
            }

            // Get all items
            get {
                call.respond(items)
            }

            // Update item
            put("{id}") {
                val id = call.parameters["id"]?.toInt() ?: return@put call.respond(HttpStatusCode.BadRequest)
                val updatedItem = call.receive<Item>()
                val index = items.indexOfFirst { it.id == id }
                if (index != -1) {
                    items[index] = updatedItem
                    call.respond(HttpStatusCode.OK, updatedItem)
                } else {
                    call.respond(HttpStatusCode.NotFound)
                }
            }

            // Delete item
            delete("{id}") {
                val id = call.parameters["id"]?.toInt() ?: return@delete call.respond(HttpStatusCode.BadRequest)
                val index = items.indexOfFirst { it.id == id }
                if (index != -1) {
                    items.removeAt(index)
                    call.respond(HttpStatusCode.NoContent)
                } else {
                    call.respond(HttpStatusCode.NotFound)
                }
            }
        }
    }
}

fun main() {
    embeddedServer(Netty, port = 8080, module = Application::module).start(wait = true)
}

1.4. Run the Ktor Application

Run your Ktor backend using:

./gradlew run

Your Ktor server will start on port 8080, with CRUD routes for managing items.


2. Frontend Setup (Angular)

2.1. Create an Angular Project

Generate a new Angular project:

ng new angular-crud-app
cd angular-crud-app

2.2. Install Angular HTTP Client

Ensure the HttpClientModule is imported in your app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';  // Import HttpClientModule

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

2.3. Create a Service to Handle CRUD Operations

Create a service to interact with the backend API:

ng generate service item

In item.service.ts, define the CRUD methods:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface Item {
  id: number;
  name: string;
}

@Injectable({
  providedIn: 'root',
})
export class ItemService {
  private apiUrl = 'http://localhost:8080/items';

  constructor(private http: HttpClient) {}

  getItems(): Observable<Item[]> {
    return this.http.get<Item[]>(this.apiUrl);
  }

  createItem(item: Item): Observable<Item> {
    return this.http.post<Item>(this.apiUrl, item);
  }

  updateItem(id: number, item: Item): Observable<Item> {
    return this.http.put<Item>(`${this.apiUrl}/${id}`, item);
  }

  deleteItem(id: number): Observable<void> {
    return this.http.delete<void>(`${this.apiUrl}/${id}`);
  }
}

2.4. Create a Component to Display and Manage Items

Create a component to display the list of items and interact with the backend:

ng generate component item-list

In item-list.component.ts, add the logic for CRUD operations:

import { Component, OnInit } from '@angular/core';
import { ItemService, Item } from '../item.service';

@Component({
  selector: 'app-item-list',
  templateUrl: './item-list.component.html',
  styleUrls: ['./item-list.component.css'],
})
export class ItemListComponent implements OnInit {
  items: Item[] = [];

  constructor(private itemService: ItemService) {}

  ngOnInit(): void {
    this.loadItems();
  }

  loadItems(): void {
    this.itemService.getItems().subscribe((data) => {
      this.items = data;
    });
  }

  createItem(name: string): void {
    const newItem: Item = { id: Date.now(), name };
    this.itemService.createItem(newItem).subscribe(() => this.loadItems());
  }

  updateItem(id: number, name: string): void {
    const updatedItem: Item = { id, name };
    this.itemService.updateItem(id, updatedItem).subscribe(() => this.loadItems());
  }

  deleteItem(id: number): void {
    this.itemService.deleteItem(id).subscribe(() => this.loadItems());
  }
}
In i

In item-list.component.html, create a simple interface for CRUD operations:

<div>
  <h1>Item List</h1>
  <ul>
    <li *ngFor="let item of items">
      {{ item.name }} <button (click)="deleteItem(item.id)">Delete</button>
      <button (click)="updateItem(item.id, 'Updated Name')">Update</button>
    </li>
  </ul>

  <input #newItemName type="text" placeholder="New Item Name" />
  <button (click)="createItem(newItemName.value)">Create Item</button>
</div>

2.5. Run the Angular Application

Run the Angular application with:

ng serve

Your Angular frontend will be running on http://localhost:4200, and it will interact with the Ktor backend for CRUD operations.


3. Test the Application

  • Start the Ktor backend by running the Gradle run task.
  • Start the Angular frontend with ng serve.
  • Access the Angular app at http://localhost:4200 to manage items through the Ktor API.

This setup provides a basic CRUD implementation using Ktor and Angular. You can extend it with features like form validation, error handling, and more complex business logic.

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete