"Hello, world" — The Minimal Example
Pre-requirement Knowledge and Skills
It is implied that you are already can/know:
- Create the Node.js project and install the npm dependencies (if no, you should to learn the Node.js fundamentals first).
- Configure the TypeScript compiler
(Yamato Daiwa Backend (from now: YDB) is intended to be
used with
TypeScript
, herewith withoutany
type). - The Object Orienting Programming (OOP) fundamentals: the approaches suggested by @yamato-daiwa/backend is OOP-based). Although YDB not impose the specific architecture, the usage of OOP is desirable, and therefore will be in the following lessons.
Node.js-project Rollout
Create the new Node.js project and install the following npm dependencies. During this lesson it is strongly recommended to install the versions specified inside the square brackets to avoid the troubles caused by changing of the API with new versions of these dependencies.
- @yamato-daiwa/backend [0.3.0]
- The main npm package of this framework
- @yamato-daiwa/es-extensions [1.7.0]
- Auxiliaries actual for both Node.js and Browser JavaScript. For this tutorial, we will need only HTTP_Methods enumeration from this package, but much more in the future.
- ts-node [10.9.2]
- The REPL for the TypeScript language. Creating the effect such that TypeScript has own runtime, thanks to what we will not spend our time to routines with output JavaScript files.
- typescript [5.5.4]
- The npm package package of the TypeScript language, the
peer dependency of
ts-node
. Although modern versions of npm installs such dependencies automatically, we will consciously install the specific version of this package.
npm i @yamato-daiwa/backend@0.3.0 @yamato-daiwa/es-extensions@1.7.0
npm i ts-node@10.9.2 typescript@5.5.4 -D
Code
Bellow server application will return the HTML code, including the heading
h1
with text content "Hello, world!"
on
the HTTP request of GET-type to
http://127.0.0.1:80/
address.
Actually, such HTML code does not represent the valid
HTML page, however for testing purposes the responding just with HTML body is
possible — modern browsers will display it.
Before submit this request, let us analyze the source code of this simplest example.
import { Server, Request, Response, ProtocolDependentDefaultPorts } from "@yamato-daiwa/backend";
import { HTTP_Methods } from "@yamato-daiwa/es-extensions";
Server.initializeAndStart({
initializeAndStart
of
Server
class accepts the
configuration object as first and only parameter.
This method does things exactly according to its name, and only that's how it should be. IP_Address: "127.0.0.1",
IP_Address
has been made to required
property not without reason: you as engineer must
comprehend on which IP address your server application will run.
In the real project, it will be environment-dependent (local, staging, production, etc.).
We will discuss the conditional configuration in dedicated tutorials.
For now, let the value 127.0.0.1 AKA
the localhost. HTTP: { port: ProtocolDependentDefaultPorts.HTTP },
ProtocolDependentDefaultPorts.HTTP
—
is the default port
for HTTP protocol.
It must be specified explicitly by the same reason as IP_Address
, however
because rely to human's memory could be dangerous, the default ports of
various protocols has been stored to
ProtocolDependentDefaultPorts
enumeration.
From you it is required only to comprehend on default port will be available the application
or on some one else.
routing: [
{
route: { HTTP_Method: HTTP_Methods.get, pathTemplate: "/" },
routing
, as if obviously and must be obviously for high quality naming,
allows to define the routing —
in the server web development context, it is the generating of various
responses depending on accordance of request to specifies templates of
URI.
We will consider the routing in details in subsequent lessons.
For now, it is important what we are serving the root route
(corresponding to URI http://127.0.0.1:80/
)
only .
For all other routes, for example
/foo
(corresponding to URI
http://127.0.0.1:80/foo
) or
/bar/baz
(corresponding to URI
http://127.0.0.1:80/bar/baz
), the server will respond with "not found" error.
async handler(request: Request, response: Response): Promise<void> {
The request handler defines which actions must be executed when the submitted
request satisfying to the route specified above via
route
property.
This function is a-priori asynchronous (returns either
explicitly or implicitly the instance of Promise
,
but this is not exact definition from the viewpoint of
ECMAScript
, because the functions accepts the
callbacks via parameters also being called «asynchronous»),
because the response submitting is asynchronous by its nature.
In addition the request handler frequently includes other asynchronous operations such as
database transactions or files reading/writing.
In fact, the route
and handler
are like
conditional expression and the action which must be executed when the
conditional expression is truthy.
Usually the response is being generated depending on the request, which instance represented by first parameter. For example, in the GET-request case we may need to access to query parameters (without URI context this term could be ambiguous), and in the POST- or PUT-request case — to access the data containing in the request body. However, we will postpone the manipulations with the instance of Response class to subsequent, more difficult lessons; for now let us ignore the first parameter and always submit the same response.
return response.submitWithSuccess({ HTML_Content: "<h1>Hello, world!</h1>" });
As generally known, the HTTP response has the status being abbreviated by 3-digits code. Currently it is important that these statuses are being split to 5 groups:
- Informational responses
- Successful responses
- Redirection messages
- Client error responses
- Server error responses
Method submitWithSuccess
of the class
Response
submitting the code from the "successful" range
(200
as default).
Specifying the HTML_Content
property of the
first and only parameter of
submitWithSuccess
method, we are expressing that
going to submit the HTML code, and the framework will automatically set
the necessary HTTP-headers.
}
}
]
});
Testing
Let us launch our application by ts-node.
ts-node EntryPoint.ts
If the code has no mistakes, you will be informed about application successful launching by the following terminal output:
Open the displaying URI in your browser. If your terminal can recognize the links, you can open it by mouse click. At least one log will be displayed, about request to root route:
Probably one more request will be logged — about
/favicon.ico
route:
If such log presents, it has been occurred by the browser automatically to display the favicon. If the framework was not prepared to such request, it submitted the response with "not found" error, however the YDB framework submitting the own icon as default. Of course it could be replaced with another one, what we will do in one one of subsequent lessons.
As localhost is the "pronoun" for the IP-address
127.0.0.1
, and 80 is the default
port for the HTTP protocol, besides
http://127.0.0.1:80/
we can submit the requests
to http://localhost
, http://localhost:80
or
http://127.0.0.1:80/
.
Finally, let us see how the framework will behave when we will submit the request which has no
the matching in routing
.
For example, in the request to http://127.0.0.1:80/foo
case, the
log will be:
The frameworks logged that the requested resource not found. The browser should display the similar message basing on response status 404 Not found.