{"id":16370819,"url":"https://github.com/integralist/node-learning","last_synced_at":"2025-06-16T22:04:43.644Z","repository":{"id":140161920,"uuid":"11685285","full_name":"Integralist/Node-Learning","owner":"Integralist","description":"Code written with Node.js to learn its features and how to build applications using it.","archived":false,"fork":false,"pushed_at":"2013-09-15T17:09:20.000Z","size":620,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-16T22:04:42.441Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Integralist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-26T12:31:20.000Z","updated_at":"2014-03-15T08:30:08.000Z","dependencies_parsed_at":"2023-03-13T10:44:18.619Z","dependency_job_id":null,"html_url":"https://github.com/Integralist/Node-Learning","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Integralist/Node-Learning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2FNode-Learning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2FNode-Learning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2FNode-Learning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2FNode-Learning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Integralist","download_url":"https://codeload.github.com/Integralist/Node-Learning/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Integralist%2FNode-Learning/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260249959,"owners_count":22980763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T03:06:11.677Z","updated_at":"2025-06-16T22:04:43.605Z","avatar_url":"https://github.com/Integralist.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Node.js\n\n## What type of work is Node useful for?\n\nNode.js is great for common network application tasks such as those with heavy I/O (input/output) and requests to other services.\n\nIf you want to write an application that does a lot of expensive computations and calculations, you might want to consider moving these operations to other services that your Node applications can then call remotely.\n\nThis doesn't mean you should completely shy away from computationally intensive tasks. If you're doing these only some of the time, you can still include them in Node.js and take advantage of a method on the `process` global object called `nextTick`. This method basically says, \"Give up control of execution, and then when you have a free moment, call the provided function.\" It tends to be significantly faster than just using the `setTimeout` function.\n\nUsing `nextTick` plays much better in the single-threaded world of Node event processing and callbacks, and you can use `process.nextTick` in any situation in which you are worried that a complex or slow computation is necessary. Effectively think of it in the same way as using `setTimeout` for chunking large Arrays.\n\nSome developers believe that using `global.setImmediate` is better than `process.nextTick` because it avoids issues where `nextTick` doesn't yield to the event loop, and so `setImmediate` doesn't block other I/O.\n\n## General Node patterns\n\n### Naming your file\n\nName your main file `server.js`\n\n### Callbacks\n\nCallbacks generally utilise the pattern where by the first argument is an error parameter (this is either an error object or `null`). The second argument is the resulting data being passed through.\n\n### Errors\n\nIf there is an error then another pattern is to check if the error being passed through is a truthy value and if so call an error handler function and `return;` out of the current function.\n\n### Inline Callbacks\n\nInline callbacks should be kept and then a callback function passed in which we call if we find an error (we pass the error to it) and we call if there is a success (we pass null and then the success)...\n\n```js\nfunction loadFileContent (path, callback) {\n    fs.open(path, 'r', function (err, file) {\n        if (err) {\n            return callback(err);\n        } else if (!f) {\n            return callback({ error: \"invalid_handle\",\n                       message: \"bad file handle from fs.open\" });\n        } else {\n            callback(file);\n        }\n    });\n}\n```\n\nWhen outputting JSON data there should always be an `error` property and a `data` property. The `error` can be assigned `null` if there wasn't an error, otherwise it'll be a `String` message describing the error (as this is more descriptive than an error code which would otherwise need to be looked up first). The `data` property can be assigned whatever the resulting data is.\n\n### Returning Data/Values\n\nNode patterns indicate that devs like to return fast and early, but also the act of returning is generally considered to be for breaking the flow rather than needing the returned value.\n\nSo for example, instead of...\n\n```js\nif (err) {\n    displayError(err);\n    return;\n}\n```\n\n...you should do this...\n\n```js\nif (err) {\n    return displayError(err);\n}\n```\n\n...as in this example we don't care about the returned value, we're just running some code that displays an error but we also want to bail out of our current function as quickly as possible.\n\n## I/O (Streams not file system API)\n\nIt is generally considered a good idea to use Streams over the standard file system API.\n\nFor example, yes using `readFile` is async and so non-blocking (as per the benefits of using Node), but the buffer and memory of your application will get filled up (if it has lots of users making requests for that file at once) because that method stores up all the buffer content and then sends it, where as with Streams you can incrementally send data back to the client as it arrives thus emptying the buffer and memory of your application and allowing it to scale more easily.\n\n## Events\n\nIt's a common practice for Node code to inherit from Node's core event library...\n\n```js\nvar events = require('events');\n\nfunction Constructor(){}\n\nConstructor.prototype = new events.EventEmitter();\nConstructor.prototype.__proto__ = events.EventEmitter.prototype;\nConstructor.prototype.doSomething = function(){\n    this.emit('some:event', 'data to pass to listener');\n};\n```\n\n## Asynchronous work-arounds\n\nThere are a few ways to handle asynchronous operations in Node.\n\nYou can use a basic counter...\n\n```js\nfunction loadAlbumList (response, callback) {\n    var directories = [],\n        pattern = /(\\d)/g,\n        pagination = [],\n        counter = 0,\n        match;\n\n    fs.readdir(__dirname + '/albums/', function (err, files) {\n        if (err) {\n            return callback(response, err);\n        }\n\n        files.forEach(function (value) {\n            fs.stat('albums/' + value, function (err, stat) {\n                if (err) {\n                    callback(response, err);\n                    return callback = null; // overwrite the callback (see conditional check below)\n                }\n\n                if (stat.isDirectory()) {\n                    directories.push(value);\n                }\n\n                /*\n                    Using a basic counter is one way of handling asynchronous operations.\n                    Because this function's closure still has access to variables\n                    outside it we can use that to help us determine when to execute the callback.\n                 */\n                if (++counter === files.length \u0026\u0026 callback) {\n                    while ((match = pattern.exec(url_settings.query)) !== null) {\n                        pagination.push(match[1]);\n                        pattern.lastIndex++;\n                    }\n\n                    directories.splice(pagination[0] * pagination[1], pagination[1]);\n\n                    callback(response, null, directories);\n                }\n            });\n        });\n    });\n}\n```\n\n...or you can use a async library.\n\nThe following example uses the `after` module...\n\n```js\nfs.readdir(__dirname + '/albums/', function (err, files) {\n    if (err) {\n        return callback(err, response);\n    }\n\n    done = after(files.length, callback);\n\n    files.forEach(function (value) {\n        fs.stat('albums/' + value, function (err, stat) {\n            if (err) {\n                return done(err);\n            }\n\n            if (stat.isDirectory()) {\n                directories.push(value);\n            }\n\n            done(null, results);\n        });\n    });\n});\n```\n\n## Streams\n\nStreams are a powerful way to transfer large amounts of data in Node while maintaining the asynchronous, nonblocking nature of the system.\n\nYou listen to stream events on the `Request` object (like a standard event system), mainly the `readable` and `end` events.\n\nYou then `read()` the data coming in and once the `end` event fires, pass that read data into a callback function to do something with it.\n\n## HTTP Status'\n\n- 200 OK—Everything went fine.\n\n- 301 Moved Permanently—The requested URL has been moved, and the client should re-request it at the URL specified in the response.\n\n- 400 Bad Request—The format of the client’s request is invalid and needs to be fixed.\n\n- 401 Unauthorized—The client has asked for something it does not have permission to view. It should try again authenticating the request first.\n\n- 403 Forbidden—For whatever reason, the server is refusing to process this request. This is not the same as 401, where the client can try again with authentication.\n\n- 404 Not Found—The client has asked for something that does not exist.\n\n- 500 Internal Server Error—Something happened resulting in the server being unable to process the request. You typically use this error for situations in which you know the code has entered some sort of inconsistent or buggy state and needs developer attention.\n\n- 503 Service Unavailable—This indicates some sort of runtime failure, such as temporarily low on memory or having troubles with network resources. It’s still a fatal error like 500, but it does suggest the client could try again in a while.\n\n## RESTful APIs\n\nThe word `REST` comes from Representational State Transfer, and basically implies that you can request an accurate representation of an object from the server. REST APIs focus on four core operations (which, coincidentally, map to four HTTP request methods):\n\n- Creation (`PUT`)\n- Retrieval (`GET`)\n- Updating (`POST`)\n- Destruction (`DELETE`)\n\nSome people refer to these operations as CRUD, and pretty much everything you do in your API centers around doing one of these things to objects.\n\nTry to version your API so that users can opt-in to the particular version of your API. `domain.com/api/v1/albums/photos/`\n\n## Middleware\n\nBecause Express comes with Connect you can `use()` any of the middleware that connect can (as long as it's also mentioned in your package.json). For a list of middleware available see [http://www.senchalabs.org/connect/](http://www.senchalabs.org/connect/).\n\nExpress actually exposes these for you: `app.use(express.compress());`\n\n## Configuration and Node Environments\n\nTo run your app (using Express) with a particular configuration you'll need to set a `NODE_ENV` environment variable: `NODE_ENV=production \u0026\u0026 node program.js`, then you can use the `configure` method like so...\n\n```js\napp.configure('production', function(){\n    app.use(express.compress()); // only gzip on production\n\n    // OR set some variables...\n    app.set('log level', 'warningsOnly')\n});\n```\n\nYou can also set your `NODE_ENV` variable within your application using the global `process`: `process.env.NODE_ENV = 'development'`\n\nThese methods remain for backward compatability but the up to date way to do these checks is like so...\n\n```js\n// development only\nif () {\n  app.set('db uri', 'localhost/dev');\n}\n\n// production only\nif (app.get('env') === 'production') {\n  app.set('db uri', 'n.n.n.n/prod');\n}\n```\n\n## Databases\n\n### MongoDB\n\n- Install Database Server\n- Run Database Server\n- Using the interactive Shell\n- Make it work with Node using compatible Driver\n\n#### Install Database Server\n\nDownload from [http://www.mongodb.org/downloads](http://www.mongodb.org/downloads) and copy the contents of the folder (which is just a `bin` folder) to somewhere you'll remember, I did:\n\n`~/db/mongo/2.4.6/` (2.4.6 being the version number of the server)\n\nYou'll also need to create a folder to store your databases: `~/db/mongo/2.4.6/databases/` (you can see I just added a subfolder called `databases`)\n\n#### Run Database Server\n\nRun `mongod --dbpath ../databases` (from within the `bin` folder).\n\nNote: if you don't create a folder to store your databases then `mongod` can be run without the `--dbpath` flag and so will default to a `/data/db/` directory (if that doesn't exist then you'll want to create it as the database server will error otherwise).\n\n#### Using the interactive Shell\n\nTo run the interactive shell just type `mongo` (from within the `bin` folder). You can then see all databases using `show dbs` (you'll see when starting the server that a `local` database has been automatically created).\n\nWhen running the shell you only need to run the commands, nothing is persisted after the shell is closed.\n\nSo the shell has a `db` variable which tells you want database is in use. If you want to change databases use `use myNewDBName` then `db` will equal `myNewDBName`.\n\nYou can then insert records into that new database using `db.myTestCollection.insert({ name: \"Mark\" })` and then find that data using `db.myTestCollection.find()` which returns all records in the database.\n\nTo delete a database you create (either here in the shell or when running code\nthat creates a new database) first switch to using the database and the run\n`db.dropDatabase()`\n\nFor a reference to the full shell commands see [http://docs.mongodb.org/manual/reference/mongo-shell/](http://docs.mongodb.org/manual/reference/mongo-shell/)\n\n#### Make it work with Node using compatible Driver\n\nAdd `\"mongodb\": \"1.3.x\"` to your package.json file and run `npm install`\n\nTerminology is slightly different from traditional relational databases:\n\n- Tables = Collections\n- Rows = Documents\n- Cell = File\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintegralist%2Fnode-learning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintegralist%2Fnode-learning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintegralist%2Fnode-learning/lists"}