Before we go further and learn more about the Hono framework,
the one thing that is bothering me is database credentials written in
code. We should adjust the existing code by removing the credentials
from the code and put it within the .env file. We should never hard-code the secret(s) as per 12factor app.
Go ahead and create a .env file in the root of the project.
touch .env
Let’s define the following environment variables within this created .env file.
We should not commit this file in the Git. The file should be added within .gitignore file. But, to give and idea about the existence of the .env file, we should have the .env.example file in the repo with same content as we have in .env file but with dummy environment variables or env vars.
cp .env .env.example
Hono has an adapter to read the env vars from the .env file. But, unfortunately it is not working for the Node and outside of c or context. For now, we are going to use the dotenv package. Let’s first install the dotenv package.
npm i -E dotenv
Import dotenv/config in app.js and we are good to go.
With these changes, we have removed the hard-coded secrets from our
code. These changes should not effect the output. Run the application
to confirm the same!
npm run devListening on http://localhost:3000
Visit the http://localhost:3000 in the web browser and you should see the following output in terminal while displaying Hello! in the browser.
Result(1) [ { '?column?': 2 } ]
Note
The code is available at GitHub. Checkout chapter03 branch for the code of this chapter.
In this article, we are going to connect the database in Hono
application. For the purpose of demonstration, we are going to use
PostgreSQL database and postgres
as npm package. You are free to use any other package and database as
steps will be similar except you need to consult the respected
documentation for initial setup.
Let’s install a postgres package.
npm i -E postgres
As per postgres package documentation, we first need to import the postgres function. This function accepts the connection options, and we can save the connection within sql variable as follows.
You need to adjust the connection options to the postgres() function based on your PostgreSQL setup. Once done, you now have the active connection within sql variable.
Let’s execute the simple SELECT 1 + 1
query within root route and print the result of it. The query returns
the promise, and due to this we need to update the signature of the
callback function to async/await.
That’s it! Run the application using the following command.
npm run dev
Visit http://localhost:3000 in the browser and check the terminal. You should see the following console message.
Result(1) [ { '?column?': 2 } ]
We got the result 2 as 1+1 and when you don’t define the column name in SELECT clause in PostgreSQL, PostgreSQL by default gives ?column? as column name.
With these changes, our Hono application is connected with database.
You might say that this is boring and nothing specific to Hono. That is
right! As Hono doesn’t re-invent wheel in every aspect of the web
development and database connection is one such a case!
Note: The code is available at GitHub. Checkout chapter02 branch for the code of this chapter.
The routes of the application are defined within the lib/hello_web/router.ex file. In this file, look for the following code snippet.
scope "/", HelloWeb do
pipe_through :browser
get"/", PageController,:home
end
In a future article, we will cover what other code does in this file.
But, for now we can focus on this code block and specifically, this
line - get "/", PageController, :home. It means when a GET / or root route is requested, execute the home action (function) of PageController.
You can find this PageController or page_controller.ex file within the lib/hello_web/controllers folder. Open this file, and you should see the following code.
defmodule HelloWeb.PageController do
use HelloWeb,:controller
def home(conn, _params)do
# The home page is often custom made,
# so skip the default app layout.
render(conn,:home, layout: false)
end
end
There we have the home function! This function renders home template or home.html.heex file without layout and located at lib/hello_web/controllers/page_html folder.
Don’t worry about the location of these files! Don’t memorize the locations. With some practice, you know all these eventually.
So, we have the router.ex
file that defines the routes of the application that point to the
controller’s action and the controller’s action to render a view. There
is one more file page_html.ex located at the lib/hello_web/controllers
folder. But, we haven’t talked about it yet and we’ll talk about it in
future articles. But, it is required to have to complete this
request-response cycle.
---
Let’s add a new route GET /about. Open router.ex file, and write the following.
When the GET /about is requested, we are going to call about the action of the PageController file. Let’s add this about function in the page_controller.ex file. Open the page_controller.ex file and write the following.
defmoduleHelloWeb.PageControllerdouseHelloWeb,:controllerdefhome(conn,_params)do# The home page is often custom made,# so skip the default app layout.render(conn,:home,layout:false)enddefabout(conn,_params)do# The home page is often custom made,# so skip the default app layout.render(conn,:about)endend
I almost copied the home function with two notable changes - we are going to render about.html.heex file and remove the layout argument to use default layout. We do not have this about.html.heex file in the lib/hello_web/controllers/page_html file. So, let’s create one.
In this article, I am going to briefly explain to you the purpose of a few files and folders present in this hello
Phoenix project. This will be brief. Because, as you start to become
familiar with Phoenix projects, it will become second nature to you.
We have a _build
folder. When you run the application, Elixir compiles the project and
saves the artifacts within this folder. You can ignore what is within
this folder because Git also ignored this folder in the .gitignore file!
We have an assets
folder. You can put static assets such as JavaScript or CSS within this
folder that further require compilation such as TailwindCSS. But, if
you want to save the static assets that don’t require the compilation
such as plain CSS files or images, you can put it within the priv/static folder.
We have a config folder. This folder contains the configurations of the project. config.exs is the starting point and then we have files after each of the environments. We already know the config/dev.exs file as modified for the database configuration for the dev or development environment.
We have a deps
folder. This folder contains the dependencies of this project. Again,
we do not have to worry about this file as this file is ignored in .gitignore.
We have a lib folder. This folder contains the application code. We are going to spend most of the time in this folder.
We have a priv
folder. This folder contains files which are directly not needed in
production but the application depends on. For example, migration
scripts. We need migration scripts for database modification but
production does not directly include the code of it.
Finally, all the test cases are written within the test folder. And mix.exs and mix.lock file contains the dependencies of the project.
I think this brief overview is enough to get started and I will cover in details where it requires.
---
Let’s do a quick modification in scaffold code to print the hello,
world text instead of the default landing page. What you are seeing at http://localhost:4000 is coming from lib/hello_web/controllers/page_html/home.html.heex. Open this file and replace the whole HTML with the following.
<h1>hello, world</h1>
You do not have to reload the page in the browser thanks to the
Phoenix framework as it will auto reload for you! There you have the
hello, world application in the Phoenix framework.
I'm migrating this blog to chauhankiran.pages.dev. This chauhankiran.blogspot.com blog is created in a first-generation blog theme that I highly customized. I want to customize more. But, I'm not getting any help on it. Also, I'm unable to find the documentation on first-generation themes. Current theme is too complicated for me! I remember copying one widget of 12-15 lines of code and expanding it into a couple of hundred lines of code is complicated for me.
Although, chauhankiran.pages.dev looks the same as this one, it is created in Jekyll and the theme is customized to retain the curren look-and-feel. The repo. is hosted on GitHub and deployed on CloudFlare pages.
I'm slowly migrating these articles. I do not plan to delete this current blogspot. But, the new content will be posted there!
This is the first article in a series where we are going to build a simple back-end application in Hono in Node.js environment.
Create a new folder with the name hono-app.
mkdir hono-app
Go inside the created hono-app folder.
cd hono-app
Create a package.json file using npm with default values (-y).
npm init -y
Let’s install the hono package.
npm i -E hono
In order to use Hono in the Node.js environment, we also need to the @hono/node-server package.
npm i -E @hono/node-server
Finally, let’s install nodemon to ease the development. We should install this as a development dependency (-D).
npm i -E -D nodemon
For now, we are done with setup. Let’s move on to the coding side. Create a new file with name app.js.
touch app.js
Open this file (or hono-app folder) in your favorite text-editor/IDE and write the following code.
import { Hono } from'hono';
const app = new Hono();
We are using the latest import...from syntax in our Node.js application! We have imported the Hono and then created an instance of the Hono() using a new keyword and saved it as an app.
Let’s now define a root route(/) and return a simple Hello! text as a response (don’t forget to return the response).
Here, c is a context and it contains both request and response in it with many useful methods such as .text(). The .text() method return response in plain text with string passed to it e.g. Hello!.
Now, to run the application in Node, we need to use @hono/node-server package. Import serve from @hono/node-server package.
serve() function takes Hono instance as the first argument and second argument should be a callback function with info param that gives useful information such as port. If you don’t define the port value as we did, the default is 3000.
Before we go further and run the application, we need to do some adjustment in the package.json file. As we are using the latest import...from syntax, we need to define type as module. Also, update the main entry point to app.js file.
With these changes, we are now ready to run the application. Run the following command in the terminal.
npm run devListening on http://localhost:3000
Open http://localhost:3000 in the web browser and you should see Hello! as the plan text. If that is the case, congratulations! You have just created first Hono application in Node.js.
Note: The code is available at GitHub. Checkout chapter01 branch for the code of this chapter.
I suggest PostgreSQL when someone asks for the recommendation on what database one should use. I use PostgreSQL when I am learning or building something in a new web framework or library. I use PostgreSQL when I want to experiment with databases. PostgreSQL is the default choice for me in most of the cases.
Every few months, I change the operating system from one GNU/Linux distro to another mostly staying with the land of Debian (e.g. apt). Most of the time, I just need to run the following command to install PostgreSQL.
apt install postgresql
This command install and activates the PostgreSQL server locally on my computer. I use the psql command tool to work with this database server.
Following are the commands I use to work with PostgreSQL.
sudo -i -u postgres
psql
Although technically it is not correct, I read the first command as sudo imagine user as postgres to provide access. After entering the password, the user changes from the current logged-in user to postgres and then I can directly work with PostgreSQL using the second psql command.
We can combine the above two commands into a single one as follows.
sudo -iu postgres psql
Again, technically it is not correct, but I read it as sudo imagine users as postgres and then launch psql directly.
The first thing I normally do after connecting with PostgreSQL is to change the password. This is trivial as running the following command.
password \postgres
We are changing the password for the postgres user. After running this command, PostgreSQL asks you to enter and re-enter a new password for the postgres user. And then you are ready to go!
---
If somehow, you are facing difficulties installing PostgreSQL on your computer, installing via Docker is yet another option. At some convenient place, save the docker-compose.yml file with following content.
You can choose any other password you like instead of pq2q4a!
Once done, run the following command in the terminal where you have this docker-compose.yml file.
docker-compose up -d
This will run the docker-compose.yml file and up the PostgreSQL service in detached mode. Meaning that it'll run the PostgreSQL service in the background once the docker is running. When you start the computer, if Docker is not running, you just need to run the docker and it'll auto run the PostgreSQL service for you.
Note: To follow this article, you need to install an API client to
test the routes that we are going to create in this article. Try Postman or Insomnia if you haven’t one.
In this article, we are going to create the APIs for the Contact resource. If you are building an MVC web app, then you need to create seven routes whereas if you are creating an API, you need to create five routes.
To start with, let’s add a route that returns all the contacts as GET /contacts. When this route is requested, the server should run the index action of ContactsController in the config/routes.js file.
Now, we need to add a route for a specific contact as GET /contacts/:id. When this route is requested, the server should run the show action of ContactsController in routes.js file.
Let’s define this show action within ContactsController.js file and also print the passed id value using req.params.id.
module.exports={index:(req,res)=>{res.json({message:"All contacts"});},show:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Single contact"});},};
Open the http://localhost:1337/contacts/1 in the browser and you should see this JSON response. You should also see the console message as contact id is 1 in the terminal.
Next, we need to add a route that creates a new contact by passing first name and last name as firstName and lastName respectively. We can define this route as POST /contacts and map against the create action of ContactsController.
Let’s define this create action within ContactsController.js file and also print the passed firstName and lastName values using req.body.firstName and req.body.lastName (you can destructure in single line, if you want).
module.exports={index:(req,res)=>{res.json({message:"All contacts"});},show:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Single contact"});},create:(req,res)=>{console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.json({message:"Creating contact"});},};
To test this route, we need to do a POST api call in Insomnia (or any
other API client you are using). You should get the above JSON response
when calling this route and first name & last name should be
consoled in the terminal.
Before we go further and add route for updating a resource, let’s do a status code modification in create route as 201 should be the status code when creating a resource. We know how to do it as we’re going to use Express’s .status() method.
module.exports={index:(req,res)=>{res.json({message:"All contacts"});},show:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Single contact"});},create:(req,res)=>{console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.status(201);res.json({message:"Creating contact"});},};
Much better! Just confirm in Insomnia that you should get 201 status code in response (You can chain .status() and .json() methods in single line, if you want).
Let’s define a route to update a specific contact as PUT /contacts/:id. When this route is requested, the server should run the update action of ContactsController.
Let’s define this update action within the ContactsController.js file. Let’s also print the id as req.params.id and passed firstName & lastName values as req.body.firstName and req.body.lastName (you can also destructure, if you want).
module.exports={index:(req,res)=>{res.json({message:"All contacts"});},show:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Single contact"});},create:(req,res)=>{console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.status(201);res.json({message:"Creating contact"});},update:(req,res)=>{console.log(`contact id is ${req.params.id}`);console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.json({message:"Updating contact"});},};
We need to test this route in Insomnia. You should get the above JSON response when calling this route and id, firstName & lastName should be consoled in the terminal.
Finally, we need to add a route that deletes a specific contact as DELETE /contacts/:id and should run the destroy action of ContactsController. delete is a reserved keyword in JavaScript. Due to this, we choose destroy as function name.
Let’s define this destroy action within ContactsController.js file and also print the id as req.params.id.
module.exports={index:(req,res)=>{res.json({message:"All contacts"});},show:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Single contact"});},create:(req,res)=>{console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.status(201);res.json({message:"Creating contact"});},update:(req,res)=>{console.log(`contact id is ${req.params.id}`);console.log(`first name is ${req.body.firstName}`);console.log(`last name is ${req.body.lastName}`);res.json({message:"Updating contact"});},destroy:(req,res)=>{console.log(`contact id is ${req.params.id}`);res.json({message:"Deleting contact"});},};
And now we have the stub end-points for the given resource e.g. Contact with best practice to create REST APIs.
Create a folder with name of the project e.g. project-name.
$ mkdir project-name
Go inside the created project-name folder.
$ cd project-name
Create a module or mod file using following command.
$ go mod init project-name
This command will create go.mod file. This file is the manifest file of the project that contains info of your project such as project name, Go version, dependencies of the project and so on. Following is the content as of now we’ve in this go.mod file.
module go-example
go 1.21.5
We don’t have any dependency related information in this file yet. Because, our project yet not consuming any third-party package.
Create a file with name main.go and write following code in it.
package main
import "net/http"
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func (c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "hello, world",
})
})
r.Run()
}
This is the simple hello, world program in Gin framework. Notice that we’re importing Gin framework from github.com/gin-gonic/gin. But, we haven’t installed this package yet. In order to install the package, we need to run following command.
$ go mod tidy
This command will look for the dependencies used in this project and download it for us. After successful completion of the command, if you look over the go.mod file again, it looks like this.
On line number 5, there we’ve the dependency. Remaining are the indirect dependency as they end with comment // indirect meaning that these dependencies are not directly consume by the project. But, project’s dependency are depends on it.
Finally, you should see a file with name go.sum. This file is auto generated by Go for the dependencies with checksum to figure out whether to download the dependencies again or not. Let’s not worry about this file as it’ll be created, updated, and managed by Go for us.
એ જાણે સ્વભાષામાં જ વિચારાયું અને લખાયું છે તેવું સહજ અને સરળ હોવુ જોઈએ. જે ભાષામાંથી ઉતારાયું હોયતે ભાષાના રૂઢીપ્રયોગો અને શબ્દોના વિશેષ અર્થો ન જાણનાર એને સમજી ન શકે એવું તે ન હોવું જોઈએ.
ભાષાંતરકારે જાણે મૂળ પુસ્તકને પી જઈને તથા પચાવીને એને ફરીથી સ્વભાષામાં ઉપજાવ્યું હોય તેવી કૃતિ લાગવી જોઇએ.
આથી સ્વતંત્ર પુસ્તક કરતા ભાષાંતર કરવાનું કામ હંમેશા સહેલુ નથી હોતું. મૂળ લેખક સાથે જે પૂરેપૂરો સમભાવી અને એકરસ થઈ શકે નહીં અને તેના મનોગતને પકડી લે નહીં, તેણે તેનું ભાષાંતર ન કરવું જોઈએ.
ભાષાંતર કરવામાં જુદી જુદી જાતનો વિવેક રાખવો જોઈએ. કેટલાંક પુસ્તકોનું અક્ષરશઃ ભાષાંતર કરવું આવશ્યક ગણાય, કેટલાંકનો માત્ર સાર આપી દેવો બસ ગણાય તો કેટલાંક પુસ્તકોનાં ભાષાંતર સ્વ સમાજને સમજાય એ રીતે વેશાંતર કરીને જ આપવાં જોઈએ. કેટલાંક પુસ્તકો તે ભાષાના ઉત્કૃષ્ટ હોવા છતાં પોતાનો સમાજ અતિશય જુદા પ્રકારનો હોવાથી તેના ભાષાંતરની સ્વભાષામાં જરૂર જ ન હોય; અને કેટલાંક પુસ્તકોના અક્ષરશઃ ભાષાંતર ઉપરાંત સારરૂપ ભાષાંતરની પણ જરૂર ગણાય.
Complexity never eliminate, it just move from one place to another.
When you're not writing middleware to log requests, someone else wrote or is writing middleware for you. If you think that you can easily write a single page application in a given framework or library then understand that it depends on 1000+ modules to make it easy and the complexity is divided between these 1000+ modules but not eliminated.
Going forward with learning, defvar is used to define variables. Continue with last program written in hello.lisp. Here is how I've defined the hello, world program again with variable.
(defvar greetings "hello, world")
(format t greetings)
I read many places that variables are defined with star(*) around it to mark as global variable and * is valid character to define a variable.
(defvar *greetings* "hello, world")
(format t *greetings*)
Not just * but hyphen(-) can be used to define multi-words variables and this is recommended instead of camelCase or snake_case.
(defvar hello-world "hello, world")
(format t hello-world)
Frankly speaking I haven't seen a program like above anywhere else (defining a variable and then using it in next line without context). May be in functional programming, most of the variables are bound to the scope and only defined where needed.
But, defvar is used to define the variable in Common Lisp.
In my free time (which I have very less), I'm learning Lisp programming language. After doing some search, I decided to go with Common Lisp and installed sbcl.
Unless you're using Emacs, do not write multiple lines of code in REPL (in Terminal). Most of the terminals don't support paren auto-closing and highlight. Due to this, you might frustrate.
I'm using GNU/Linux machine. Following command help me to install the sbcl on my computer.
sudo apt install sbcl
After installation, check for the version and you can confirm the installation.
sbcl --version
Write only sbcl and it'll open the true REPL for you. In order quit or exit the REPL you need to write (quit).
You can directly write 10 or "hello, world" (use double quotes) as these are the literal values.
* 10 10 * "hello, world" "hello, world"
If you try to write 10 as (10) or "hello, world" as ("hello, world") you'll get errors. Because, in simple terms, after open paren, Lisp expect to have something that can execute. For example, (+ 3 4) works as + will execute on 3 and 4 values.
Here is the hello, world in Common Lisp.
* (format t "hello, world")
Here, format print on terminal (actually it is standard output) "hello, world" string. You can write code within file that can have .lisp extension. Then you can run it as,
Application is up and running at http://localhost:1337 but it throws a 404 error. Let’s fix it by adding a root route. To do so, first create a config folder and then routes.js file within config folder.
mkdir config
touch config/routes.js
Open the config/routes.js file and write the following code.
module.exports.routes={};
It exports the routes object that will have all the routes of the application.
Meaning that when the root route (/) is requested, server run the index action (or method) from the HomeController. But, we don’t have controller and action.
Go ahead and create a folder with the name api. Within this api folder, create a folder with name controllers. In this folder, we’ll put all the application controllers.
mkdir api
mkdir api/controllers
Finally, within this controllers folder, create a file with the name HelloController.js. The name of the file should be the same as the controller name defined in routes.js file.
touch api/controllers/HomeController.js
Open the api/controllers/HomeController.js file and write the following code.
module.exports={};
It exports the object that will have all the actions we are interested in calling from this controller.
Sails internally uses Express
framework. So, the actions within the controller are essentially the
callback function we usually write in Express for a given route with req and res (and next) parameters.
Let’s define an index as a named function that returns a sample JSON response.
That’s it! Reload (or open) the http://localhost:1337 in the browser. You should now see a JSON response with the message { "message": "Home page" } instead of a 404 error page.
When you write app.set('view engine', 'something'), Express will check something module in node_modules and load it. EJS use this trick and due to this, you just have write this line only. Even you don't have to import ejs (or something in example).
All the repos under Express org on GitHub has either index.js if the package is consist of only one file or the package code is within lib folder.
In progress. I'll add more points as I learn more.
This command is used to open a shell session as the user "postgres" with an environment set up as if "postgres" had logged in directly. This is often useful when you need to perform administrative tasks or run commands specific to the PostgreSQL database system, which typically runs with a dedicated user account for security reasons.
Now, write psql command in terminal to open the command-line interface to PostgreSQL.
$ psql
We now have the PostgreSQL open in our terminal.
To fetch the all database, following command is used.
To connect with specific database, use \c followed by the database name.
$ \c abc_development
You are now connected to database "abc_development" as user "postgres".
We're now connected with the abc_development database.
To list all the tables within given database, following command is used.
$ \dt
Did not find any relations.
We get the message "Did not find any relations." meaning that no table exists as of now in this database.
We can create the table using following command (do not run this command yet).
create table products (
id int primary key,
name varchar(256) not null
);
We're trying to add id as primary key and name as the another string column. But, this query has one problem - id is not auto increment for us by default. To have it that feature, we need to defined it as serial than int like this (now you can run this command).
create table products (
id serial primary key,
name varchar(256) not null
);
With this the products table is created.
Let's write a simple insert query to confirm the usage of the table.
insert into products (name) values ('Neem plant');
Finally, let's confirm that the product is added successfully in table by writing the select query.
select * from products;
id | name
----+--------------
1 | Neem plant
(1 row)