{"id":20840907,"url":"https://github.com/js-factory/ironhead","last_synced_at":"2025-05-08T22:06:17.469Z","repository":{"id":34068342,"uuid":"166654339","full_name":"js-factory/ironhead","owner":"js-factory","description":"Functional and Declarative NodeJS Framework.","archived":false,"fork":false,"pushed_at":"2022-12-10T16:41:51.000Z","size":503,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-08T22:06:08.125Z","etag":null,"topics":["configurable","express","functional-programming","javascript","nodejs","routing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/js-factory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-20T11:39:14.000Z","updated_at":"2021-02-23T10:43:25.000Z","dependencies_parsed_at":"2023-01-15T04:22:52.536Z","dependency_job_id":null,"html_url":"https://github.com/js-factory/ironhead","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/js-factory%2Fironhead","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/js-factory%2Fironhead/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/js-factory%2Fironhead/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/js-factory%2Fironhead/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/js-factory","download_url":"https://codeload.github.com/js-factory/ironhead/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253154974,"owners_count":21862622,"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":["configurable","express","functional-programming","javascript","nodejs","routing"],"created_at":"2024-11-18T01:18:13.109Z","updated_at":"2025-05-08T22:06:17.438Z","avatar_url":"https://github.com/js-factory.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Ironhead \n======\nNodeJS Framework over [express](https://github.com/expressjs/express) based on functional and declarative programming.\n\n\n# Motivation\n\n\u003e In typical fast pace dev environment, code review is a challenge and simply causes more and more tech debt. Functional Programming enables developers to refactor a simple program or function. Taking control over execution reduces repetitive work to be done by programmer and eventually help in reducing number of lines of code to be written.\n\n\n#### Key features\n1. Code decoupling.\n2. Functional programming.\n3. Clear boundries between presentation and business logic.\n4. Declarative program.\n5. Refactoring smaller functions are much more easy.\n\n\n#### MVC\n\u003e MVC pattern has severed us exceptionally well over the period and still does. But it's no more fit for our next generation UI framework.\n\n\n## Contents\n\n1. [Routes](#router)\n2. [Middleware](#middleware)\n3. [Views](#views---templaing-engine)\n4. [Userhooks](#userhooks)\n5. [Configuration](#configuration)\n7. [Custom Path Configuration for components](#custom-path-configuration)\n\n## Router\n\n**Route** is plain javascript object. It defines how a particular http request will be handled by the web application.\n\nAnd here's sample **route**!\n\n```javascript\n// routes/foo.js\nconst requestSchema = require('../schema/request/foo');\nconst responseSchema = require('../schema/response/foo');\nconst gateway = require('../gateway/foo.js');\nconst { fn1, fn2 } = require('../dekorators');\nconst prehandler = require('../prehandler/foo');\n\nmodule.exports = {\n    domain: 'index',\n    method: 'GET',\n    url: '/',\n    template: 'index',\n    responseType: 'html',\n    allowRedirect: false,\n    isReqValidation: true,\n    schema: {\n        ...requestSchema,\n        ...responseSchema\n    },\n    prehandlers: [\n       prehandler\n    ],\n    gateway,\n    dekorators: [  \n    \tfn1,\n        fn2\n    ]\n};\n\n// sample url - https://www.example.com/?cid=foo\u0026pos=0\n// request schema\n// schema/request/foo.js\nmodule.exports = {\n    query: {\n        type: 'object',\n        properties: {\n            cid: { type: 'string' },\n            pos: { type: 'integer' },\n        },\n        required: ['cid']\n    },\n    cookies: {\n        type: 'object',\n        properties: {\n            sid: { type: 'string' }\n        },\n        required: ['sid']\n    },\n    config: {\n        type: 'object',\n        properties: {\n            showWelComeMessage: { type: 'boolean' }\n        }\n    }\n}\n\n// response schema\n// schema/response/foo.js\nmodule.exports = {\n\tresponse: {\n        ok: { // A successful response\n            type: 'array',\n            items: {\n                type: 'object',\n                properties: {\n                    id: { type: 'integer' },\n                    fkc: { type: 'integer' }\n                }\n            }\n        },\n        notOk: { // Unsuccessful response\n        \tbadReq: { // Bad request \n            \tsuccess: false,\n                error: {\n                \tstatusCode: 1001,\n                    message: ''\n                },\n                data: {}\n            },\n            badRes: { // Api failed or some other exception\n            \tsuccess: false,\n                error: {\n                \tstatusCode: 400, // 4xx, 5xx\n                    message: ''\n                },\n                data: {}\n            }\n        }\n    }\n};\n\n```\n\n#### Route Schema\n- **domain -:** You may want to group your application into different pages or modules. You can define these logical grouping in the route. \n\n- **method -:** An  [HTTP verb](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) i.e. GET or POST \n- **url -:** External url to be handled by the application\n- **responseType -:** Http Response format  \u003cbr/\u003e\n  ```javascript \n  ResponseType Options: html|json\n  Default Value: json\n\t```\n\t****\u003csmall\u003eNote -:**** If it is set to json, template will be ignored and json response will be sent to client \u003c/small\u003e\n- **allowRedirect -:** Allow http redirect 301|302. If the flag is set true framework attach redirect middleware which expect a redirect node in the decorators output.\n  ```javascript\n  {\n      ... // other props\n      redirect: {\n          code: 302, // Default value 302, other option 301\n          path: '/' // if path is not provided it will redirect to referrer\n      }\n  }\n\n  ```\n- **isReqValidation -:** It enables request validation. If validation fails it will respond with `schema.response.notOk.badReq` defined in response schema.\n- **template -:** A template file path. The template will be used to prepare html response when `responseType` is set to `html`\n- **schema -:** A request and response validator. Also it filters the data and send only those defined in the shcema. Please refer [AJV](http://epoberezkin.github.io/ajv/) documentations for further details. Refer above route definition for more details.\n\n- **prehandlers -:** \nA `pre handler` is a plain JavaScript function. It has access to request parameters such as query params, path params, cookies, request body, headers etc. Developer can use these parameters and modify them for future use during request lifecycle.\nA prehandler gets access to properties defined in the request schema.\n\n- **gateway -:** A `gateway` is bridge between your application and external systems i.e. rest apis, databases etc. `gateway` attaches final response into response. Your application response module can access it calling `res.props('data');\n\n```js\n// express middleware\n// sendToClinet.js\n\nconst sendToClinet = (req, res) =\u003e {\n    const data = res.props('data');\n    // application logic ...\n    // application logic ...\n    if(sendJson) {\n        return res.json(data);\n    }\n    return res.render('templateName', data);\n}\n\n```\n\n- **dekorators -:** A `dekorator` is a pure javascript function that can bind to certain properties of bigger response, it can modify the data. A dekorator must return an object. Having dekorator in place offers you to define functions with single responsibility.\n\n```javascript\n// Simple dekorator\n\n// title.js\n\nconst title = (props) =\u003e {\n    const { name, brand, done } = props; // dispatch is injected by connect.\n    const newName = name.replace(brand.name, '');\n\n    return done({\n        name: newName   // name is propery in initial state\n    });\n  };\n\n  module.exports = connect(['name', 'brand'], title);\n\n```\n\n\n## Middleware\n\n**Middlewares** are the functions which are executed in the middle of \u003ci\u003erequest response cycle\u003c/i\u003e.\n\n**Custom Middlewares** definition is similar to middlewares\n\nAnd here's how you define the custom **middlewares** and its **execution chain!!**\n\n```javascript\n// Defining middleware chain\n\n\n// Custom Middlewares definition\nconst {\n\tresponseFactory,\n    notFound,\n    defaultErrorHandler\n} = require('./app/middleware');\n\n{\n    order: [\n        'cookieParser',\n        ....\n        ....\n        .....\n        'router',\n        'responseFactory',\n        'notFound',\n        'defaultErrorHandler'\n    ],\n    {\n        responseFactory,\n        notFound,\n        defaultErrorHandler\n    }\n}\n\n```\n\n```javascript\n// Default Error handler\nconst defaultErrorHandler = (err, req, res, next) =\u003e {\n};\n\n// Custom Middleware Definition\nconst customMiddleware = (req, res, next) =\u003e {};\n```\n\n#### Order\nIt is an array in which we can define the execution order of the middlewares. One can specify the custom middlewares and some are given to the application by the framework like:\n\n1. **Cookie Parser** - `cookieParser` key to be used in **order**.\n2. **Router** - `router` key to be used in **order**.\n\n#### Cookie Parser\nIt is a middleware which is offered by the framework and it internally uses [Cookie-Parser](https://github.com/expressjs/cookie-parser) by express.\n\n\u003e NOTE: For signing the cookies with a secret, one should use cookies configuration.\n\n#### Router\nIt is also a middleware, which needs to be plugged in **order** list and the **routes** declared by the application will be executed at that particular point in the \u003ci\u003erequest response lifecycle \u003c/i\u003e.\n\n\n## Views - templaing engine\n\nA templating engine/view engine enables the application to use static templates files to genarate HTML which is rendered at the client side.\n\nAnd here's the example of configuring the `Template/View Engine`!!\n\n```javascript \n // config/views.js\n \n module.exports = {\n \tengine: \u003cengine\u003e\n };\n```\n\n*Templates path* can be configured using **rc configuration**\n\nFramework Supports **express-compliant** template engines. More about it can be explored at [Express Template Engines](https://expressjs.com/en/guide/using-template-engines.html)\n\n## Userhooks\n\n***Hooks*** are an array of functions that are executed prior to application binding. Only after successfull execution of all the hooks, **Application** binds to the specified port.\n\nAnd here's the sample **hook!!**\n\n```javascript\n\n// Custom Hook definition\nfunction customHook(app, cb) {\n    try {\n        app.setLocals('key', 'value');\n    } catch (err) {\n        console.log('\\n---------------------------------------------------\\n');\n        console.error('Error.');\n        console.log('\\n---------------------------------------------------\\n');\n    }\n    cb();\n}\n```\n\n**Custom Hook** receives two arguments:\n\n1. **app** - \u003ci\u003eApplication Instance\u003c/i\u003e\n2. **cb** - \u003ci\u003eCallback function\u003c/i\u003e\n\n\n\u003e NOTE: **cb** function must be called otherwise your application won't start.\n\n## Configuration\n\nFramework supports the **default** and **environment** configs.\n\n####  Config - `config/*`\n\n`config/config.js` It should contain the default configuration of the application.\n\nAnd here's the sample to define the configuration, to set the **secret** value of the **cookies** for sigining and **port**!!\n\n```javascript\n// secret will be used by cookie parser for signing the cookies\nmodule.exports = {\n    cookie: {\n        secret: '123123123'\n    },\n    port: 1447\n};\n```\n\n#### Environment Config - `/config/env/*`\n\n**NODE_ENV** defines the environment of the application and depending on that **environment** config is loaded.\n\nIf no `environment` is set, it will try to load the **development.js**\n\n\u003e NOTE: Environment configs overrides the default configuration.\n\n## Custom path configuration\n\nOne can specify the custom path for components.\n\n```\n{\n    \"cluster\": true,\n    \"paths\": {\n        \"config\": '/config',\n        \"routes\": '/app/routes',\n        \"middleware\": '/app/middleware',\n        \"hooks\": \"/app/hooks\",\n        \"views\": \"/public/templates\"\n\n    }\n}\n\n```\n\n## Concept and Fundamentals\n---\n\n\u003ePrehandlers, gateway, dekorators must follow [functional programming](https://www.youtube.com/watch?v=e-5obm1G_FY) fundamentals. Please refer below resources for more details\n\n[******Learning Functional Programming with JavaScript - JSUnconf 2016******](https://www.youtube.com/watch?v=e-5obm1G_FY)\u003cbr/\u003e\n[******Master Functional Programming******](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0)\n\n---\n\n## License\n\n  [MIT](LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjs-factory%2Fironhead","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjs-factory%2Fironhead","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjs-factory%2Fironhead/lists"}