How to Create a RESTful CRUD API with Ktor and MongoDB


Here’s how you can build RESTful CRUD APIs using Ktor and MongoDB for a basic application:


Step 1: Create Ktor Project

  1. Set Up Dependencies in your build.gradle.kts:

    dependencies {
        implementation("io.ktor:ktor-server-core:2.3.3")
        implementation("io.ktor:ktor-server-netty:2.3.3")
        implementation("org.mongodb:mongodb-driver-sync:4.10.2")
        implementation("ch.qos.logback:logback-classic:1.4.11")
    }
  2. Main Application File (Application.kt):

    import io.ktor.application.*
    import io.ktor.features.ContentNegotiation
    import io.ktor.http.HttpStatusCode
    import io.ktor.jackson.jackson
    import io.ktor.response.respond
    import io.ktor.routing.*
    import io.ktor.server.engine.embeddedServer
    import io.ktor.server.netty.Netty
    import io.ktor.features.StatusPages
    import org.litote.kmongo.*
    import io.ktor.request.receive
    import io.ktor.http.HttpMethod
    
    // MongoDB client setup
    val client = KMongo.createClient()
    val database = client.getDatabase("ktor_db")
    val collection = database.getCollection<Person>()
    
    data class Person(val id: String? = null, val name: String, val age: Int)
    
    fun Application.module() {
        install(ContentNegotiation) {
            jackson { }
        }
    
        install(StatusPages) {
            exception<Throwable> { cause ->
                call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage)
            }
        }
    
        routing {
            route("/persons") {
                // Create Person
                post {
                    val person = call.receive<Person>()
                    collection.insertOne(person)
                    call.respond(HttpStatusCode.Created, person)
                }
    
                // Get All Persons
                get {
                    val persons = collection.find().toList()
                    call.respond(persons)
                }
    
                // Get Person by ID
                get("{id}") {
                    val id = call.parameters["id"]
                    val person = collection.findOneById(id)
                    if (person != null) {
                        call.respond(person)
                    } else {
                        call.respond(HttpStatusCode.NotFound, "Person not found")
                    }
                }
    
                // Update Person
                put("{id}") {
                    val id = call.parameters["id"]
                    val updatedPerson = call.receive<Person>()
                    val updateResult = collection.updateOneById(id, updatedPerson)
                    if (updateResult.modifiedCount > 0) {
                        call.respond(HttpStatusCode.OK, updatedPerson)
                    } else {
                        call.respond(HttpStatusCode.NotFound, "Person not found")
                    }
                }
    
                // Delete Person
                delete("{id}") {
                    val id = call.parameters["id"]
                    val deleteResult = collection.deleteOneById(id)
                    if (deleteResult.deletedCount > 0) {
                        call.respond(HttpStatusCode.NoContent)
                    } else {
                        call.respond(HttpStatusCode.NotFound, "Person not found")
                    }
                }
            }
        }
    }

Step 2: MongoDB Setup

  1. MongoDB Connection: Use KMongo, a Kotlin-friendly MongoDB library, to interact with MongoDB.

    • KMongo.createClient() creates a MongoDB client.
    • database.getCollection<Person>() retrieves the collection where your data will be stored.
  2. CRUD Operations:

    • Create: collection.insertOne(person) to insert a new Person document.
    • Read (All): collection.find().toList() fetches all Person records.
    • Read (By ID): collection.findOneById(id) fetches a specific Person by ID.
    • Update: collection.updateOneById(id, updatedPerson) to update a document by ID.
    • Delete: collection.deleteOneById(id) to delete a document by ID.

Step 3: Start the Ktor Server

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

Step 4: Test the APIs

1. Create a Person (POST):

curl -X POST http://localhost:8080/persons \
  -H "Content-Type: application/json" \
  -d '{"name": "John Doe", "age": 30}'

2. Get All Persons (GET):

curl http://localhost:8080/persons

3. Get a Person by ID (GET):

curl http://localhost:8080/persons/{id}

4. Update a Person (PUT):

curl -X PUT http://localhost:8080/persons/{id} \
  -H "Content-Type: application/json" \
  -d '{"name": "John Smith", "age": 32}'

5. Delete a Person (DELETE):

curl -X DELETE http://localhost:8080/persons/{id}

Step 5: Handling Responses and Errors

  • The StatusPages feature is used to handle exceptions globally. If an error occurs (e.g., invalid input), it returns a 500 HTTP error with the error message.
  • You can customize this for more specific error handling as needed.

With this, you've created a basic Ktor application with MongoDB integration to perform RESTful CRUD operations for managing Person records. You can extend this by adding more complex functionality, such as authentication, validation, and more sophisticated error handling.

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