{"id":19671503,"url":"https://github.com/kashi93/nolla","last_synced_at":"2025-04-29T00:33:40.296Z","repository":{"id":63753769,"uuid":"547441499","full_name":"kashi93/nolla","owner":"kashi93","description":"Nolla was inspired by the laravel framework.","archived":false,"fork":false,"pushed_at":"2023-09-18T16:04:53.000Z","size":6390,"stargazers_count":19,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2023-09-18T21:49:48.152Z","etag":null,"topics":["clone-laravel","express","expressjs","framework","middleware","nodejs","nodejs-framework","nolla","router","typescript"],"latest_commit_sha":null,"homepage":"","language":"EJS","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/kashi93.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":"2022-10-07T17:34:55.000Z","updated_at":"2023-09-18T21:49:48.153Z","dependencies_parsed_at":"2023-02-18T19:16:01.063Z","dependency_job_id":null,"html_url":"https://github.com/kashi93/nolla","commit_stats":null,"previous_names":[],"tags_count":2,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kashi93%2Fnolla","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kashi93%2Fnolla/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kashi93%2Fnolla/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kashi93%2Fnolla/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kashi93","download_url":"https://codeload.github.com/kashi93/nolla/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224142752,"owners_count":17262884,"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":["clone-laravel","express","expressjs","framework","middleware","nodejs","nodejs-framework","nolla","router","typescript"],"created_at":"2024-11-11T17:09:00.970Z","updated_at":"2024-11-11T17:09:01.827Z","avatar_url":"https://github.com/kashi93.png","language":"EJS","readme":"\n- [Nolla](#nolla)\n- [Installation](#installation)\n    - [Scaffold](#scaffold)\n    - [Database](#database)\n- [The Basics](#the-basics)\n  - [Routing](#routing)\n    - [Basic Route](#basic-route)\n    - [Available Router Methods](#available-router-methods)\n    - [Required Parameters](#required-parameters)\n    - [Named Routes](#named-routes)\n    - [Middleware](#middleware)\n    - [Route Prefixes](#route-prefixes)\n    - [Controller Namespace](#controller-namespace)\n    - [The Route List](#the-route-list)\n  - [Middleware](#middleware-1)\n    - [Defining Middleware](#defining-middleware)\n    - [Registering Middleware](#registering-middleware)\n    - [Assigning Middleware To Routes](#assigning-middleware-to-routes)\n  - [Controllers](#controllers)\n    - [Basic Controller](#basic-controller)\n    - [Params Controller](#params-controller)\n  - [Requests](#requests)\n    - [Retrieving An Input Value](#retrieving-an-input-value)\n    - [Retrieving An Input File](#retrieving-an-input-file)\n    - [Old Input](#old-input)\n  - [Responses](#responses)\n    - [Basic Response](#basic-response)\n    - [View response](#view-response)\n    - [Override nolla response](#override-nolla-response)\n  - [Views](#views)\n    - [Rendering Views](#rendering-views)\n    - [Passing Data To Views](#passing-data-to-views)\n  - [Validation](#validation)\n    - [Writing The Validation Logic](#writing-the-validation-logic)\n    - [Displaying The Validation Errors](#displaying-the-validation-errors)\n    - [Available Validation Rules](#available-validation-rules)\n      - [Required](#required)\n      - [Email](#email)\n      - [Minimum](#minimum)\n      - [Maximum](#maximum)\n      - [Confirmation](#confirmation)\n      - [Mimes](#mimes)\n      - [Custom](#custom)\n      - [Optional](#optional)\n  - [Database](#database-1)\n    - [Migrations](#migrations)\n      - [Generating Migrations](#generating-migrations)\n      - [Available Column Types](#available-column-types)\n      - [Running Migrations](#running-migrations)\n    - [Running Raw SQL Queries](#running-raw-sql-queries)\n  - [Model](#model)\n    - [Generating Model Classes](#generating-model-classes)\n    - [Model Attributes](#model-attributes)\n      - [Table Name](#table-name)\n      - [Timestamps](#timestamps)\n      - [Hidden](#hidden)\n    - [Available Method](#available-method)\n      - [Create](#create)\n      - [Where](#where)\n      - [OrWhere](#orwhere)\n      - [Update](#update)\n      - [Delete](#delete)\n\n\n# Nolla\nNolla inspired from laravel framework,our goal is to make Laravel developer don't feel awkward when migration from laravel to node.We'll help you take your first steps as a web developer or give you a boost as you take your expertise to the next level. We can't wait to see what you build.\n\n# Installation\n\n### Scaffold\n\nTo get started, you can scaffold the project with a clone of a starter project.\n\n```\ngit clone https://github.com/kashi93/nolla.git project\ncd project\ncp .env.example .env\nnpm install\nnpm run serve\n```\n\n\nAlternatively, to serve project without npm : \n\n**Production**\n\n```\nnpm run build\nnode build/nolla serve\n```\n\n**Development**\n\n```\nts-node lib/nolla serve\n```\n\n### Database\n\n\n\nCreate an empty mysql database for your project. In our example we created a database called “nolla”. Just create an empty database here, the exact steps will depend on your system setup.\n\n\n\nSync your created database with our project in your .env file for the database part.\n\n\n```\nDB_CONNECTION=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_DATABASE=nolla\nDB_USERNAME=root\nDB_PASSWORD=\n```\n\n\n\nMigrate the database.\n\n```\nts-node lib/nolla migrate\n```\n\n\n\nIn default migrations, the database is users and migrations table.\n\n# The Basics\n\n## Routing\n\n\n\nThe routes directory contains all of the route definitions for your application. By default directory : \n\n```\nlib/routes/web.ts\n```\n\n### Basic Route\n\n\n\n```\nimport { default as Route } from \"../vendor/route/route\";\n\nRoute.get(\"/\", function () {\n  return view(\"welcome\");\n});\n```\n\n### Available Router Methods\n\n\n\nThe router allows you to register routes that respond to any HTTP verb :\n\n\n\n```\nRoute.get(url: string,argv: [controllerClassPath: string,method: string] | Function);\nRoute.post(url: string,argv: [controllerClassPath: string,method: string] | Function);\n```\n\n### Required Parameters\n\nSometimes you will need to capture segments of the URI within your route.\n\n\n\n**Route**\n\n\n\n```\nRoute.get(\"/user/:id/edit\", [\"user.controller\", \"edit\"])\n```\n\n**Controller**\n\n\n\n```\nclass UserController extends Controller {\n    async edit(id) {\n        return `user id is ${id}`;\n    }\n}\n\nexport = UserController;\n```\n\n### Named Routes\n\nNamed routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the name method onto the route definition:\n\n```\nRoute.get(\"/\", [\"user.controller\", \"index\"]).name(\"user.index\");\n```\n\n### Middleware\n\nTo assign middleware to all or specific routes.\n\n```\nRoute.middleware(\"auth\", () =\u003e {\n    Route.get(\"/\", [\"user.controller\", \"index\"]).name(\"user.index\");\n});\n```\n\n### Route Prefixes\n\nThe prefix method may be used to prefix each route in the group with a given URI.\n\n```\nRoute.prefix(\"admin\", () =\u003e {\n    Route.get(\"/users\", [\"user.controller\", \"index\"]).name(\"user.index\");\n    // Matches The \"/admin/users\" URL\n});\n```\n\n### Controller Namespace\n\nBy default controller namespace.\n\n```\nRoute.controllerNameSpace(\"/app/controllers/\", () =\u003e\n    Route.middleware(\"web\", () =\u003e require(\"../../routes/web\"))\n);\n```\n\nYou can refer to route providers.\n\n```\nlib/app/services/route.service.ts\n```\n\n### The Route List\n\nThe route:list command can easily provide an overview of all of the routes that are defined by your application:\n\n```\nts-node lib/nolla route:list\n```\n\n## Middleware\n\n### Defining Middleware\n\nDefault directory for middleware is lib/app/middlewares.For example we create  lib/app/middlewares/auth.middleware.ts\n\n```\nimport { Request, Response, Next } from \"../../\";\n\nexport = (req: Request, res: Response, next: Next) =\u003e {\n  if (auth.user() == null) {\n    /*\n     * redirect to router\n     */\n    return response.redirect(route(\"login\"));\n\n    /*\n     * redirect using express response\n     */\n    // return res.status(403).json({\n    //   status: \"Error\",\n    //   message: \"Unauthenticated\",\n    //   data: {},\n    // });\n  }\n  next();\n};\n```\n\n### Registering Middleware\n\nTo register middleware for the HTTP request to your application, list the middleware in lib/config/app.ts\n\n```\n{\n    ...,\n    routeMiddleware: {\n        web: \"app/middlewares/web.middleware\",\n        auth: \"app/middlewares/auth.middleware\",\n    },\n}\n```\n\n### Assigning Middleware To Routes\n\n```\nRoute.middleware(middleware: string[] | string, routes: Function);\n```\n\n## Controllers\n\nBy default, controllers are stored in the lib/app/controllers/example.controller.ts directory.\n\n### Basic Controller\n\n```\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  create() {\n    return view(\"nolla/pages/user/user_create_form\", {\n      layout: \"nolla/templates/app\",\n    });\n  }\n}\n\nexport = UserController;\n```\n\nAssigning controller To Routes\n\n```\nRoute.get(url: string,argv: [controllerClassPath: string, method: string] |Function)\n```\n\n### Params Controller\n\n```\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n async edit(id: string) {\n    const user = await userModel.where(\"id\", \"=\", id).first();\n    return view(\"nolla/pages/user/user_edit_form\", {\n      layout: \"nolla/templates/app\",\n      user,\n    });\n  }\n}\n\nexport = UserController;\n```\n\nBy default routes return to controller.\n\n```\n() =\u003e arg...,req,res\n```\n\nAssigning controller To Routes\n\n```\nRoute.get(\"/user/:id/edit\", [\"user.controller\", \"edit\"])\n```\n\n## Requests\n\nNolla request is extended from the default express request.\n\n### Retrieving An Input Value\n\n```\nreq.body || req.query = input(field:string) =\u003e any\n```\n\n```\nconst name = request.input(\"name\");\n```\n\n### Retrieving An Input File\n\n```\nFile {\n  fieldname: string;\n  originalname: string;\n  encoding: string;\n  mimetype: string;\n  destination: string;\n  filename: string;\n  path: string;\n  size: number;\n  move: (publicPath?: string, name?: string) =\u003e Promise\u003cstring | null\u003e;\n}\n```\n\n```\nif (request.$file(\"test\") != null) {\n    await request.$file(\"test\").move(\"images\");\n}\n```\n\n### Old Input\n\nBy default we keep input from one request during the next request.\n\n```\n\u003cinput type=\"text\" class=\"form-control\" name=\"name\" value=\"\u003c%= old(\"name\")  %\u003e\" /\u003e\n```\n\n## Responses\n\nNolla response is extended from the default express response.\n\n### Basic Response\n\n```\nRoute.get(\"/\", function () {\n  return \"Welcome to nolla\";\n});\n```\n\n```\nRoute.get(\"/\", function () {\n  return [1,2,3];\n});\n```\n\n```\nRoute.get(\"/\", function () {\n  return {\n    name:\"nolla\",\n    active:true\n  };\n});\n```\n\n### View response\n\n```\nRoute.get(\"/\", function () {\n  return view(\"nolla/pages/user/user_create_form\");\n});\n```\n\n### Override nolla response\n\n```\nRoute.get(\"/\", function (req,res) {\n    return res.status(200).json({\n      user:{\n        name:\"nolla\",\n        active:true\n      }\n    });\n});\n```\n\n## Views\n\nNolla views using the ejs package and is stored in the lib/resources/views directory. You can refer to https://ejs.co/\n\n### Rendering Views\n\n```\nview: (path: string, data?: { [key: string]: any }) =\u003e void\n```\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  create() {\n    return view(\"nolla/pages/user/user_create_form\");\n  }\n}\n```\n\n### Passing Data To Views\n\n```\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async edit(id: string) {\n    const user = await userModel.where(\"id\", \"=\", id).first();\n    return view(\"nolla/pages/user/user_edit_form\", {\n      user,\n    });\n  }\n}\n```\n\n## Validation\n\nNolla validation is extended from express-validator package.\n\n### Writing The Validation Logic\n\n```\nvalidate(req: Request,rule: {[field: string]: Rules[]},sentBack: boolean = true) =\u003e Promise\u003cany[] | boolean\u003e;\n```\n\n```\nimport { Request } from \"../../\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n   async store(req: Request) {\n    const validate = await this.validate(req, {\n      name: [\"required\"],\n      email: [\n        \"required\",\n        \"email\",\n        async function (attr: string, val: any, fail: Function) {\n          if (\n            (await userModel\n              .where(\"email\", \"=\", request.input(\"email\"))\n              .first()) != null\n          ) {\n            fail(\"The email has already been taken.\");\n          }\n        },\n      ],\n      password: [\"required\", \"min:5\", \"max:8\"],\n      password_confirmation: [\"required\", \"confirmation:password\"],\n    });\n\n    if (validate) {\n      // The validation is valid...\n    }\n  }\n}\n```\n\n### Displaying The Validation Errors\n\n```\n\u003cdiv class=\"col-6\"\u003e\n  \u003cdiv class=\"form-group\"\u003e\n    \u003clabel\u003eName\u003c/label\u003e\n    \u003cinput type=\"text\" class=\"form-control\" name=\"name\" value=\"\u003c%= old(\"name\")  %\u003e\" /\u003e\n    \u003c% if (errorHas('name')) { %\u003e\n       \u003cdiv class=\"text-danger m-1\"\u003e\u003c%=message%\u003e\u003c/div\u003e\n    \u003c% } %\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n### Available Validation Rules\n\n#### Required\n\n```\nname: [\"required\"]\n```\n\n#### Email\n\n```\nemail: [\"email\"]\n```\n\n#### Minimum\n\n```\nfield:`min:${number}`\n```\n```\npassword: [\"min:5\"]\n```\n\n#### Maximum\n\n```\nfield:`max:${number}`\n```\n```\npassword: [\"max:8\"]\n```\n\n#### Confirmation\n\n```\npassword: [\"required\", \"min:5\", \"max:8\"],\npassword_confirmation: [\"required\", \"confirmation:password\"]\n```\n\n#### Mimes\n\n```\nimage: [\"mimes:jpeg,svg\"]\n```\n\n#### Custom\n\n```\nfield:Function\n```\n\n```\nemail: [\n  ...,\n  async function (attr: string, val: any, fail: Function) {\n    if ((await userModel.where(\"email\", \"=\", request.input(\"email\")).first()) != null) {\n      fail(\"The email has already been taken.\");\n    }\n  },\n]\n```\n\n#### Optional\n\n```\nimage: [\"nullable\", \"mimes:jpeg\", \"min:528\"]\n```\n\n## Database\n\nNolla database is extended from node mysql package.\n\n### Migrations\n\n#### Generating Migrations\n```\nts-node lib/nolla create:migration -n=books\n```\n\n#### Available Column Types\n\n| Command                                    | MySql                                                                  |\n| ------------------------------------------ | ---------------------------------------------------------------------- |\n| Table.id(column = \"id\")                    | {{column}} BIGINT NOT NULL AUTO_INCREMENT , PRIMARY KEY ( {{column}} ) |\n| Table.bigInt(column: string)               | {{column}} BIGINT NOT NULL                                             |\n| Table.string(column: string, length = 255) | {{column}} VARCHAR(${length}) NOT NULL                                 |\n| Table.timestamp(column: string)            | {{column}} TIMESTAMP NOT NULL                                          |\n| Table.timestamps()                         | created_at TIMESTAMP NULL , updated_at TIMESTAMP NULL                  |\n| Table.nullable()                           | {{current_params}} NULL                                                |\n| Table.unique()                             | {{current_params}} UNIQUE                                              |\n| Table custom(statement: string)            | -                                                                      |\n\n#### Running Migrations\n```\nts-node lib/nolla migrate\n```\n\n### Running Raw SQL Queries\n\n```\nimport { execute } from \"../../vendor/database/mysql/model/builder/execute\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async index() {\n    const users = await execute(\"SELECT * FROM users\");\n    console.log(users);\n  }\n}\n```\n\n## Model\n\n### Generating Model Classes\n\nModels generated by the create:model command will be placed in the lib/app/models directory.\n\n```\nts-node lib/nolla create:model -c=Book --tn=books\n```\n\nRequired Argument\n\n| argument     | alias | Description            |\n| ------------ | ----- | ---------------------- |\n| --class      | -c    | Name of model          |\n| --table_name | --tn  | name of database table |\n\n\n### Model Attributes\n\n#### Table Name\n\nThe attributes to sync database with model\n\n```\nimport { default as Model } from \"../../vendor/database/mysql/model\";\n\nclass UserModel extends Model {\n  constructor() {\n    super();\n    this.table = \"users\";\n  }\n}\n\nexport = new UserModel();\n```\n\n#### Timestamps\n\nBy default, nolla expects the created_at and updated_at column exists in the database table. These column values are automatically set when models are created or updated.\n\n```\nimport { default as Model } from \"../../vendor/database/mysql/model\";\n\nclass UserModel extends Model {\n  constructor() {\n    super();\n    this.useTimeStamps = true;\n  }\n}\n\nexport = new UserModel();\n```\n\n#### Hidden\n\nThe attributes that should be hidden for response serialization.\n\n```\nimport { default as Model } from \"../../vendor/database/mysql/model\";\n\nclass UserModel extends Model {\n  constructor() {\n    super();\n    this.hidden = [\"password\"];\n  }\n}\n\nexport = new UserModel();\n```\n\n### Available Method\n\n#### Create\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async store(req: Request) {\n    await userModel.create({\n        name: request.input(\"name\"),\n        email: request.input(\"email\"),\n        password: await hash.make(request.input(\"password\")),\n      });\n    return response.redirect(route(\"user.index\"));\n  }\n}\n```\n\n#### Where\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async edit(id: string) {\n    const user = await userModel.where(\"id\", \"=\", id).first();\n    return view(\"nolla/pages/user/user_edit_form\", {\n      layout: \"nolla/templates/app\",\n      user,\n    });\n  }\n}\n```\n\n#### OrWhere\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async edit(id: string) {\n    const user = await userModel.where(\"id\", \"=\", id)\n    .orWhere(\"name\",\"=\",\"nolla\")\n    .first();\n    return view(\"nolla/pages/user/user_edit_form\", {\n      layout: \"nolla/templates/app\",\n      user,\n    });\n  }\n}\n```\n\n#### Update\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async update(id: string, req: Request) {\n   const data: { [key: string]: any } = {\n        name: request.input(\"name\"),\n        email: request.input(\"email\"),\n      };\n\n    if (request.input(\"password\") != null) {\n      data.password = await hash.make(request.input(\"password\"));\n    }\n\n    await userModel.where(\"id\", \"=\", id).update(data);\n\n    return response.redirect(route(\"user.index\"));\n  }\n}\n```\n\n#### Delete\n\n```\nimport { Request } from \"../../\";\nimport { default as hash } from \"../../vendor/rainbows/hash\";\nimport { default as userModel } from \"../models/user.model\";\nimport Controller from \"./controller\";\n\nclass UserController extends Controller {\n  async destroy(id: string) {\n    await userModel.where(\"id\", \"=\", id).delete();\n    return response.redirect(route(\"user.index\"));\n  }\n}\n```\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkashi93%2Fnolla","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkashi93%2Fnolla","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkashi93%2Fnolla/lists"}