Solving Web Application Issues in C - The Greenest Programming Language by@velydev
424 reads

Solving Web Application Issues in C - The Greenest Programming Language

tldt arrow
Read on Terminal Reader

Too Long; Didn't Read

An example web applications in C using Vely framework: you will write an HR application that manages employees using Nginx as web server and MariaDB as database.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Solving Web Application Issues in C - The Greenest Programming Language
Sergio Mijatovic HackerNoon profile picture

@velydev

Sergio Mijatovic

Worked for Oracle and DARPA.

react to story with heart

Cover image copyright (c) 2022 Sergio Mijatovic

C language and the Web

Even though a great deal of the world’s web infrastructure is written in C, most people don’t think of C to write web applications. And that’s understandable, given C’s lack of easy-to-use web and database constructs, no direct connectivity to web servers, and safety issues, just to name a few.

C, however, is the world’s greenest programming language, and that’s important if we want to help the environment. It certainly doesn’t hurt that if you want the best performance, C is the language to use.

This article will show how to harness the power of C and smooth out the aforementioned issues.

What is Vely?

Vely is a general-purpose framework for C developers. Applications created using Vely are native, without interpreters or byte-code schemes.

The application you'll write and run

You'll write a Human Resources (HR) web application that maintains the list of employees. It's simple and not quite bursting with bells and whistles, but it demonstrates enough to get started. And you wouldn't want a tutorial meant for learning to be cluttered with all kinds of things you can easily add on your own. The purpose here is to learn the basics.

So to that end, there are three parts to this.

  • The first is adding employees.

  • The second one is showing the list of employees.

  • The third one is being able to delete an employee from the list.

Before you start:

  1. Install Vely. You can use standard packagers like apt, dnf, zypper or pacman. Go to https://vely.dev/pkg/ to install Vely. You can always remove it with the same packager,
  2. Create a directory for your project - you can name it anything you want. All that's done here should be done in that directory,
  3. Make sure you have MariaDB and Nginx installed, as they are used here.

Screenshots of application

Here are the snapshots of the application. This is the end result.

Web form to add an employee:

image

The result of adding an employee:

image

List the employees:

image

You can also delete an employee, and after that it won’t be in the list anymore.

Vely - how it works

Next, you'll create source code files for the application. The files have a .vely extension.

The source code in those files is C with Vely statements in it. Each statement will generate a certain C code, so the end result is always C. That's how Vely works.

The part that makes Vely a framework is request handling - a simple dispatcher provides a foundation for standard HTTP request processing across the board. There’s also an automatic memory garbage collector, which is useful for long-running processes such as web application daemons.

The bottom line is, Vely code will turn itself into pure C which is then compiled into a native application.

Introduction to using SQL

First I'll talk about using databases, as it's the foundation for database-driven web applications.

Vely currently supports MariaDB/mySQL, PostgreSQL, and SQLite databases. The interface is the same for any of them. For example, to query table employee and display a list of names found, here's the Vely code:

run-query @db = \
    "select firstName, lastName from employee where employeeID='%s'" \
    output firstName, lastName \
    : empid
    
    @Employee is <<query-result  firstName>> <<query-result  lastName>>
end-query

Here are a few things to keep in mind when coding Vely:

  • Line continuation

Notice the usage of backslash (\) which, like in C, means the line continuation. So the first 3 lines of code are a single statement.

  • Outputting data

To display data to the web client (such as a browser) or the standard output, use the output statement, which is the @ at the beginning of the line.

  • Database configuration

The database is specified with @ clause, in this case, it's @db. This is the file that holds the native database connection information. Each database has its own; in this case, you're using MariaDB (or mySQL), and so file db might have the following content:

[client]  
user=user_name 
password=password     
database=database_name     
socket=/run/mysqld/mysqld.sock

You can read more on the details of writing a connection string information for MariaDB/mySQL. Vely uses native database connectivity for performance, and the connection details are native too. This covers much of what you need in order to query a database in C using Vely.

  • Database queries

To run a query, use run-query statement. Typically it states the database used (with @ clause), the query itself, and the list of output columns (with output clause). You supply input parameters for the SQL statement after : clause.

  • Query results

To display column data from the query's result-set, use query-result statement. When used in the output, as is the case here, you can place it within << and >> - that's inline code.

  • Query loops

If you want to loop through the result-set of your query, mark the end of this loop with end-query statement, like above.

Step 1: Getting started - the database

First, you will create the database and employee table used here. The SQL in this example is simple, so you can use any database vendor you want. Here though, MariaDB is used. The SQL to create the employee table is as follows. Save this to setup.sql file:

create table if not exists employee (
    firstName varchar(50),
    lastName varchar(50),
    employeeID integer primary key auto_increment);

Login to mySQL utility as a root user (database admin) and execute this to create the database, user, and employee table:

create database if not exists emp;
create user if not exists appuser identified by 'my_password';
grant create,alter,drop,select,insert,delete,update 
    on emp.* to appuser;
use emp;
source setup.sql;
exit

Finally, Vely needs to know where is your database. Create the database configuration file db (that's the name used in run-query statements). Copy this to file db:

[client]
user=appuser
password=my_password
database=emp
protocol=TCP
host=127.0.0.1
port=3306

Note the appuser and emp database (as well as the password) are the same as in the creation sql you executed in mysql utility.

Step 2: Source code

Here's the source code. Copy and paste the code to the files as instructed.

List employees (query a table)

This will display a list of employees from the employee table. Just to illustrate the usage of any C code, (since most of the code here is Vely statements), I've added the C code to find out the Process ID (PID) and display it. Save this to emp.vely file:

#include "vely.h"

void emp()
{
    out-header default

    @<!DOCTYPE html>
    @<html>
    @<head><title>Vely example</title></head>
    @<body>

    pid_t pid = getpid(); // get current process ID

    @Employee report from process <<pf-out "%d", pid>>
    @<hr/>

    @<table border="1">
 
    run-query @db = \
        "select firstName, lastName, employeeID from employee" \
    	output firstName, lastName, employeeID

        @<tr>
            @<td> <<query-result lastName>> </td>
            @<td> <<query-result firstName>> </td>
            @<td> \
                <a href="?req=del_emp\
                    &employee_id=<<query-result employeeID>>">\
                    Delete\
                </a> </td>
        @</tr>
    end-query
    @</table>
    @</body>
    @</html>
 }

As you see, the output statement @ is used a lot. It outputs any text that follows on the same line. Since the same Vely program can serve as a web application and as a command-line program, the output's destination depends on how you use it. If it's a web application, the output goes to the web client, i.e. a browser. If it's a command-line program, the output goes to the standard output, i.e. stdout.

While outputting data, the inline code is often used as part of the output. Inline code is written between << and >> and typically calls a Vely statement that outputs something. In this example, query-result outputs the column values of a query result-set.

Note you'll have the ability to delete an employee record by clicking the Delete link. The link calls back your application and specifies which employee record to delete based on employeeID that's embedded in the delete link.

All Vely requests must have a req input parameter, specifying what .vely file will handle the request. So when the user clicks the link, code in del_emp.vely will run. That's coming up.

Add an employee (insert into table)

To insert data into the employee table, the employee's first and last name will be provided as input parameters. Those are simple to obtain in the Vely framework by using input-param statements. Then, INSERT SQL will insert the data with run-query, which uses no-loop clause to say that there's no result-set loop (i.e. this isn't a SELECT query), and affected-rows to get the number of rows actually inserted. Finally, you'll check if a row was inserted as expected, and inform the user. Save this code to add_emp.vely file:

#include "vely.h"

void add_emp() {
    out-header default
    
    input-param first_name
    input-param last_name
    
    run-query @db = \
        "insert into employee (firstName, lastName) \
            values ('%s', '%s')" \
    	: first_name, last_name \
        no-loop \
        affected-rows define aff_rows
    
    if (aff_rows != 1) {
    	@Could not add employee!
        exit-request
    }
    
    @Employee added
}

Web form to add employees

In order to add employees, you will need a web form to enter them before sending them off as input parameters to add_emp.vely for processing. Here is a simple form to do that - note the use of "?" as an action attribute in <form> element. It means: use the same URL path that led here and then add the URL query string from the form's input fields.

Note the hidden field req which is a mandatory field that Vely needs in order to route the HTTP requests - unsurprisingly it contains add_emp. Save this to form_add_emp.vely file:

#include "vely.h"

void form_add_emp() {
    out-header default
    
    @<h2>Enter employee</h2>

    @<form action="?" method="POST">
    @    <input type="hidden" name="req" value="add_emp">

    @    <label for="first_name">First name:</label><br>
    @    <input type="text" name="first_name" value=""><br>

    @    <label for="last_name">Last name:</label><br>
    @    <input type="text" name="last_name" value=""><br><br>

    @    <input type="submit" value="Submit">
    @ </form>
}

Delete an employee (delete from table)

Deleting an employee record will obtain the employee ID, and issue a DELETE SQL statement. Note the use of : clause, which lets you specify the SQL input parameters, in this case employee_id to be deleted. Save this to del_emp.vely file:

#include "vely.h"

void del_emp() {
    out-header default
    
    input-param employee_id
    
    run-query @db = \
        "delete from employee where employeeID='%s'" : employee_id \
        no-loop \
        affected-rows define aff_rows
    
    if (aff_rows == 1) {
        @Employee record deleted.
    } else {
        @Could not delete an employee record.
    }
}

Step 3: Create application

To create the Vely application, do this:

sudo vf -i -u $(whoami) emp

-i says create a Vely application, -u says the owner of it will be the current user, and emp is the application name.

This will create a directory /var/lib/vv/emp, which is the application directory for your project (see how Vely works). You have initialized it and set up permissions to allow the current user to use this directory, while other users cannot access it.

Step 4: Make application

You now have the following files in your project: emp.vely, form_add_emp.vely, add_emp.vely, del_emp.vely and db. Vely' vv utility will make an application out of them - it will automatically find these files and generate a proper Makefile for you and link in the necessary libraries.

You can make the application with vv:

vv -q --db=mariadb:db

-q says you're making the application. --db says you're using MariaDB database and the database configuration file is in the file db.

Note you can use multiple databases in your application, and from different vendors too.

Step 5: Run application

You will run the application as a FastCGI application server. Your application server runs behind the web server (in this case Nginx), which acts as a reverse proxy. A number of persistent and concurrent server processes will serve the incoming requests. The processes do not exit and they work in parallel. Also, they are not directly accessible to the end user.

To start your application:

vf -w 5 emp

This will start 5 concurrent processes. Read about vf - Vely's FastCGI process manager for more on how you can fine-tune performance, including setting up a dynamic process loader that varies the number of processes running based on the actual runtime load.

Step 6: Setup Nginx for FastCGI

The final step is to setup a web server, Nginx in this case. Edit the Nginx configuration file - for Ubuntu and similar Linux distros:

sudo vi /etc/nginx/sites-enabled/default

and for Fedora, like RedHat:

sudo vi /etc/nginx/nginx.conf

Add the following in the "server {}" section:

location /emp { include /etc/nginx/fastcgi_params; fastcgi_pass unix:///var/lib/vv/emp/sock/sock; }

Restart Nginx for change to take effect:

sudo systemctl restart nginx

Here, you connected the URL path "/emp" with the super-fast Unix socket connection between Nginx and your application servers. This way a URL like:

http://<your web server>/emp?req=add_emp&first_name=Joe&last_name=Darling

would call function add_emp() in file add_emp.vely with first and last names as input parameters.

That’s it

You now have a functional application ready to use. The following describes various ways to use it.

Using application from web browser

The following URLs are the interface to your application. Use both to run it. The first is to add an employee:

http://<your web server>/emp?req=form_add_emp

This one is to list employees

http://<your web server>/emp?req=emp

Of course, replace “<your web server>” with either "127.0.0.1" loopback address (if you’re testing locally), or with your web server's fully qualified name or IP address.

Note these facts:

  1. the URL path is the name of your application - /emp in this case, since that’s how you set it up with Nginx,
  2. the req parameter is always the base name of the request source file that handles it. For example, req=form_add_emp means the code in form_add_emp.vely will handle the request,
  3. any other parameters you can freely choose.

Note that if you don't have a web server, and you still want to use your application server, you can contact it directly on the command line with the FastCGI client included in the Vely installation (thus bypassing the web server). In this case, you would ask your application server to list the employee records:

export REQUEST_METHOD=GET
export QUERY_STRING='req=emp'
cgi-fcgi -connect /var/lib/vv/emp/sock/sock /

Command-line usage

Every Vely application can run as a web application or as a command-line program. They also both use HTTP as a protocol, making it easy to develop, test, maintain and use the application in a myriad of different ways.

Note that if you plan to solely run your application from the command-line, you do not need the application server, so in that case, you don't need the web server setup nor do you need to start the application server using vf process manager. It's much simpler.

To run your application from the command line, provide the input parameters on the command line and run the program. For instance to add an employee, provide REQUEST_METHOD environment variable (such as GET), and QUERY_STRING (set to URL to add an employee), and invoke the program:

export REQUEST_METHOD=GET
export QUERY_STRING='req=add_emp&first_name=Joe&last_name=Darling'
/var/lib/vv/bld/emp/emp

The result is:

Content-type: text/html;charset=utf-8
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Status: 200 OK

Employee added

If you plan to save the result in a file (for example to cache the application output), you can omit the HTTP header from the output by doing this:

export VV_SILENT_HEADER=yes

Conclusion

In this tutorial, you have learned how to create a fully-functional database-driven web application with Vely that uses MariaDB/mySQL as a database and Nginx as a reverse-proxy web server.

You could have used PostgreSQL and Apache for instance, and it would be very similar.

You have also learned how to run your application in different ways: as an application server or from the command-line. The output and behavior are exactly the same, which is useful for both deployments and for automated application testing.

Cover image copyright (c) 2022 Sergio Mijatovic

RELATED STORIES

L O A D I N G
. . . comments & more!
Hackernoon hq - po box 2206, edwards, colorado 81632, usa