Equivalent Kotlin code to my JavaScript code


#1

I’ve the below JavaScript function run perfectly, I used it to run static server without 3rd part library:

const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
const port = process.argv[2] || 9000;

http.createServer(function (req, res) {
  console.log(`${req.method} ${req.url}`);

  // parse URL
  const parsedUrl = url.parse(req.url);
  // extract URL path
  let pathname = `.${parsedUrl.pathname}`;
  // based on the URL path, extract the file extention. e.g. .js, .doc, ...
  const ext = path.parse(pathname).ext;
  // maps file extention to MIME typere
  const map = {
    '.ico': 'image/x-icon',
    '.html': 'text/html',
    '.js': 'text/javascript',
    '.json': 'application/json',
    '.css': 'text/css',
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.wav': 'audio/wav',
    '.mp3': 'audio/mpeg',
    '.svg': 'image/svg+xml',
    '.pdf': 'application/pdf',
    '.doc': 'application/msword'
  };

  fs.exists(pathname, function (exist) {
    if(!exist) {
      // if the file is not found, return 404
      res.statusCode = 404;
      res.end(`File ${pathname} not found!`);
      return;
    }

    // if is a directory search for index file matching the extention
    if (fs.statSync(pathname).isDirectory()) pathname += '/index' + ext;

    // read file from file system
    fs.readFile(pathname, function(err, data){
      if(err){
        res.statusCode = 500;
        res.end(`Error getting the file: ${err}.`);
      } else {
        // if the file is found, set Content-type and send data
        res.setHeader('Content-type', map[ext] || 'text/plain' );
        res.end(data);
      }
    });
  });


}).listen(parseInt(port));

console.log(`Server listening on port ${port}`);

I’m trying to replicate it using Kotlin, so wrote the below code:

external fun require(module:String):dynamic

fun main(args: Array<String>) {
    println("Hello JavaScript!")
    val http = require("http")
    val url = require("url")
    val fs = require("fs")
    val path = require("path")
    val port = process.argv[2] || 9000
    val hostname = "127.0.0.1"

    val server = http.createServer{req, res ->

        // parse URL
        val parsedUrl = url.parse(req.url)
        // extract URL path
        val pathname = parsedUrl.pathname
        // based on the URL path, extract the file extention. e.g. .js, .doc, ...
        val ext = path.parse(pathname).ext
        // maps file extention to MIME typere
        val map = mapOf(
            ".ico" to "image/x-icon",
            ".html" to "text/html",
            ".js" to "text/javascript",
            ".json" to "application/json",
            ".css" to "text/css",
            ".png" to "image/png",
            ".jpg" to "image/jpeg",
            ".wav" to "audio/wav",
            ".mp3" to "audio/mpeg",
            ".svg" to "image/svg+xml",
            ".pdf" to "application/pdf",
            ".doc" to "application/msword"
        )

        fs.exists(pathname, fun (exist) {
            if(!exist) {
                // if the file is not found, return 404
                res.statusCode = 404;
                res.end("File ${pathname} not found!")
            }

         // if is a directory search for index file matching the extention
         if (fs.statSync(pathname).isDirectory()) pathname += "/index" + ext;

            // read file from file system
            fs.readFile(pathname, fun(err, data){
                if(err){
                    res.statusCode = 500;
                    res.end("Error getting the file: ${err}.")
                } else {
                    // if the file is found, set Content-type and send data
                    res.setHeader("Content-type", map.get(ext) || "text/plain" )
                    res.end(data)
                }
            })
        })
    }
    
    server.listen(port, hostname, fun() { 
        println("Server running at http://${hostname}:${port}/")
    })
}

But there are some errors, that I could not fix, which are:

val port = process.argv[2] || 9000 . // process.argv unresolved

fs.exists(pathname, fun (exist) { ..} // exist pls specify it explicitly

fs.readFile(pathname, fun(err, data){ ..} // err and data pls specify it explicitly

res.setHeader("Content-type", map.get(ext) || "text/plain" ) // Required Boolean, found String


#2

I don’t know JS so I don’t really know what the JS version does. I think you are trying to get the command line arguments or if there is none use 9000. The args parameter of main contains those. So you could use code like this:

val port = args.getOrNull(2)?.toIntOrNull() ?: 9000

Those 2 errors have to do with the types of the parameters. Normally Kotlin can deduce most of the types from some context, e.g if you pass an anonymous function as an argument, the compiler can find the types of the parameters of the anonymous function. The type of the server.listen method would specify the type of the parameters. But because you are using dynamic types, the compiler does not know about those so you must specify them.

As far as I can tell you want to use the result of map.get(ext) and if the result is null use "text/plain". In Kotlin you can not use the || operator for that as it is normally used for booleans. The Kotlin way of writing this is map[ext] ?: "text/plain". Note you can use brackets to access maps, lists, etc. You should take a look at the elvis operator.

Two more things. By this question and the other one you asked I can guess that you are quite new to programming or at least programming using a different language than JavaScript. Most of the questions you had could have been answered by the Kotlin documentation, so I’d suggest you take a look at it. It is quite well written. You should definitely look at the Getting Started and Basics part: https://kotlinlang.org/docs/reference/basic-syntax.html

The other is the way you ask your questions. There is nothing wrong with being new to something or learning something new, but most people me normally included would probably skip both of your questions right away. Let me try to explain why. Reading and understanding code takes time. A lot of time. Most of the time programing is spent reading code (80% or so). Your question has 120 lines of code. There might be some questions which are so complex, that this is really necessary, but most often this is not the case. Try to spent some time to isolate the problem and just paste the required code. It might also be a good idea to create a new project in which you recreate you problem. In your case you could create 2 functions

fun call(func: (exists: Boolean) -> Unit){
    func(true)
    func(false)
}
fun test(){
    call(fun (exist) { ... })
}

At that point you would have seen, that this would work in the small test project, for reasons I explained above. Than you can try to find more anwsers or ask you question here. “I have the above code using Kotlin2JS and for some reason I get this error”

Also google first and ask later. I am 100% sure there have been people before you who had the same problem you have. Obviously not in 100% the same context, but similar enough that answers to their question would have helped you too. So look at that. This goes along the same way of trying to ask shorter more concise questions. If you can ask an more abstract question there is a higher chance someone else asked it before you. If you don’t find an answer you can still come here and ask.

I hope you can take the last part as friendly criticism. No one here minds helping other people, but I am pretty sure there are more people here willing to help if you put a bit more effort into asking the question as it makes it easier to help you :slight_smile: