Search code examples
javascriptnode.jskotlinkotlin-js-interop

Creating simple Node server with Kotlin


I'm trying to create a simple Node server using Kotlin to replicate the basic sample here:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

So, I did the below:

Created new folder, named it node

Create npm package using npm init

Created new gradle project using this command: gradle init --type java-library

Deleted the src/main and the src/test folders

Created the src/kotlin and src/resources folders

Replaced the content of the build.gradle file by:

buildscript {
    ext.kotlin_version = '1.2.21'
    ext.node_dir = 'node'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 
    }
}
apply plugin: 'kotlin2js'

repositories {     jcenter()    }

dependencies {
    def kotlinx_html_version = "0.6.8"
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

sourceSets.main {
   kotlin.srcDirs += 'src/kotlin'
   resources.srcDirs += 'src/resources'
}

compileKotlin2Js.kotlinOptions {
   outputFile = "${projectDir}/${node_dir}/index.js"
   moduleKind = "commonjs" 
   sourceMap = true
}

clean.doFirst() {
    delete("${node_dir}")
}

Installed kotlin from npm as local version: npm i kotlin Note: installing it globally npm i -g kotlin did not work at all.

Note: I did it also using npm install or npm i after adding the dependencies to the package.json file, which became like:

{
  "name": "kotlin-node-app",
  "version": "1.0.0",
  "description": "Node Application built with Kotlin Lang",
  "main": "index.js",
  "dependencies": {
    "kotlin": "^1.2.21"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "kotlin"
  ],
  "author": "Hasan Yousef",
  "license": "ISC"
}

Created my file at src/kotlin/Main.Kt as below:

external fun require(module:String):dynamic

fun main(args: Array<String>) {
    println("Hello JavaScript!")

    val http = require("http")
    val hostname = "127.0.0.1"
    val port = 3000

    println("Server will try to run at http://${hostname}:${port}/")

    val server = http.createServer{req, res -> 
        res.statusCode = 200
        res.setHeader("Content-Type", "text/plain")
        res.end("Hello World\n")
    }

    server.listen{port, hostname ->
       println("Server running at http://${hostname}:${port}/")
    }
}

Built the project using gradle build and got the index.js file generated as required.

Once running the file node index.js it did not work, and looks the app not reading the values of port and host upon calling the server.listen.

The structure, code and output of the app are in this screenshot:

enter image description here

The index.js generated is:

(function (_, Kotlin) {
  'use strict';
  var println = Kotlin.kotlin.io.println_s8jyv4$;
  var Unit = Kotlin.kotlin.Unit;
  function main$lambda(req, res) {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    return res.end('Hello World\n');
  }
  function main$lambda_0(port, hostname) {
    println('Server running at http://' + hostname + ':' + port + '/');
    return Unit;
  }
  function main(args) {
    println('Hello JavaScript!');
    var http = require('http');
    var hostname = '127.0.0.1';
    var port = 3000;
    println('Server will try to run at http://127.0.0.1:3000/');
    var server = http.createServer(main$lambda);
    server.listen(main$lambda_0);
  }
  _.main_kand9s$ = main;
  main([]);
  Kotlin.defineModule('index', _);
  return _;
}(module.exports, require('kotlin')));

//# sourceMappingURL=index.js.map

Solution

  • I just found it, it is in calling server.listen

    Considering the syntax as 'server.listen(port, hostname, backlog, callback);'

    In Kotlin it should be:

    server.listen(port, hostname, fun() { 
        println("Server running at http://${hostname}:${port}/")
    })
    

    So, the below code worked perfectly with me now:

    external fun require(module:String):dynamic
    
    fun main(args: Array<String>) {
        println("Hello JavaScript!")
    
        val http = require("http")
        val hostname = "127.0.0.1"
        val port = 3000
    
        println("Server will try to run at http://${hostname}:${port}/")
    
        val server = http.createServer{req, res -> 
            res.statusCode = 200
            res.setHeader("Content-Type", "text/plain")
            res.end("Hello World\n")
        }
    
        server.listen(port, hostname, fun() { 
            println("Server running at http://${hostname}:${port}/")
        })
    
        /* OR
        server.listen(port, hostname, {
           println("Server running at http://${hostname}:${port}/") } )
        */
    
       /* OR
        server.listen(port, hostname) {
          println("Server running at http://${hostname}:${port}/") }
       */
    }
    

    And the generated compiled index.js file is:

    (function (_, Kotlin) {
      'use strict';
      var println = Kotlin.kotlin.io.println_s8jyv4$;
      function main$lambda(req, res) {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        return res.end('Hello World\n');
      }
      function main$lambda_0() {
        println('Server running at http://127.0.0.1:3030/');
      }
      function main(args) {
        println('Hello JavaScript!');
        var http = require('http');
        var hostname = '127.0.0.1';
        var port = 3030;
        println('Server will try to run at http://127.0.0.1:3030/');
        var server = http.createServer(main$lambda);
        server.listen(port, hostname, main$lambda_0);
      }
      _.main_kand9s$ = main;
      main([]);
      Kotlin.defineModule('index', _);
      return _;
    }(module.exports, require('kotlin')));
    
    //# sourceMappingURL=index.js.map
    

    Then I run it smoothly using node node/index.js command