Note: This tutorial is a part of Express.js Guide: The Comprehensive Book on Express.js.
Todo apps are considered to be quintessential in showcasing frameworks akin to famous Todomvc.com for front-end JavaScript frameworks. In this example, we’ll use Jade, forms, LESS, AJAX/XHR and CSRF.
In our Todo app, we’ll intentionally not use Backbone.js or Angular to demonstrate how to build traditional websites with the use of forms and redirects. In addition to that, we’ll explain how to plug-in CSRF and LESS.
Example: All the source code is in the github.com/azat-co/todo-express for your convenience.
Here are some screenshots of Todo app in which we start from a home page:
There’s an empty list (unless you played with this app before):
Now we can add four items to the Todo List:
Mark one of the tasks as “done”, e.g.. “Buy milk”:
Going to the Complete page reveals this done item:
Deletion of an item from the Todo list is the only action performed via AJAX/XHR request. The rest of the logic is done via GETs and POSTs (by forms).
Scaffolding
As usual, we start by running
$ express todo-express
$ cd todo-express
$ npm install
This will give us the basic Express.js application.
We’ll need to add two extra dependencies to package.json
, the less-middleware and Mongoskin libraries:
$ npm install less-middleware --save
$ npm install mongoskin --save
Changing the name to todo-express
is optional:
{
"name": "todo-express",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.3.5",
"jade": "*",
"mongoskin": "~0.6.0",
"less-middleware": "~0.1.12"
}
}
MongoDB
Install MongoDB if you don’t have it already.
$ brew update
$ brew install mongodb
$ mongo --version
For more flavors of MongoDB installation, check out the official docs.
Structure
The final version of the app has the following folder/file structure (GitHub):
/todo-express
/public
/bootstrap
*.less
/images
/javascripts
main.js
jquery.js
/stylesheets
style.css
main.less
/routes
tasks.js
index.js
/views
tasks_completed.jade
layout.jade
index.jade
tasks.jade
app.js
readme.md
package.json
The *.less
in bootstrap
folder means there are bunch of Twitter Bootstrap (the CSS framework) source files. They’re available at GitHub.
app.js
This is a break down of the Express.js generated app.js
file with addition of routes, database, session, LESS and param middlewares.
Firstly, we import dependencies with Node.js global require()
function:
var express = require('express');
Similarly, we get access to our own modules which are app’s routes:
var routes = require('./routes');
var tasks = require('./routes/tasks');
The core http
and path
modules will be needed as well:
var http = require('http');
var path = require('path');
Mongoskin is a better alternative to the native MongoDB driver:
var mongoskin = require('mongoskin');
One line is all we need to get the database connection object. The first param follows standard URI convention of protocol://username:password@host:port/database
:
var db = mongoskin.db('mongodb://localhost:27017/todo?auto_reconnect', {safe:true});
The app itself:
var app = express();
In this middleware, we export the database object to all middlewares. By doing so, we’ll be able to perform database operations in the routes modules:
app.use(function(req, res, next) {
req.db = {};
We just store the tasks collection in every request:
req.db.tasks = db.collection('tasks');
next();
})
This line allows us to access appname
from within every jade template:
app.locals.appname = 'Express.js Todo App'
We set the server port to either the environment variable or if that’s undefined to 3000:
app.set('port', process.env.PORT || 3000);
These statements tell Express.js where templates live and what file extension to prepend in case the extension is omitted during the render
calls:
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
Display Express.js favicon (the graphic in the URL address bar of browsers):
app.use(express.favicon());
Out-of-the-box logger will print requests in the terminal window:
app.use(express.logger('dev'));
The bodyParser()
middleware is needed for painlessly accessing incoming data:
app.use(express.bodyParser());
The methodOverride()
middleware is a work around for HTTP methods that involve headers. It’s not essential for this example, but we’ll leave it here:
app.use(express.methodOverride());
To use CSRF, we need cookieParser()
and session()
:
app.use(express.cookieParser());
app.use(express.session({
secret: '59B93087-78BC-4EB9-993A-A61FC844F6C9'
}));
The csrf()
middleware itself. The order is important; in other words, csrf()
must be preceded by cookieParser()
and session()
:
app.use(express.csrf());
To process LESS stylesheets into CSS ones, we utilize less-middleware
in this manner:
app.use(require('less-middleware')({
src: __dirname + '/public',
compress: true
}));
The other static files are also in the public
folder:
app.use(express.static(path.join(__dirname, 'public')));
Remember CSRF? This is how we expose it to templates:
app.use(function(req, res, next) {
res.locals._csrf = req.session._csrf;
return next();
})
The router plug-in is enabled by this statement. It’s important to have this line after less-middleware
and csrf()
lines above:
app.use(app.router);
It’s possible to configure different behavior based on environments:
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
When there’s a request that matches route/RegExp with :task_id
in it, this block is executed:
app.param('task_id', function(req, res, next, taskId) {
The value of task ID is in taskId
and we query the database to find that object:
req.db.tasks.findById(taskId, function(error, task){
It’s very important to check for errors and empty results:
if (error) return next(error);
if (!task) return next(new Error('Task is not found.'));
If there’s data, store it in the request and proceed to next middleware:
req.task = task;
return next();
});
});
Now it’s time to define our routes. We start with home page:
app.get('/', routes.index);
The Todo List page:
app.get('/tasks', tasks.list);
This route will mark all tasks in the todo list as completed if the user presses all done button. In a RESP API, the HTTP method would be PUT but because we’re building classical web apps with forms, we have to use POST:
app.post('/tasks', tasks.markAllCompleted)
The same URL for adding new tasks as for marking all tasks completed, but in the previous methods itself (markAllCompleted
) you’ll see how we handle flow control:
app.post('/tasks', tasks.add);
To mark a single task completed, we use aforementioned :task_id
string in our URL pattern. In REST API, this should have been a PUT request:
app.post('/tasks/:task_id', tasks.markCompleted);
Unlike with the POST route above, we utilize Express.js param middleware with :task_id
token:
app.del('/tasks/:task_id', tasks.del);
For our Completed page, we define this route:
app.get('/tasks/completed', tasks.completed);
In case of malicious attacks or mistyped URLs, it’s a user-friendly thing to catch all requests with *
. Keep in mind that if we had a match previously, the Node.js won’t come to execute this block:
app.all('*', function(req, res){
res.send(404);
})
Finally, we spin up our application with good ’ol http
method:
http.createServer(app).listen(app.get('port'),
function(){
console.log('Express server listening on port '
+ app.get('port'));
}
);
The full content of app.js
file:
/**
* Module dependencies.
*/
var express = require('express');
var routes = require('./routes');
var tasks = require('./routes/tasks');
var http = require('http');
var path = require('path');
var mongoskin = require('mongoskin');
var db = mongoskin.db('mongodb://localhost:27017/todo?auto_reconnect', {safe:true});
var app = express();
app.use(function(req, res, next) {
req.db = {};
req.db.tasks = db.collection('tasks');
next();
})
app.locals.appname = 'Express.js Todo App'
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({secret: '59B93087-78BC-4EB9-993A-A61FC844F6C9'}));
app.use(express.csrf());
app.use(require('less-middleware')({ src: __dirname + '/public', compress: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
res.locals._csrf = req.session._csrf;
return next();
})
app.use(app.router);
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.param('task_id', function(req, res, next, taskId) {
req.db.tasks.findById(taskId, function(error, task){
if (error) return next(error);
if (!task) return next(new Error('Task is not found.'));
req.task = task;
return next();
});
});
app.get('/', routes.index);
app.get('/tasks', tasks.list);
app.post('/tasks', tasks.markAllCompleted)
app.post('/tasks', tasks.add);
app.post('/tasks/:task_id', tasks.markCompleted);
app.del('/tasks/:task_id', tasks.del);
app.get('/tasks/completed', tasks.completed);
app.all('*', function(req, res){
res.send(404);
})
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Routes
There are only two files in routes
folder. One of them serves the home page (e.g., http://localhost:3000/) and is straightforward:
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: 'Express.js Todo App' });
};
The remaining logic that deals with tasks itself has been placed in the todo-express/routes/tasks.js
. Let’s break it down a bit.
We start by exporting list()
request handler that gives us list of incomplete tasks:
exports.list = function(req, res, next){
To do so, we perform a database search with completed=false query:
req.db.tasks.find({
completed: false
}).toArray(function(error, tasks){
In the callback, we need to check for any errors:
if (error) return next(error);
Since we use toArray()
, we can send the date directly to the template:
res.render('tasks', {
title: 'Todo List',
tasks: tasks || []
});
});
};
Adding a new task requires us to check for the name parameter:
exports.add = function(req, res, next){
if (!req.body || !req.body.name)
return next(new Error('No data provided.'));
Thanks to our middleware, we already have a database collection in the req
object, and the default value for the task is incomplete (completed: false
):
req.db.tasks.save({
name: req.body.name,
completed: false
}, function(error, task){
Again, it’s important to check for errors and propagate them with Express.js next()
function:
if (error) return next(error);
if (!task) return next(new Error('Failed to save.'));
The logging is optional; however, it’s useful for learning and debugging:
console.info('Added %s with id=%s', task.name, task._id);
Lastly, we redirect back to the Todo List page when the saving operation is finished successfully:
res.redirect('/tasks');
})
};
This method marks all incomplete tasks as complete:
exports.markAllCompleted = function(req, res, next) {
Because we had to re-use POST route and since it’s a good illustration of flow control, we check for the all_done
parameter to decide if this request comes from the all done button or the add button:
if (!req.body.all_done
|| req.body.all_done !== 'true')
return next();
If the execution come this far, we perform db query with multi: true
:
req.db.tasks.update({
completed: false
}, {$set: {
completed: true
}}, {multi: true}, function(error, count){
Significant error handling, logging and redirection back to Todo List page:
if (error) return next(error);
console.info('Marked %s task(s) completed.', count);
res.redirect('/tasks');
})
};
The Completed route is akin to Todo List except for the completed flag value (true in this case):
exports.completed = function(req, res, next) {
req.db.tasks.find({
completed: true
}).toArray(function(error, tasks) {
res.render('tasks_completed', {
title: 'Completed',
tasks: tasks || []
});
});
};
This is the route that takes care of marking a single task as done. We use updateById
but the same thing can be accomplished with a plain update
method from Mongoskin/MongoDB API. The trick with completed: req.body.completed === 'true
is needed because the incoming value is a string and not a boolean.
exports.markCompleted = function(req, res, next) {
if (!req.body.completed)
return next(new Error('Param is missing'));
req.db.tasks.updateById(req.task._id, {
$set: {completed: req.body.completed === 'true'}},
function(error, count) {
Once more, we perform error and results check (update()
and updateById()
don’t return object, but the count of affected documents instead):
if (error) return next(error);
if (count !==1)
return next(new Error('Something went wrong.'));
console.info('Marked task %s with id=%s completed.',
req.task.name,
req.task._id);
res.redirect('/tasks');
}
)
}
Delete is the single route called by an AJAX request. However, there’s nothing special about its implementation. The only difference is that we don’t redirect, but send status 200 back.
Just for your information, the remove()
method can be used instead of removeById()
.
exports.del = function(req, res, next) {
req.db.tasks.removeById(req.task._id, function(error, count) {
if (error) return next(error);
if (count !==1) return next(new Error('Something went wrong.'));
console.info('Deleted task %s with id=%s completed.',
req.task.name,
req.task._id);
res.send(200);
});
}
For your convenience, here’s the full content of the todo-express/routes/tasks.js
file:
/*
* GET users listing.
*/
exports.list = function(req, res, next){
req.db.tasks.find({completed: false}).toArray(function(error, tasks){
if (error) return next(error);
res.render('tasks', {
title: 'Todo List',
tasks: tasks || []
});
});
};
exports.add = function(req, res, next){
if (!req.body || !req.body.name) return next(new Error('No data provided.'));
req.db.tasks.save({
name: req.body.name,
completed: false
}, function(error, task){
if (error) return next(error);
if (!task) return next(new Error('Failed to save.'));
console.info('Added %s with id=%s', task.name, task._id);
res.redirect('/tasks');
})
};
exports.markAllCompleted = function(req, res, next) {
if (!req.body.all_done || req.body.all_done !== 'true') return next();
req.db.tasks.update({
completed: false
}, {$set: {
completed: true
}}, {multi: true}, function(error, count){
if (error) return next(error);
console.info('Marked %s task(s) completed.', count);
res.redirect('/tasks');
})
};
exports.completed = function(req, res, next) {
req.db.tasks.find({completed: true}).toArray(function(error, tasks) {
res.render('tasks_completed', {
title: 'Completed',
tasks: tasks || []
});
});
};
exports.markCompleted = function(req, res, next) {
if (!req.body.completed) return next(new Error('Param is missing'));
req.db.tasks.updateById(req.task._id, {$set: {completed: req.body.completed === 'true'}}, function(error, count) {
if (error) return next(error);
if (count !==1) return next(new Error('Something went wrong.'));
console.info('Marked task %s with id=%s completed.', req.task.name, req.task._id);
res.redirect('/tasks');
})
};
exports.del = function(req, res, next) {
req.db.tasks.removeById(req.task._id, function(error, count) {
if (error) return next(error);
if (count !==1) return next(new Error('Something went wrong.'));
console.info('Deleted task %s with id=%s completed.', req.task.name, req.task._id);
res.send(200);
});
};
Jades
In the Todo app, we use four templates:
layout.jade
: the skeleton of HTML pages that is used on all pagesindex.jade
: home pagetasks.jade
: Todo List pagetasks_completed.jade
: Completed page
Let’s go through each file starting with layout.jade
. It starts with doctype, html and head types:
doctype 5
html
head
We should have appname
variable set:
title= title + ' | ' + appname
Next we include *.css
files but underneath, Express.js will serve its contents from LESS files:
link(rel="stylesheet", href="/stylesheets/style.css")
link(rel="stylesheet", href="/bootstrap/bootstrap.css")
link(rel="stylesheet", href="/stylesheets/main.css")
The body with Twitter Bootstrap structure consist of .container
and .navbar
. To read more about those and other classes, go to getbootstrap.com/css/:
body
.container
.navbar.navbar-default
.container
.navbar-header
a.navbar-brand(href='/')= appname
.alert.alert-dismissable
h1= title
p Welcome to Express.js Todo app by
a(href='http://twitter.com/azat_co') @azat_co
|. Please enjoy.
This is the place where other jades (like tasks.jade
) will be imported:
block content
The last lines include front-end JavaScript files:
script(src='/javascripts/jquery.js', type="text/javascript")
script(src='/javascripts/main.js', type="text/javascript")
The full layout.jade
file:
doctype 5
html
head
title= title + ' | ' + appname
link(rel="stylesheet", href="/stylesheets/style.css")
link(rel="stylesheet", href="/bootstrap/bootstrap.css")
link(rel="stylesheet", href="/stylesheets/main.css")
body
.container
.navbar.navbar-default
.container
.navbar-header
a.navbar-brand(href='/')= appname
.alert.alert-dismissable
h1= title
p Welcome to Express.js Todo app by
a(href='http://twitter.com/azat_co') @azat_co
|. Please enjoy.
block content
script(src='/javascripts/jquery.js', type="text/javascript")
script(src='/javascripts/main.js', type="text/javascript")
The index.jade
file is our home page and it’s quite vanilla. The most interesting thing it had is the nav-pills
menu:
extends layout
block content
.menu
h2 Menu
ul.nav.nav-pills
li.active
a(href="/tasks") Home
li
a(href="/tasks") Todo List
li
a(href="/tasks") Completed
.home
p This is an example of classical (no front-end JavaScript frameworks) web application built with Express.js 3.3.5 for
a(href="http://expressjsguide.com") Express.js Guide
|.
p The full source code is available at
a(href='http://github.com/azat-co/todo-express') github.com/azat-co/todo-express
|.
The tasks.jade
uses extends layout
:
extends layout
block content
Then goes our main page specific content:
.menu
h2 Menu
ul.nav.nav-pills
li
a(href='/') Home
li.active
a(href='/tasks') Todo List
li
a(href="/tasks/completed") Completed
h1= title
The div
with list class will hold the Todo List:
.list
.item.add-task
The form to mark all items as done has CSRF token in a hidden field and uses POST method pointed to /tasks
:
div.action
form(action='/tasks', method='post')
input(type='hidden', value='true', name='all_done')
input(type='hidden', value=locals._csrf, name='_csrf')
input(type='submit', class='btn btn-success btn-xs', value='all done')
Similar CSRF enabled form is for new task creation:
form(action="/tasks", method='post')
input(type='hidden', value=locals._csrf, name='_csrf')
div.name
input(type="text", name="name", placeholder='Add a new task')
div.delete
input.btn.btn-primary.btn-sm(type="submit", value='add')
When we start the app for the first time (or clean the database), there are no tasks:
if (tasks.length === 0)
| No tasks.
Jade supports iterations with each
command:
each task, index in tasks
.item
div.action
This form submits data to individual task route:
form(action='/tasks/#{task._id}', method='post')
input(type='hidden', value=task._id.toString(), name='id')
input(type='hidden', value='true', name='completed')
input(type='hidden', value=locals._csrf, name='_csrf')
input(type='submit', class='btn btn-success btn-xs task-done', value='done')
The index
variable is used to display order in the list of tasks:
div.num
span=index+1
|.
div.name
span.name=task.name
//- no support for DELETE method in forms
//- http://amundsen.com/examples/put-delete-forms/
//- so do XHR request instead from public/javascripts/main.js
The delete button doesn’t have anything fancy attached to it, because events are attached to these buttons from main.js
front-end JavaScript file:
div.delete
a(class='btn btn-danger btn-xs task-delete', data-task-id=task._id.toString(), data-csrf=locals._csrf) delete
The full source code of tasks.jade
:
extends layout
block content
.menu
h2 Menu
ul.nav.nav-pills
li
a(href='/') Home
li.active
a(href='/tasks') Todo List
li
a(href="/tasks/completed") Completed
h1= title
.list
.item.add-task
div.action
form(action='/tasks', method='post')
input(type='hidden', value='true', name='all_done')
input(type='hidden', value=locals._csrf, name='_csrf')
input(type='submit', class='btn btn-success btn-xs', value='all done')
form(action="/tasks", method='post')
input(type='hidden', value=locals._csrf, name='_csrf')
div.name
input(type="text", name="name", placeholder='Add a new task')
div.delete
input.btn.btn-primary.btn-sm(type="submit", value='add')
if (tasks.length === 0)
| No tasks.
each task, index in tasks
.item
div.action
form(action='/tasks/#{task._id}', method='post')
input(type='hidden', value=task._id.toString(), name='id')
input(type='hidden', value='true', name='completed')
input(type='hidden', value=locals._csrf, name='_csrf')
input(type='submit', class='btn btn-success btn-xs task-done', value='done')
div.num
span=index+1
|.
div.name
span.name=task.name
//- no support for DELETE method in forms
//- http://amundsen.com/examples/put-delete-forms/
//- so do XHR request instead from public/javascripts/main.js
div.delete
a(class='btn btn-danger btn-xs task-delete', data-task-id=task._id.toString(), data-csrf=locals._csrf) delete
Last but not least, comes tasks_completed.jade
which is just a striped down version of tasks.jade
file:
extends layout
block content
.menu
h2 Menu
ul.nav.nav-pills
li
a(href='/') Home
li
a(href='/tasks') Todo List
li.active
a(href="/tasks/completed") Completed
h1= title
.list
if (tasks.length === 0)
| No tasks.
each task, index in tasks
.item
div.num
span=index+1
|.
div.name.completed-task
span.name=task.name
LESS
As we’ve mentioned before, after applying proper middleware in app.js
files, we can put *.less
files anywhere under public
folder. Express.js works by accepting request for some .css
file and tries to match corresponding file by name. Therefore, we include *.css
files in our jades.
Here is the content of the todo-express/public/stylesheets/main.less
file:
* {
font-size:20px;
}
.btn {
// margin-left: 20px;
// margin-right: 20px;
}
.num {
// margin-right: 3px;
}
.item {
height: 44px;
width: 100%;
clear: both;
.name {
width: 300px;
}
.action {
width: 100px;
}
.delete {
width: 100px
}
div {
float:left;
}
}
.home {
margin-top: 40px;
}
.name.completed-task {
text-decoration: line-through;
}
Conclusion
The Todo app is considered classical because it doesn’t rely on any front-end framework. This was done intentionally to show how easy it is to use Express.js for such tasks. In modern day development, people often leverage some sort of REST API server architecture with front-end client built with Backbone.js, Angular, Ember or something else. Next examples dive into details about how to write such servers.
If you found this tutorial helpful, please take a look at Express.js Guide book, in which there many similar examples of Node.js developement.
I use WPEngine for this blog. It’s faster than other WP/PHP hostings.
Hi would you mind letting me know which webhost you’re working with?
I’ve loaded your blog in 3 completely different web
browsers and I must say this blog loads a lot quicker then most.
Can you recommend a good web hosting provider at a reasonable price?
Thank you, I appreciate it!
I am getting this error on terminal when I am running the server:
unable to connect to database at mongodb://localhost/todo-list-development
Hi Anna, what book are you referring to? You might want to buy Practical Node.js for more real-world-ish examples. :-)
http://webapplog.com/practical-node-js-toc/
Hi Azat,
I was wondering if the book shows how to use more than one collection of documents, from the mongoDB.
And if it has any information about how to work with user, like verifying if the user exist.
Thanks for the tutorial, it is really helpful.
You’re welcome.
Maybe.
Thank you for such a detailed example with less-middleware. I have one question though
I was running this example with express4 and I found that if I have this route
app.get(‘/tasks/completed’, tasks.completed); after
app.post(‘/tasks/:task_id’, tasks.markCompleted);
app.del(‘/tasks/:task_id’, tasks.del);
then task/completed never works (it works with your source code)
but i have to run it like this to make it work
app.get(‘/’, routes.index);
app.get(‘/tasks’, tasks.list);
app.post(‘/tasks’, tasks.markAllCompleted);
app.post(‘/tasks’, tasks.add);
app.get(‘/tasks/completed’, tasks.completed);
app.post(‘/tasks/:task_id’, tasks.markCompleted);
app.del(‘/tasks/:task_id’, tasks.del);
1) Is this issue with express4?
2) I also noticed that
app.param(‘task_id’, function(req, res, next, taskId) is being called twice and again not sure why.
These are my packe.json dependency
“express”: “~4.2.0”,
“static-favicon”: “~1.0.0”,
“morgan”: “~1.0.0”,
“cookie-parser”: “~1.0.1”,
“body-parser”: “~1.0.0”,
“debug”: “~0.7.4”,
“jade”: “~1.3.0”,
“less-middleware”: “^1.0.3”,
“mongoskin”: “^1.4.4”,
“method-override”: “^1.0.2”,
“csrf”: “0.0.3”,
“express-session”: “^1.2.0”,
“http”: “0.0.0”,
“errorhandler”: “^1.0.1”,
thank you, it’s a very useful article on mongoDB with nodeJS
1) No, it’s a front end file, we manually create it and put in /public/… you can look it up in the GitHub repo
2) Maybe, usually it’s just a zip download and again putting under /public
PS: Don’t confuse front-end and back end js :-)
Although with npm it’s possible to install front-end modules. You should check out ender.js as well.
Hi Azat,
Thanks for this great tutorial. Should main.js be automatically generated in /public/javascripts? I noticed that you don’t cover the code for that file here.
Also, is there an automatic way to install /bootstrap/*.less in /public? I know we can do
npm install bootstrap --save
but this only installs bootstrap into /node-modules.
Similar question for /public/javascripts/jquery.js — is there a way to install this automatically?
Hi Lukas, thank you for reading. Yes, the default laws apply. However, if you plan to use my work (code or writing), we can come up with a special agreement. Just send me an email/message with your particular use case. For example, I encourage people to conduct Node.js and Backbone.js training with my tutorials. I can setup a special price for ebooks and paperbacks for that.
Thanks for an excellent article! I really really considering buying book now ;-)
One request though. I do not see any license/copyright notice. Can you add some so I know whether I can use code parts directly or not?
A longer explanation is on github (for example). The short citation:
You’re under no obligation to choose a license. It’s your right not to include one with your code or project, but please be aware of the implications. Generally speaking, the absence of a license means that the default copyright laws apply. This means that you retain all rights to your source code and that nobody else may reproduce, distribute, or create derivative works from your work. This might not be what you intend.
This applies both to your code in github and to this blogpost…
Thanks in advance