Kotlin com Ktor
1. Visão geral
O Ktor é uma estrutura para criar servidores e clientes assíncronos em sistemas conectados usando a poderosa linguagem de programação Kotlin. Isso facilita o desenvolvimento de um aplicativo independente com servidores incorporados.
Neste tutorial, vamos explorar como criar um aplicativo de servidor autônomo usando Ktor.
2. Configurando um aplicativo Ktor
Vamos começar configurando o projeto Ktor. Estaremos usandoGradle, que é a abordagem recomendada e fácil de usar. O Gradle pode ser instalado seguindo as instruções fornecidas emGradle site.
Crie o arquivobuild.gradle:
group 'com.example.kotlin'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.2.40'
ext.ktor_version = '0.9.2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = 'APIServer.kt'
sourceCompatibility = 1.8
compileKotlin { kotlinOptions.jvmTarget = "1.8" }
compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
kotlin { experimental { coroutines "enable" } }
repositories {
mavenCentral()
jcenter()
maven { url "https://dl.bintray.com/kotlin/ktor" }
}
dependencies {
compile "io.ktor:ktor-server-netty:$ktor_version"
compile "ch.qos.logback:logback-classic:1.2.1"
testCompile group: 'junit', name: 'junit', version: '4.12'
}
Importamos o Ktor e o pacote do servidor netty Ktor. Netty é o servidor integrado que usaremos neste exemplo.
3. Construindo o servidor
Criamos nosso aplicativo adicionando código à pasta de origemsrc/main/kotlin.
Aqui, criamos o arquivoAPIServer.kt com o método principal:
fun main(args: Array) {
}
Em seguida, criamos e iniciamos o servidor Netty incorporado:
embeddedServer(Netty, 8080) {
}.start(wait = true)
Ele criará e iniciará o servidor na porta8080. Definimoswait=true no métodostart() para ouvir as conexões.
4. Construindo a API
Vamos adicionar a API. Para lidar com solicitações HTTP, o Ktor fornece o recursoRouting.
Ativamos oRouting feature com um blocoinstall onde podemos definir rotas para caminhos específicos e métodos HTTP:
val jsonResponse = """{
"id": 1,
"task": "Pay waterbill",
"description": "Pay water bill today",
}"""
embeddedServer(Netty, 8080) {
install(Routing) {
get("/todo") {
call.respondText(jsonResponse, ContentType.Application.Json)
}
}
}.start(wait = true)
Neste exemplo, o servidor lidará com uma solicitaçãoGET para o caminho/todoe responderá com um objetotodo JSON. . Aprenderemos mais sobre como instalar recursos na seçãoInstalling Features.
5. Executando o servidor
Para executar o servidor, precisamos de uma tarefa de execução no Gradle:
task runServer(type: JavaExec) {
main = 'APIServer'
classpath = sourceSets.main.runtimeClasspath
}
Para iniciar o servidor, chamamos esta tarefa:
./gradlew runServer
Nossa API pode então ser acessada viahttp://localhost:8080/todo.
6. Instalando recursos
Um aplicativo Ktor normalmente consiste em uma série de recursos. Poderíamos pensar nos recursos como uma funcionalidade injetada no pipeline de solicitação e resposta.
Usando o recursoDefaultHeaders, podemos adicionar cabeçalhos a cada resposta de saída. Routing é outro recurso que nos permite definir rotas para lidar com solicitações, etc.
Também podemos desenvolver nossos recursos e instalá-los.
Vamos dar uma olhada adicionando um cabeçalho personalizado a cada solicitação, instalando o recursoDefaultHeaders:
install(DefaultHeaders) {
header("X-Developer", "example")
}
Da mesma forma, podemos substituir os cabeçalhos padrão definidos pela própria estrutura do Ktor:
install(DefaultHeaders) {
header(HttpHeaders.Server, "My Server")
}
A lista de cabeçalhos padrão disponíveis pode ser encontrada na classeio.ktor.features.DefaultHeaders.
7. Servindo JSON
Construir um JSON stringificado manualmente não é fácil. Ktor fornece um recurso para servir objetos de dados como JSON usando Gson.
Vamos adicionar a dependência Gson em nossobuild.gradle:
compile "io.ktor:ktor-gson:$ktor_version"
Por exemplo, usamos um objeto de dados com o nomeAuthor:
data class Author(val name: String, val website: String)
Em seguida, instalamos o recursogson:
install(ContentNegotiation) {
gson {
setPrettyPrinting()
}
}
Por fim, vamos adicionar uma rota para o servidor que serve a um objeto de autor como JSON:
get("/author") {
val author = Author("example", "example.com")
call.respond(author)
}
A API do autor servirá ao objeto de dados do autor comoJSON.
8. Adicionando controladores
Para entender como lidar com várias solicitações de ação HTTP, vamos criar um aplicativo TODO que permite ao usuário adicionar, excluir, visualizar e listar itens TODO.
Começaremos adicionando uma classe de dadosTodo:
data class ToDo(var id: Int, val name: String, val description: String, val completed: Boolean)
Em seguida, criamos umArrayList para conter vários itensTodo:
val toDoList = ArrayList();
Em seguida, adicionamos os controladores para lidar com solicitações POST, DELETE e GET:
routing() {
route("/todo") {
post {
var toDo = call.receive();
toDo.id = toDoList.size;
toDoList.add(toDo);
call.respond("Added")
}
delete("/{id}") {
call.respond(toDoList.removeAt(call.parameters["id"]!!.toInt()));
}
get("/{id}") {
call.respond(toDoList[call.parameters["id"]!!.toInt()]);
}
get {
call.respond(toDoList);
}
}
}
Adicionamostodoroute e mapeamos as diferentes solicitações de verbos HTTP para esse endpoint.
9. Conclusão
Neste artigo, aprendemos como criar um aplicativo de servidor Kotlin com a estrutura Ktor.
Construímos um pequeno aplicativo de servidor em alguns minutos, sem usar nenhum código clichê.
Como sempre, as amostras de código podem ser encontradasover on GitHub.