{"id":15675361,"url":"https://github.com/joelibaceta/hack-er","last_synced_at":"2026-02-24T02:32:27.624Z","repository":{"id":147422751,"uuid":"307499930","full_name":"joelibaceta/hack-er","owner":"joelibaceta","description":"How to build a web micro framework using hack, we have called it Hack-er, this initiative was born to bring more developers to be closer to hack, simplifying the first steps thought a tutorial.","archived":false,"fork":false,"pushed_at":"2020-10-27T20:44:23.000Z","size":2813,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-12T13:32:49.190Z","etag":null,"topics":["2020","facebook","hack","hack-lang","hackathon","hhvm","tutorial"],"latest_commit_sha":null,"homepage":"","language":"Hack","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/joelibaceta.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-10-26T20:45:47.000Z","updated_at":"2024-03-19T12:57:37.000Z","dependencies_parsed_at":"2024-02-16T05:44:39.001Z","dependency_job_id":null,"html_url":"https://github.com/joelibaceta/hack-er","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/joelibaceta/hack-er","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelibaceta%2Fhack-er","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelibaceta%2Fhack-er/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelibaceta%2Fhack-er/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelibaceta%2Fhack-er/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joelibaceta","download_url":"https://codeload.github.com/joelibaceta/hack-er/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joelibaceta%2Fhack-er/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29769176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T01:40:24.820Z","status":"online","status_checked_at":"2026-02-24T02:00:07.497Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["2020","facebook","hack","hack-lang","hackathon","hhvm","tutorial"],"created_at":"2024-10-03T15:58:55.160Z","updated_at":"2026-02-24T02:32:27.599Z","avatar_url":"https://github.com/joelibaceta.png","language":"Hack","readme":"\u003cimg src=\"docs/main2.gif\" width=\"100%\"/\u003e\n\n\u003c/br\u003e\n\u003c/br\u003e\n\u003c/br\u003e\n\n# Discovering Hack \n## How to start building a microframework using hack language\n\nIn this tutorial we will learn how to build your first website written completly using Hack.\n\nThe objective of this tutorial is to make an extra contribution to existing documentation, to allow more developers to adopt hack in an easier way, through showing a step-by-step tutorial for building your first website using hack.\n\n\u003c/br\u003e\n\n**Pre requirements**\n\n- hhvm 4.80.0 or major\n- Composer installed\n\n\u003c/br\u003e\n\n## Let's begin, as always everything starts with a \"hello world\"\n\nTo write our first hack website we have to create an index.hh file with a main entry point as follows:\n\n```\n\u003c\u003c__EntryPoint\u003e\u003e\nfunction main(): void {\n  echo \"\u003ch1\u003eHello World\u003c/h1\u003e\";\n}\n```\n\nThen run hhvm in server mode, executing `hhvm -m server -p 8080` in your command line located in your the same folder that your script are.\n\nOpen your favorite browser, go to \"http://localhost:8080/index.hh\" and check your brand new website. \n\n![](docs/1.png)\n\n\u003cbr/\u003e\n\n\u003cimg src=\"docs/meme2.jpg\" width=\"200\"\u003e\n\n## But ... we are going to need manage routes ... \n\nThat is true, let's create a route manager\n\n```\nclass Router {\n  \\\\ ... \n}\n```\n\nNow, we have to save our route params as controller and action names, we are goint to use `index.hh/controller/action` format, on this way we can use `proxy_pass` in our webservers to bypass the requested routes to our application.\n\n![](docs/step1.png)\n\nTo reach this goal we have to preprocess our request uri in order to extract the segments which contains or values.\n\n```php\npublic function __construct($server) {\n \n  $this-\u003equery_string = $server[\"QUERY_STRING\"]; \n  $request_url = (isset($server['REQUEST_URI'])) ? $server['REQUEST_URI'] : '';\n  $script_url  = (isset($server['PHP_SELF'])) ? $server['PHP_SELF'] : '';\n  $url = str_replace('src/index.hh/', '', $script_url);\n  $segments = explode('/', $url);\n\n  if(isset($segments[1]) \u0026\u0026 $segments[1] != '') $this-\u003econtroller = $segments[1];\n  if(isset($segments[2]) \u0026\u0026 $segments[2] != '') $this-\u003eaction = $segments[2];\n\n}\n```\n\nNow we hava stored our controller and action names in `$controller` and `$action` instance variables.\n\nFinally we have to build an `apply` method to run the routing process when we receive an http request, for this, we just call to the controller method according with the controller and action names as follows:\n\n```php\n  public function apply(): void{\n\n    $path = __DIR__ . '/../src/controllers/' . $this-\u003econtroller . '.hh';\n\n    $controller_name = mb_convert_case($this-\u003econtroller, MB_CASE_TITLE, \"UTF-8\") . \"Controller\";\n    $action_name = $this-\u003eaction;\n\n    if (file_exists($path)) {\n      require_once($path); \n        if(!method_exists($controller_name, $this-\u003eaction)){\n          echo \"Method not found\";\n        } else {\n          $obj = new $controller_name();\n          $obj-\u003e$action_name();\n        }\n    } else {\n      echo $path;\n       echo \"Invalid route\";\n    }\n\n  }\n```\n\n\u003e We recommend save your application files within a `src`folder, to differentiate them from our micro framework files.\n\n\u003cbr/\u003e\n\n\u003cimg src=\"docs/meme3.jpeg\" width=\"200\"\u003e\n\n## Ok, thats sounds good but ... how can I use it?\n\nOk, first we have to write additional code to our `index.hh` file.\n\n```php\n\u003c\u003c__EntryPoint\u003e\u003e\nasync function main(): Awaitable\u003cvoid\u003e {\n\n  require_once(__DIR__.'/vendor/autoload.hack');\n  require_once(__DIR__.'/lib/router.hh');\n\n  $path = basename($_SERVER['REQUEST_METHOD']);\n\n  $router = new Router($_SERVER);\n  $router-\u003eapply(); \n\n}\n```\n\nThen you have to create your first controller inside of `src/controllers` folder, and write a simple index method which will be called by the router.\n\n```php\nclass GreetingsController {\n\n  public function index(): void{\n    echo \"\u003ch1\u003e Hello World from your first controller\u003c/h1\u003e\"\n  }\n\n}\n```\n\nLet's run our server `hhvm -m server -p 8080` and go to `http://localhost:8080/index.hh/greetings/index`\n\n![](docs/3.png)\n\n\u003cbr/\u003e\n\n\n\u003cimg src=\"docs/meme4.png\" width=\"200\"\u003e\n\n## Not bad, But shouldn't it have views?\n\nSure, lets crete a `views` folders inside our `src` folder.\n\nA neat way to do it would be, create a controller class to contain our helpers methods for our controllers as a 'loadView()' method.\n\n```php\nclass Controller {\n\n  public function loadView(string $name): View {\n\t\t$view = new View($name);\n\t\treturn $view;\n\t}\n    \n}\n```\n\nNow we have to create a `View` class to represent our views, we are going to render simple html by now.\n\n```php\nclass View {\n \n\tprivate $template;\n\n\tpublic function __construct(string $template): void {\n\t\t$this-\u003etemplate = __DIR__ . '/../src/views/'. $template;\n\t}\n\n\tpublic function render(): void { \n\t\t$myfile = fopen($this-\u003etemplate, \"r\");\n    echo fread($myfile,filesize($this-\u003etemplate));\n\t}\n    \n}\n```\n\nFinally, we have to use all of this in our application.\n\nFirst we use our new helper method in our greetings controller as follows:\n\n```php\n\nclass GreetingsController extends Controller {\n\n  public function index(): void{\n    $template = $this-\u003eloadView('hello.html'); \n\t\t$template-\u003erender();\n  }\n\n}\n```\n\nThen he can write a simple html file inside of our `/src/views` folder.\n\n```html\n\u003ch1\u003ehello \u003cb\u003eworld\u003c/b\u003e\u003c/h1\u003e\n\u003ch2\u003eFrom your first view\u003c/h2\u003e\n```\n\nLet's run our server `hhvm -m server -p 8080` and go to `http://localhost:8080/index.hh/greetings/index`\n\n![](docs/4.png)\n\n\u003cbr/\u003e\n\n\u003cimg src=\"docs/meme5.png\" width=\"200\"\u003e\n\n## I see, and what about if I want to return a json response?\n\nWe can return our json responses from our controller as follows:\n\n```php\nclass GreetingsController extends Controller {\n\n  public function index(): void{\n    $template = $this-\u003eloadView('hello.html'); \n\t\t$template-\u003erender();\n  }\n\n  public function api(): void {\n    $greeting = vec[\"hello world\"];\n    echo json_encode($greeting);\n  }\n\n}\n```\n\nIf we go to `http://localhost:8080/index.hh/greetings/api`, we will see a json response.\n\n![](docs/5.png)\n\n\u003ccenter\u003e\n\n\u003cp align=\"center\"\u003e\n\n  ![](docs/meme6.gif)\n\n\u003c/p\u003e\n\n\u003c/center\u003e\n\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\n# What have we learned?\n\n- Now we can understand how hhvm processes http requests.\n- We are able to set up a simple web application or API using hack.\n- We hope we have motivated you to continue exploring hack.\n\n# What next ?\n\n- We would like to add XHP support in our views\n- We would like to add auto detection of routes based on http methods, as listing, create, update, delete.\n- We would like to write more useful controller helpers \n- Prepare a packgist package for our micro framework.\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoelibaceta%2Fhack-er","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoelibaceta%2Fhack-er","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoelibaceta%2Fhack-er/lists"}