where "stuff" is probably best described as "streams" yes, I could have just said "streams", but it's too late now
npm init
together
- Create a file named read.js
- Add the 'fs' library to the file
var fs = require('fs');
- Read the filestream to "lipsum.txt" (provided in this repo)
var file = createReadStream('lipsum.txt');
- Listen for the "readable" event
file.on("readable", function(){ ... });
- Loop through the chunks of
file.read()
in thereadable
event
var chunk = null;
while(null !== (chunk = file.read())){ ... }
console.log
out the chunks as you get them fromfile.read()
- Listen for the "end" event on
file
andconsole.log
something
or you can use file.on('data', function(chunk){ ... });
- Change the
console.log()
in the while chunk mess to beprocess.stdout.write()
- Note 1:
console.log
just callsprocess.stdout.write
with some formatting and a newline at the end - Note 2:
process.stdout
is a writable stream
- Comment out the whole
file.on("readable"...
block - Pipe the
file
(readable stream) toprocess.stdout
(a writable stream)
- doing that chunk stuff is necessary sometimes, but whenever you can, you should just
pipe
stuff along
together
- Add the
http
library to the file - Create a server
var server = http.createServer(function(request, response){ ... });
- Write to the header on the response (a writable stream)
response.writeHead(200, {'Content-Type': 'text/html'});
- End the stream and write something at the end
response.end("okay");
- Note:
end('something')
is just shorthand forwrite('something');
followed byend()
- Listen on 7000 (or whatever)
server.listen(7000)
- Add a message to your console to let you know you're listening and on what port
server.listen(7000, function(){
console.log("listening on 7000");
});
Run server and check it in a browser
It might be more clear if you move the anonymous function to a "handleRequest" method.
npm install -g nodemon
- Use
nodemon something.js
to run your node files and they will automatically be updated
on your own
- Require the
fs
lib - Create a readable stream just like we did earlier off of the "lipsum.txt" file
pipe
that stream to the server response Note: Make sure yourcreateReadStream
is happening inside the response, otherwise it will only happen once
together
- Get the time
new Date();
.toString()
.toISOString()
.toJSON()
- Get the method
request.method
- Get the url hit
request.url
- Get the
user-agent
(fromrequest.headers
)
together
- Check the
request.url
- Respond with a 200
return
together
- Require
stream
- specifically, we're going to need
stream.Transform
var Transform = require('stream').Transform;
- Create a new parser from the
Transform
var parser = new Transform();
- Define the transform method
parser._transform = function(data, encoding, done){
this.push(data);
done();
};
- Alter data before pushing it to replace the
\n
s with<br>
s
data = data.toString().replace(/\n/g, '<br>');
- Add the parser to the piped stream
file.pipe(parser).pipe(response);
Note: make sure the parser gets reset every request, each transform is its own stream, and once it reaches the end of the stream, it's done. So it won't work more than once unless it's reset.
together
- Create a
logger.js
file - Move the functionality to that file
- assign the functionality to
module.exports
- give it
request
andresponse
parameters - now when you
require
that module, the variable will be a function
- Require that file in your app
var logger = require('./logger');
- Use that
logger()
function
on your own
- Create a
newlineTransformer.js
file - Move the functionality to that file
- you want to return the
parser
- because it uses
new
you're going to have to run the code every time - so return a function and calling that function will execute the new
- Require that file in your app
var newlineTransformer = require('newlineTransformer');
- Use the function in your
pipe
stream
.pipe(newlineTransformer())
on your own
- We already created a route for '/favicon.ico'
- Create a route for '/lipsum'
if(request.url === '/lipsum'){ ... }
- Move all lipsum related such to that route
- Else send a header for a 404 error
response.writeHead(404);
- And just end the response with a message to the user
response.end("404 Not Found");
together
- Just copy the '/lipsum' route and make it look at the 'sample.md' file
together
npm install markdown
- Require the module
var markdown = require( "markdown" ).markdown;
- it is used like this:
markdown.toHTML("I can't actually put real markdown in this example but let's pretend I did");
- Create a markdown parser
- the same way we created the other transformers
- in a module
this.push(markdown.toHTML(data.toString()));
- Add the new parser to the markdown route
together
- Copy everything you did for the markdown route
- Since they're doing the same thing, create a function to
handleMarkdown
- Require the 'url' lib
var url = require('url');
- Set a parsed url variable
var purl = url.parse(request.url, true);
- where purl is short for "parsed url"
- true is referring to if we want to parse request parameters!
console.log
the query params
console.log(purl.query);
on your own?
- Change the route definition to use the parsed url param of
pathname
if(purl.pathname === '/lipsum'){ ...
- Get a "limit" parameter from the GET request
purl.query.limit
- Add a new limit parser module
- Have the module take a limit param and pass that
module.exports = function(limit){ ... }
var limitTransformer = require('./limitTransformer');
pipe
the stream through that limit parser
.pipe(limitTransformer(limit)).
- Using
limit
in the limit parser, track how many character you're letting through
- remember these are data chunks
Example: (I'll bet you can do better!)
parser._transform = function(){
if(limit === undefined){
this.push(data);
done();
} else {
if(this.limit > data.toString().length){
this.push(data);
this.limit - data.toString().length;
} else if(this.limit > 0 && this.limit < data.toString().length){
this.push(data.toString().substr(0, this.limit));
this.limit = 0;
}
done();
}
};