May 09, 2021 CoffeeScript
You want to create an HTTP server on the network. In this approach, we will gradually move from the smallest server to a function key value store.
We'll use node .js the HTTP library and create the simplest web server in Coffeescript.
We can start by importing .js the HTTP module. T his will include a creative server, a simple request handler that returns to the HTTP server. We can use this server to listen for TCP ports.
http = require 'http'
server = http.createServer (req, res) -> res.end 'hi\n'
server.listen 8000
To run this example, simply put it in a file and run it. Y ou can terminate it with ctrl-c. We can test it with the curl command, which can be used on most of the snix platforms:
$ curl -D - http://localhost:8000/
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
hi
Let's give a little feedback on what's happening on the server. At this point, we can be friendly to the user and provide them with some HTTP header files.
http = require 'http'
server = http.createServer (req, res) ->
console.log req.method, req.url
data = 'hi\n'
res.writeHead 200,
'Content-Type': 'text/plain'
'Content-Length': data.length
res.end data
server.listen 8000
Try accessing it again, but this time using a different URL path, such
http://localhost:8000/coffee
You'll see a server console like this:
$ coffee http-server.coffee
GET /
GET /coffee
GET /user/1337
What if our web server could hold some data? W e'll try to figure out a simple key value store in the element that is retrieved by the GET method request. Provides a critical path, the server will request a value returned, and if it does not exist, a 404 error.
http = require 'http'
store = # we'll use a simple object as our store
foo: 'bar'
coffee: 'script'
server = http.createServer (req, res) ->
console.log req.method, req.url
value = store[req.url[1..]]
if not value
res.writeHead 404
else
res.writeHead 200,
'Content-Type': 'text/plain'
'Content-Length': value.length + 1
res.write value + '\n'
res.end()
server.listen 8000
We can try a few urls and see how they respond:
$ curl -D - http://localhost:8000/coffee
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 7
Connection: keep-alive
script
$ curl -D - http://localhost:8000/oops
HTTP/1.1 404 Not Found
Connection: keep-alive
Transfer-Encoding: chunked
Text / plain is indefensible. W hat if we use application/json or text/xml? A t the same time, our store retrieval process can also be refactored with a little bit - how about throwing out some exceptions and handling them? Let's see what we can come up with:
http = require 'http'
# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']
# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
value = store[key]
throw 'Unknown key' if not value
switch format
when any, json then [JSON.stringify({ key: key, value: value }), json]
when xml then ["<key>#{ key }</key>\n<value>#{ value }</value>", xml]
else throw 'Unknown format'
store =
foo: 'bar'
coffee: 'script'
server = http.createServer (req, res) ->
console.log req.method, req.url
try
key = req.url[1..]
[value, contentType] = get store, key, req.headers.accept
code = 200
catch error
contentType = 'text/plain'
value = error
code = 404
res.writeHead code,
'Content-Type': contentType
'Content-Length': value.length + 1
res.write value + '\n'
res.end()
server.listen 8000
The server still returns a value that matches a given key and a 404 error if it does not exist. B ut it will respond in a JSON or XML structure based on the headerAccept. Take a look at it for yourself:
$ curl http://localhost:8000/
Unknown key
$ curl http://localhost:8000/coffee
{"key":"coffee","value":"script"}
$ curl -H "Accept: text/xml" http://localhost:8000/coffee
<key>coffee</key>
<value>script</value>
$ curl -H "Accept: image/png" http://localhost:8000/coffee
Unknown format
Our final step is to provide the client with the ability to store data. We will keep RESTiness by listening to POST requests.
http = require 'http'
# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']
# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
value = store[key]
throw 'Unknown key' if not value
switch format
when any, json then [JSON.stringify({ key: key, value: value }), json]
when xml then ["<key>#{ key }</key>\n<value>#{ value }</value>", xml]
else throw 'Unknown format'
# puts a value in the db
put = (store, key, value) ->
throw 'Invalid key' if not key or key is ''
store[key] = value
store =
foo: 'bar'
coffee: 'script'
# helper function that responds to the client
respond = (res, code, contentType, data) ->
res.writeHead code,
'Content-Type': contentType
'Content-Length': data.length
res.write data
res.end()
server = http.createServer (req, res) ->
console.log req.method, req.url
key = req.url[1..]
contentType = 'text/plain'
code = 404
switch req.method
when 'GET'
try
[value, contentType] = get store, key, req.headers.accept
code = 200
catch error
value = error
respond res, code, contentType, value + '\n'
when 'POST'
value = ''
req.on 'data', (chunk) -> value += chunk
req.on 'end', () ->
try
put store, key, value
value = ''
code = 200
catch error
value = error + '\n'
respond res, code, contentType, value
server.listen 8000
Pay attention to how the data is received in a POST request. By attaching handlers to the events of the Data and End request objects, we were eventually able to buffer and save the data from the client.
$ curl -D - http://localhost:8000/cookie
HTTP/1.1 404 Not Found # ...
Unknown key
$ curl -D - -d "monster" http://localhost:8000/cookie
HTTP/1.1 200 OK # ...
$ curl -D - http://localhost:8000/cookie
HTTP/1.1 200 OK # ...
{"key":"cookie","value":"monster"}
Give http.createServer a function (request, response) - I t returns a server object that we can use to listen to a port. L et the server interact with the request and response objects. Use server.listen 8000 to listen to port 8000.
For API and overall information on this issue, refer to .js https and https documentation pages. In addition, HTTP spec may come in use.
Create a layer between the server and the developer that allows the developer to do something similar:
server = layer.createServer
'GET /': (req, res) ->
...
'GET /page': (req, res) ->
...
'PUT /image': (req, res) ->
...