In a previous article, we provided a detailed description of the basic uses of ActionEquals. We showed how with a few modifications to your <form> and <input> tags, the forms submitted by the users on your site are viewable from the ActionEquals Dashboard, and how to sort, search and export this data. We also showed how a single line of Javascript injects a CAPTCHA into a contact page.

REST Use Cases

In this article, we demonstrate the ActionEquals REST API. Every Free Evaluation and Advanced account has full access to this feature. While easy to integrate, the API provides the means by which any program can automate interaction (create, retrieve, update, delete, and search) with the persistant storage we provide your account. By consuming the REST API, your application can in fact use ActionEquals as a database and implement such advanced behaviors such as the following and probably many we haven't even thought of:

* Implement backend/admin logic such as workflow

* Sending personalized confirmation Email or SMS messages

* Implement application security

* Changing user passwords and deleting user accounts

* Storing and displaying alerts, blog articles, news, etc.

* Integrate with online stores and payment gateways

* Implement dynamic product lists and image galleries

You can find detailed documentation of the API at

Yet Another Demo

Creating a demo site is a pretty good approach for providing the right amount of detail that can be understood quickly. We created another demo implemented as a Microsoft Blazor WebAssembly application. You can find all the source code at The application runs in the browser and, just like the United Pest demo in a previous article, requires nothing more than static hosting.

Please note that we do not ever recommend implementing letting your front end (browser script) talk directly to our API. This is a demo. In fact, we do not implement this demo site on the public web for people to play with. This is because a sophisticated user could watch the network traffic, decode the authentication header sent with each request, use the credentials to logon to ActionEquals, and then proceed to wreak mischief and destruction reaching levels thought impossible.

In a real-world application, you will have your own service layer that implements the REST API client, keeping the credentials secret-- and your front-end will consume that.   

About Blazor

Blazor WebAssembly is a relatively new client-side web framework comparable to other SPA frameworks such as ReactJS, AngularJS and VueJS. Notice the "JS" in the names of these other frameworks. Many engineers have realized over the years that Javascript has in many instances, acted as a kind of "assembly language" of the web browser. Higher level, or at least "cleaner" languages such as Typescript and Dart were implemented to compile down to Javascript. The real assembly language of the brower is WebAssembly. The interesting thing about Blazor is that Microsoft implemented a C# compiler that targets WebAssembly, mostly obviating the use of Javascript as a "middle man." The end result is better performance than Javascript and far more enjoyable and productive development experience.

Of course, we could have implemented the demo in any of the other frameworks, or could have just used vanilla Javascript

This application has two concepts: Witches and Watches. The user can add some Watches (i.e. wrist watches) and Witches. Each Witch can optionally watch any Watch.

Then, by clicking Edit, the user can change the name of any Watch or Witch and can also change which Watch each Witch is watching. Any Witch can be deleted.

A Watch can be deleted only if it is not being watched by a Witch.

What does this have to do with Forms?

A Form as defined in HTML, can be thought of a specialized kind of database table. Like a table, it has a collection of fields. In ActionEquals, forms have a built-in unique "Key" field and a DateSubmitted field, just like a typical database table. By using the API to create "forms", interaction with the actual database of data submissions is effectively detached from HTML. Thus, an application is not limited to querying the data submitted in real HTML forms on your site, but it can also create tables and records for which no HTML forms actually exist.

The class ActionEqualsApiRequest implements the client API:

public class ActionEqualsApiRequest<T> {

    string BaseUrl = "";


    public HttpClient httpClient { get; set; }

    string TableName;

    public string Endpoint { get; set; }

    public ActionEqualsApiRequest(HttpClient client, string tableName) {

        TableName = tableName;

        httpClient = client;


        httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", Username, Password))));


    public async Task<T[]> GetAllAsync() {

        Endpoint = $"{BaseUrl}{ApiKey}?f={TableName}";

        var answer = await httpClient.GetFromJsonAsync<T[]>(Endpoint, serializationOptions());

        return answer;


    public async Task<T> GetByKey(string key) {

        Endpoint = $"{BaseUrl}{ApiKey}?f={TableName}&Key={key}";

        var answer = await httpClient.GetFromJsonAsync<T>(Endpoint, serializationOptions());

        return (answer);


    public async Task<bool> Insert(T dto) {

        Endpoint = $"{BaseUrl}{ApiKey}?f={TableName}";

        return (await httpClient.PostAsJsonAsync(Endpoint, dto, serializationOptions())).IsSuccessStatusCode;


    public async Task Delete(string key) {

        Endpoint = $"{BaseUrl}{ApiKey}?f={TableName}&Key={key}";

        await httpClient.DeleteAsync(Endpoint);


    public async Task Update(string key, T updatedDto) {

        Endpoint = $"{BaseUrl}{ApiKey}?f={TableName}&Key={key}";

        await httpClient.PutAsJsonAsync(Endpoint, updatedDto, serializationOptions());


    JsonSerializerOptions serializationOptions() {

        return new JsonSerializerOptions { DictionaryKeyPolicy = null, PropertyNamingPolicy = null };



Then, consuming the API becomes very straightforward. For example:

await (new ActionEqualsApiRequest<WatchDTO>(Http, "Watches").Insert(record))

where record is an instance of a type with the fields defining the table. If a table doesn't exist, it is created on-the-fly. Field names follow the same conventions as those of ActionEquals-compatible HTML form fields.


The REST API provided by ActionEquals offers more interesting possibilities that even we initially realized. The possibilities it provides our users make it the most compelling Forms-as-a-Service and distinguish it far beyond anything offered by its theoretical competition. The REST API is easy to consume and can be swapped with a "native" data layer as needs dictate.

Previous Article