REST

Labels
AJAX(112) Apple(1) Application Builder(244) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(11) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) DotNetNuke(12) EASE(20) Email(6) Features(99) Firebird(1) Form Builder(14) Globalization and Localization(6) Hypermedia(2) Installation(4) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(15) OAuth(6) OAuth Scopes(1) OAuth2(9) Offline(19) Offline Apps(4) Offline Sync(4) Oracle(10) PKCE(2) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(166) Reports(48) REST(28) RESTful(25) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(75) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) Stored Procedure(4) Teamwork(15) Tips and Tricks(83) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(332) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
REST
Sunday, October 16, 2022PrintSubscribe
PWA, Device Authorization Grant, Many-To-Many Input

Progressive Web Apps

Code On Time release 8.9.25.0 produces Progressive Web Apps. Support of PWA specification makes an app installable on Android, Chrome OS, Mac OS, and Windows directory from the supported browsers. Deployed apps are ready to be packaged and published to all major app stores. Each app now has its own “beating heart” - the service worker. This script is installed by browsers when the app is loaded. The installed worker will cache the app resources using the “cache busting” technique supported in the server-side framework. A tiny change to a script, stylesheet, or font will cause the cache to refresh. This ensures the correct set of client files both in the online and offline modes.

Applications created with Code On Time will greet users with the prompt to install the app and experience the native mode. Deployed apps are easy to package and publish to app stores.
Applications created with Code On Time will greet users with the prompt to install the app and experience the native mode. Deployed apps are easy to package and publish to app stores.

Learn how to preview and debug an installed application.

OAuth Device Authorization Grant

Device Authorization Grant flow further extends the opportunity to find new ways to integrate applications created with Code On Time in the everyday life of their users. RESTful API Engine turns an application into a powerful backend for custom clients. Built-in Device Authorization flow will future-proof the app by making it possible to integrate the application with the smart devices.

"Cool Gadget" sample demonstrates the Device Authorization Grant flow available in the applications created with Code On Time. Users can safely authorize the 3rd party devices to access the user data and identity information.
"Cool Gadget" sample demonstrates the Device Authorization Grant flow available in the applications created with Code On Time. Users can safely authorize the 3rd party devices to access the user data and identity information.

Many-To-May Data Input And Search

Tagging is the populate user interface feature that allows setting up the many-to-many data relationships between data records in the database with the minimalistic input. This feature has been a part of the framework in the foundation of apps created with Code On Time for many years. The new release finally makes it possible to filter and search the many-to-many fields, which is not as simple as it may seem at the first glance.

Many-to-many data input is the standard features of the apps created with Code On Time. Users can also filter and search data records by entering multiple tags that must be linked to the items in the output.
Many-to-many data input is the standard features of the apps created with Code On Time. Users can also filter and search data records by entering multiple tags that must be linked to the items in the output.

Release Notes

The following features, bug fixes, and enhancements are included in the release:

  • (PWA) Apps now installable.
  • (OAuth2) Device Authorization Grant flow is now supported.
  • (Framework) Many-to-Many support is fully implemented.It is now possible to filter and search the many-to-many fields.
  • (Framework) Requests with the XML content type will ignore the whitespace and DTD links. The latter eliminates the possibility of a "blind" XML External Entity (XXE) Injection.
  • (Touch UI) A click on the checkbox in the grid will execute an update of the row with all field values of the row. Previously only the primary key and the toggled field were included. The new behavior ensures that the business rules on the server will have a consistent set of field values to work with.
  • (Reports) Action ReportAsExcel will produce the output in OPENXML format. The file extension is *.xlsx.
  • (Reports) Action ReportAsWord will produce the output in OPENXML format. The file extension is *.docx.
  • (Framework) YamlDotNet 11.2.1 is included in the library.
  • (Framework) Newtonsoft.JSON 13.0.1 is included in the library.
  • (Touch UI) Position of the context menu on the toolbar is shifted by 4px away from the edge of the screen.
  • (Touch UI) The default display density is derived from the physical screen size.
  • (Touch UI) Input focus will activate the tab containing the focused field even if it was not in the "edit" mode prior to the focus.
  • (Touch UI) Progress indicator has the "accent" color. Previously it was always blue.
  • (Touch UI) Theme selector switches UI to the "busy" mode during the theme preview.
  • (Touch UI) New "Reset" option is available in Settings|Theme menu. The option is available if the user has selected a theme in the past.
  • (Touch UI) Updated icons for "grid" and "cards" view styles.
  • (Touch UI) Top 5/10 options in the advanced search do not raise exceptions. The list of top 5/10 lookups is presented to the user for selection.
  • (Touch UI) Event handler context.app can inspect context.isMenu property to determine if the context options will be displayed in the context menu in response to the interactive request by the user.
  • (Touch UI) Labels with the blank header are marked with data-hide-when="wrap" attribute. The physical presence of the label allows adaptive hiding of the label when the content is wrapped.
  • (Touch UI) Login prompt displays the "Login" next to the icon on the toolbar when the form is displayed in fullscreen mode.
  • (Touch UI) New theme processing compatible with PWA mode.
  • (Framework) Account Manager persists the fixed number of user properties (name,email, access_token,refresh_token,claims). The user avatars are served in JPEG format.
  • (Framework) The new class AppResouceManager performs production of cacheable client resources.
  • (Framework) Method TextUtility.ToMD5Hash(string) will produce a hash of the string parameter.
  • (PWA) Method $app.getScript uses the app manifest information to download the dynamic scripts.
  • (RESTful) Fixed the bug in processing of PATCH requests.
  • (Touch UI) Click on the icon of the ui-disabled item will not trigger the "vclick" on the item.
  • (PWA) Method UserHomePageUrl() determines the 'start_url' in the manifest.
  • (Framework) Method DataCacheItem.SerializeRequest allows custom serialization of the request object. Override the method to use additional request data such as the request domain.
  • (Framework) Details are synced even when the external filter is not defined on the child data view.
  • (RESTful) Enhanced validation of "sort" parameter.
  • (RESTful) ASP.NET session is removed when the embedding engine is resolving the links.
  • (RESTful) Embedding engine calculates resource tags for faster embedding of the object resource. The links of previously fetched resources are used in place of the duplicates.
  • (RESTful) Embedding will timeout at 60 seconds or when the execution exceeds the option server.rest.timeout specified in touch-setting.json configuration file.
  • (RESTful) Robust refreshing of the page with the ".oauth2" cookie set upon receiving the authorization URL request. Simple 302 with Response.Redirect will not set the cookie on the domains other than localhost when running in Microsoft Azure.
  • (RESTful) Virtual on-demand fields specified in the body are ignored.
  • (RESTful) The "Detailed" HTTP error mode is enabled to allow RESTful error reporting in the apps hosted in Microsoft Azure.
  • (Runtime) Content types application/json and application/x-yaml are added to the mime map in web.config. This will ensure property recognition of JSON and Yaml file types on hosting services such as Microsoft Azure.
  • (RESTful) Configuration file web.config removes status codes 400, 401, 403, 404, 412, 4122, and 500 from HTTP error reporting delegated to the host web server. This allows custom JSON responses from the RESTful API of the apps deployed to Microsoft Azure and other hosting platforms.
  • Cloud On Time app for iOS, Mac, and Windows is retired and replaced with the PWA support in the generated apps. Applications are installable from the browser on the supported platforms. Deployed applications are ready to be packaged and published to the app stores.

Coming Soon

Offline Sync

The all-new Offline Sync Add-On is coming next. It will be compatible with the Progressive Web Apps support in the framework. The licensing will change as follows:

  • Perpetual use with 12 months of maintenance updates
  • Sold is multiples of ten users
  • Bound to the domain name and “localhost”
  • New lower pricing

Online apps that do not require the offline/disconnected data will benefit from the enhanced ability to operate when there is no network. If the app is installed on the device from the browser or as the native app, then the pages will be pre-loaded in the local cache for the improved user experience.

Live Project Designer

The next implementation target is the Live Project Designer described in the Roadmap. We are running behind our original schedule but the goal remains the same - make the app development process with Code On Time intuit and simple.

Tuesday, May 17, 2022PrintSubscribe
Data Caching, RESTful API Engine, Visual Studio 2022

Code On Time release 8.9.24.0 introduces the performance enhancing Universal Data Caching and one of a kind RESTful API Engine. Visual Studio 2022 is supported in the Project Designer.

Universal Data Caching will give your applications a significant performance boost. Most databases have a few tables with the content that does not change frequently. Developers can define simple rules that will eliminate the queries to such tables. It takes only a few minutes to make your app run faster.

Specify the data controllers and and the output caching duration in the application configuration. Start reaping the benefits!

Level 3 RESTful API Engine is included now in every application built with Code On Time. The data controllers are automatically mirrored in the application API.

  • Developers can use the engine to create custom data-aware embedded pages that either blend in the Touch UI or have a completely custom presentation.
  • The engine supports OAuth 2.0 Authorization Flows suitable for the standalone web and mobile applications. Use any framework and technology to build a custom frontend with the Code On Time application in the backend.
  • External scripts and utilities can make direct calls into your application with the robust authentication based on authorization keys. Use tools like cUrl to make your application perform custom actions or change data.
  • Developers can limit the application UI to the specific user roles. For example, administrators can sign into the application and manage data while the users in other roles will only be able to sign in to confirm their identity during OAuth 2.0 Authorization.

The engine is introduced in the RESTful Workshop, the curated set of tutorials that will empower the reader to build the modern high performance software in a record time and at the fraction of the cost of other tools. Level 3 REST API is self-documented with the hypermedia embedded in the data.

RESTful API Engine makes it possible to build custom embedded pages and standalone web and mobile frontends using your application as a backend. External scripts and utilities can use your application to orchestrate the complex workflows.

Code On Time is making a big bet on the RESTful API Engine to deliver the new benefits to our customers:

  • Developers will be able to build apps serving as backends for devices that need to know the user identity and a way to read and write the user-specific data. The next release will support OAuth 2.0 Device Authorization Grant flow for the input-constrained devices. You may have experienced this flow when authorizing a medical device to access your health data or when allowing a smartwatch to use your music service. The same flow is authorizing a smart TV in a hotel room to access the video streaming service that you are paying for at home.
  • Cloud Identity has been on our roadmap for several years. Soon developers will be able to build a collection of apps with one of them serving as the Identity Provider while the others will become the Identity Consumers.
    • Each application will have its own security system.
    • Users will identify themselves by signing into the Identity Provider. This app may have the 2-Factor Authentication enabled or include an option to authenticate users with the third-party providers such as Google, Microsoft, or Facebook.
    • An application will become the identity consumer at runtime when the administrator creates a Cloud Identity link with another application. Device Authorization Flow will authorize the establishment of the link when approved by the administrator of the intended Identity Provider.
    • Identity Consumer application synchronizes its roles and custom OAuth 2.0 scopes with the Identity Provider database. This makes it possible to manage users of the entire application collection in one place.
    • RESTful API Engine access tokens will be issued by the Identity Provider application. The same access token will authorize requests to any application in the collection. The token will inherit the permissions configured in the Identity Provider by the collection administrator.
  • Microservices Architecture becomes a reality with Code On Time even for the smallest of developer shops. Cloud Identity and access token portability across the collection of applications make it possible to create the frontend that will exchange data with multiple backend applications. Each backend provides a custom API, has its own performance characteristic, and can be deployed independently. This improves the stability of the frontend and its overall performance. Learn more in the Introduction to Microservices Architecture.
  • The upcoming built-in GraphQL processor will parse the queries and resolve them by executing the RESTful API Engine requests. GraphQL has emerged at Facebook as the query language for the complex collections of APIs. Their numerous apps needed small subsets of data from multiple sources, which required several requests fetching too much data. Graph QL server is the “fat client” that defines the supported query types. The server accepts the queries formulated as a graph and delegates the execution to the custom resolvers. The output of multiple resolvers is merged in the graph that matches the query.
  • The App Studio application is a part of each Code On Time installation. This local web app presently starts the product activation process by redirecting developers to the account management portal. App Studio will come with the RESTful API Engine enabled in the future releases. It will serve as the local project management portal that will replace the start page of the app generator, which will be relegated to the icon tray. It will also provide the backend to the v9 Live Project Designer. The code generator will be invoked in the command line mode by the RESTful API Engine of the App Studio in response to the developer activities in the Project Designer of live apps. This is the architectural departure from our original plan outlined in the Roadmap, but we are on the finishing line now to deliver the amazing development tools in the heads of developers.
  • Content Hub, our innovative publishing platform, creates the new content in our legacy public site. We have developed this platform for internal use. The hub agent monitors the shared drives in our corporate Google Drive and transforms the changed documents into the HTML-based Display Flow content published through the RESTful API to the account management portat. The portal feeds the content to the database of the legacy site. The following capabilities of the platform will become commercially available:
    • Content Hub Agent will monitor Google Drive, Office 365, and network folders for the content in Microsoft Word Format. The agent is a multi-platform application. Changes are pushed to the hub-enabled application built with Code On Time.
    • Content Hub Add-On for applications created with Code On Time will render the content imported by the hub agent as public pages, blog posts, documentation library, newsletters, helpdesk tickets, public forum posts, etc.
    • Add-on will provide the interactive content editor based on Touch UI. It will customize the presentation style of the live “content hub” pages. It will create tickets and community posts from within the apps built with Code On Time in the same format that is used by the hub agent. It will invoke the RESTful API of the app to read and write the hub content.

The release 8.9.24.0 includes the following features and enhancements:

  • (Framework) Upgraded the framework to jQuery.3.6.0 and the latest version of the Material Icons.
  • (AppGen) Added support for VS2022.
  • (App Gen) Develop command in the project options will activate the most recent version of Visual Studio if the solution file format version is 12.00. This will ensure that VS2022 starts when both VS2022 and 2019 are installed on the same machine.
  • The enhanced Postal Address Verification silently resolves the postal addresses with Google Geocoding. The customers in the United States can achieve a perfect resolution of each address in the USPS-approved format.
  • (Touch UI) New tag form-max-(xs|sm|md) will make the contents of the form aligned in the middle of the page.
  • (Touch UI) Input field tagged as text-style-primary will display in the "primary" color.
  • (Touch UI) Modal popups will have the header when displayed in the content pages, which have their own header hidden.
  • (DAF) Client-side cookies are created with the SameSite=Strict attribute.
  • (Framework) Access control check is performed in the correct sequence for the standard membership controllers both for reading and writing of data.
  • (Touch UI) New css rules to enable hover over the fields with the Actions lookup to ensure correct display of icons in the buttons.
  • (Touch UI) Right-clicking on the logo will open the menu panel.
  • RESTful API Engine is included in the generated apps.
  • (Framework) New js/sys/restful.js provides a thin wrapper on top of Fetch API for the RESTful API Engine.
  • (Touch UI) A click on the empty part of the app toolbar or reading pane button bar will close an visible popup menu.
  • (Touch UI) Eliminated the redundant 3rd level child Data View fetching in the form views with multi-level master-detail. This significantly reduces the load time of forms with master-detail field relationships.
  • (Touch UI) Improved stability of inline editing in multi-level master detail forms. In some situations the aggressive selection of items in DataView fields would have caused the unnecessary attempts to fetch data and server-side exceptions.
  • Universal Data Caching improves the response time of the requests to read data in Touch UI.
  • (Touch UI) The focused universal inputs are redrawn whether or not they have a value. Previously only non-empty inputs were redrawn.
  • (Touch UI) Simplified parsing of the virtual page activator.
  • Integrated codemirror-5.65.2 for the upcoming Content Hub Add-On to allow display and editing of code samples.
  • (Touch UI) Refactored the code responsible for the "scrollable" state of the system tab bar. The visual presentation goes from flat to scrolled when the scrollable content is detected and the view does not have the horizontal scrolling (grid with horizontal scrolling).
  • (Touch UI) Removed redundant CSS class definition.
  • (Framework) New $app.urlArgs() method returns an object map of the page location URL parameters of the specified argument. The argument is either a string or a hypermedia object with the 'href' property. If the parameter is not specified, then the URl of the page in the browser is used for the parameter extraction.
  • (Touch UI) Account Access grant for OAuth 2.0 Authorization Flows is now supported by the framework,
  • (Offline Sync) Improved reporting of data downloading errors during sync.
  • (Framework) ASP.NET version headers and X-Powered-By headers are not returned by the apps in the HTTP response headers.
  • (Client Framework) Server-side errors raised when the data is retrieved from the server are displayed in the notifiction bar at the bottom of the screen. This helps detect data fetching errors that may remain invisible to the developers.
  • (ASPX) New method Invoke is implemented in DataControllerService to handle all incoming requests. It allows file uploading in the apps with the aspx page model.
  • (Map) Clearing of the geo map will result in the new tooltip assigned to it.
  • (Touch UI) Fixed the exception raised when the quick find filter is cleared.
  • (App Gen) Develop command in the project options will activate the most recent version of Visual Studio if the solution file format version is 12.00. This ensures that VS2022 starts when both VS2022 and VS2019 are installed on the same machine.
  • (Designer) Action property "whenKeySelected"is correctly persisted when set to "No" in the Project Designer.
  • (Site Content) CreatedDate and ModifiedDate fields are set to the DateTime.UtcNow.
  • (CMS) Renamed "Workflow Register" option to "Site Content (recommended)". This option is available in the database connection string settings.
  • (Reports) Class Library projects are provided with the correct ReportViewer references. Previously the leading and trailing spaces have caused errors when building projects.
  • (Reports) Included the reference to the Microsoft RDL Designer for VS 2022 in the custom reports. The reference is visible to the developers in VS if the designer is not installed.
  • (Code Gen) Simplified the syntax of !String.IsNullOrEmpty in the C# source code.
  • (Code Gen) Added support for IsNullOrWhiteSpace unary code generation expression.
  • (CodeGen) Value Inequality operators are produced as natural a != b and a<>b operators in C# and VB. Previously such operators were generated as !(a==b) and Not(a = b).
  • (Code Gen) C# code string constants are now presented with "string" + "string" breaks.
  • (Code Gen) C# code placed to the previous text line the symbols +|-|*|/|% that were previously wrapped to the next line.
  • (Codegen) C# code simplification of "params System.Object[]" to "params object[]".
  • (Framework) Numeric primary keys do not cause hidden exceptions when new BLOBs are uploaded with ODP.
  • (Framework) Method $app.actionInfo(path) returns the information about the action for the specified path in the format "groupId/actionId".
  • (Touch UI) Actions rendered as "Actons" field display simple confirmations and data controller confirmations.
  • (Touch UI) Remove the preloading instructions for the fonts. Added the version of the app to the font reference in the touch-theme.css.
  • (CodeGen) Class attribute definitions in C# will have "spaces" surrounding the "=" preceding the attribute parameter values.
  • (Touch UI) Right-clicking on the logo will open the menu panel.
  • (Touch UI) Click on the empty part of the app toolbar or reading pane button bar will close an visible popup menu.
  • (Touch UI) Eliminated the redundant 3rd level child Data View refresh in the form views with multi-level master-detail.
  • (Touch UI) Improved stability of inline editing in multi-level master detail forms.
Thursday, April 21, 2022PrintSubscribe
BLOBs with RESTful API

Touch UI provides the following view of the Categories in the backend application. The Picture field contents can be downloaded, replaced, or deleted by users. The sketch pad allows making visual annotations on the image.

Images can be downloaded, replaced, or deleted. The BLOB input of Touch UI allows making the visual annotations on the image. The BLOB data is physically stored in the database or external storage.
Images can be downloaded, replaced, or deleted. The BLOB input of Touch UI allows making the visual annotations on the image. The BLOB data is physically stored in the database or external storage.

Every row in the Categories table contains a Binary Large Object (BLOB) in the Picture column. The data type of the column is image. Modern database engines allow storing the binary data of variable length directly in the tables. Applications created with Code On Time work with the BLOBs stored in the database or external storage, such as a folder of the file system or a container in Microsoft Azure.

The JSON data presented below is the categories singleton resource returned by the backend. There are five fields and lots of hypermedia. The picture field and products field have the API links as their values. The former corresponds to the physical column Categories.Picture. The latter is the products field defined in the Categories model.

RESTful API allows fetching the BLOB values, passing BLOBs in the CRUD requests, and replacing or deleting the BLOBs in the singleton resource fields.
JSON
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152{
    "categoryId": 1,
    "categoryName": "Beverages",
    "description": "Soft drinks, coffees, teas, beers, and ales",
    "picture": "/v2/categories/1/picture",
    "products": "/v2/categories/1/products",
    "_links": {
        "self": {
            "href": "/v2/categories/1"
        },
        "up": {
            "href": "/v2/categories"
        },
        "collection": {
            "href": "/v2/categories?count=true"
        },
        "first": {
            "href": "/v2/categories?page=0&limit=10"
        },
        "products": {
            "href": "/v2/categories/1/products?count=true",
            "embeddable": true
        },
        "products-first": {
            "href": "/v2/categories/1/products?page=0&limit=10",
            "embeddable": true
        },
        "edit": {
            "href": "/v2/categories/1",
            "method": "PATCH"
        },
        "replace": {
            "href": "/v2/categories/1",
            "method": "PUT"
        },
        "replace-picture": {
            "href": "/v2/categories/1/picture",
            "method": "PUT"
        },
        "delete-picture": {
            "href": "/v2/categories/1/picture",
            "method": "DELETE"
        },
        "delete": {
            "href": "/v2/categories/1",
            "method": "DELETE"
        },
        "schema": {
            "href": "/v2/categories/1?_schema=true"
        }
    }
}

Fetching BLOBs

The BLOB can be fetched if the value of the singleton resource field is not equal to null. The link in the value identifies the resource followed by the name of the field. The original file name of the BLOB may follow the field name in the resource URL with certain configurations of the resource data controller.

Links in Values

The BLOB link in the sample data shown above consists of the /v2/categories/1 singleton resource URL and the picture field name concatenated together. An attempt to load the blob in the incognito or private browser mode will force the backend application to return the error. An authorization key or access token is required to read the resources known to the RESTful API.

RESTful API must be enabled explicitly in the application configuration. An authorization key or access token is required to access a resource.
RESTful API must be enabled explicitly in the application configuration. An authorization key or access token is required to access a resource.

Navigate to the backend application in the new browser window, sign in, and enter the same URL in the address bar. The image will be loaded successfully . Touch UI application creates an encrypted cookie to track the user identity. The BLOB request will be authenticated since the cookie is sent by the browser with each request.

RESTful API Engine identifies the user automatically when the host application is making a request. The cookie with the self-encrypted user access token provides the identity information.
RESTful API Engine identifies the user automatically when the host application is making a request. The cookie with the self-encrypted user access token provides the identity information.

Standalone single page applications and other HTTP clients will have to specify an authorization key or access token explicitly. Here is the blob fetched by Postman with the authorization key specified in the URL.

Postman shows the BLOB fetched from the resource with the authorization key specified in the "x-api-key" query parameter. RESTful API Engine requires an access token or authorization key to be specified explicitly by the external applications.
Postman shows the BLOB fetched from the resource with the authorization key specified in the "x-api-key" query parameter. RESTful API Engine requires an access token or authorization key to be specified explicitly by the external applications.

Most client applications will not be able to secure an authorization key or set up a cookie with the user identity. JavaScript client apps can establish a secure communication channel with the backend by taking advantage of the restful.js script. It is being used extensively in the standalone single page apps of the workshop.

Here is the customized SPA4 with RESTful Hypermedia and CRUD client app that fetches the images from the backend application in a secure fashion. An image appears in the Category cell when clicked by users.

The standalone single page application fetches the image of the product category on-demand when the category name is clicked. The app follows the hypermedia links to find the product category "picture" field value.
The standalone single page application fetches the image of the product category on-demand when the category name is clicked. The app follows the hypermedia links to find the product category "picture" field value.

The BLOB resource URL cannot be assigned to the src attribute of the image and must be fetched from the backend with the access token specified in the request header.

This is the modified version of the handleHypermedia function that does the image retrieval and assignment.

JavaScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758function handleHypermedia(e) {
    var row = e.target.closest('[data-index]')
    if (row && products) {
        let tableCell = e.target.closest('td');
        if (tableCell.previousSibling != null && tableCell.previousSibling.previousSibling == null) {
            // the cell in the "Category" column was clicked
            $app.restful({
                url: products.collection[row.getAttribute("data-index")]._links.self,
                hypermedia: 'categoryId >>'
            }).then(obj => {
                $app.restful({
                    url: obj.picture
                }).then(blob => {
                    // create an object URL
                    let dataUrl = URL.createObjectURL(blob);
                    // create an image element and replace the cell content with it
                    let img = document.createElement('img');
                    img.src = dataUrl;            // set the image src
                    img.title = obj.categoryName; // set the image tooltip
                    img.style.maxWidth =          // set the maximum image width
                        tableCell.getBoundingClientRect().width - 12 + 'px';
                    // clear the cell content
                    tableCell.innerHTML = '';
                    // insert image in the cell
                    tableCell.appendChild(img);
                });
            });
        }
        else
            readProduct(row.getAttribute("data-index"));
    }
    else {
        var btn = e.target.closest('[data-hypermedia]');
        if (btn && products) {
            var hypermedia = btn.getAttribute('data-hypermedia');
            switch (hypermedia) {
                case 'new':
                    newProduct();
                    break;
                case 'create':
                    postProduct();
                    break;
                case 'edit':
                    patchProduct();
                    break;
                case 'delete':
                    deleteProduct();
                    break;
                case 'cancel':
                    hideForm();
                    break;
                default:
                    refreshProductList(products._links[hypermedia]);
                    break;
            }
        }
    }
}

The original implementation orchestrates the UI flow in the app by responding to the clicks on the product list rows and buttons. The Edit Product form is displayed when users click anywhere in the product row.

The extended code figures when the click occurs in the second column of the product table and goes on to fetch and display the category image in the table cell:

  • First, it invokes the $app.restful method. The self link of the clicked product item is specified in the url parameter. The hypermedia parameter tells the method to locate and fetch the categoryId hypermedia control in the singleton product resource. The obj argument in the then chain function will be the instance of the category object just like the one shown at the top of the tutorial.
  • The obj argument has the picture property. Another call of the $app.restful method will fetch the BLOB object from the url specified in the property value. The blob argument of the then chain function is the instance of the Blob object. The $app.restful method converts the server response into a Blob instance if the content type of the response is not JSON, XML, or YAML.
  • Finally, the Object URL is created from the Blob instance and the table cell contents are replaced with the image that has its src attribute set to base-64 encoded URL. The image is fitted to the cell boundaries and has its title set to the category name to serve as a tooltip.

The products resource collection items do not have the URL of the category picture. The display of the category image takes three requests:

  1. The product item is fetched from the self hypermedia link of the selected item in the product collection.
  2. The category is fetched from the categoryId hypermedia control of the product item.
  3. The BLOB is fetched from the resource specified by the picture field of the product category.
Client application discovers the missing data by following the hypermedia links.

A shrewd developer may figure the correct category image URL and reduce this discovery sequence to a single request:

JavaScript
123456789101112131415161718// the cell in the "Category" column was clicked
Let productItem = products.collection[row.getAttribute("data-index")];
$app.restful({
    url: '/v2/categories/' + productItem.categoryId + '/picture'
}).then(blob => {
    // create an object URL
    let dataUrl = URL.createObjectURL(blob);
    // create an image element and replace the cell content with it
    let img = document.createElement('img');
    img.src = dataUrl;            // set the image src
    img.title = productItem.categoryName; // set the image tooltip
    img.style.maxWidth =          // set the maximum image width
        tableCell.getBoundingClientRect().width - 12 + 'px';
    // clear the cell content
    tableCell.innerHTML = '';
    // insert image in the cell
    tableCell.appendChild(img);
});

The item in the product collection has the categoryId, which can be used to construct the URL of the categories resource singleton field without much difficulty.

The explicit resource URLs in the client application create a tight coupling between the client and the current implementation of the backend. This may lead to broken apps when the backend evolves over time.

If efficiency is important, then consider including the additional fields in the collections and singletons by denormalizing the data models. Avoid using the explicit URLs in the client code to ensure the application longevity and maintainability.

Public Links

Making dedicated requests to fetch an image from the server may seem exotic, but unavoidable if the images cannot be exposed to the world. BLOB objects may represent documents, images, video, and sound files, which frequently require limited access.

The product category image is not something that needs to be kept private. If that is the case, then an authorization key must become a part of the image URL specified in the src attribute of the img element. The job of fetching the image from the server can be outsourced to the browser and Document Object Model.

Let’s introduce the public authorization key in the ~/app/touch-settings.json configuration file of the backend application. Note that there is also the server.rest.acl section specifying the Access Control List of the API.

JSON
123456789101112131415161718192021222324252627282930313233343536{
  "ui": {
    "roles": "Administrators"
  },
  "server": {
    "rest": {
      "enabled": true,
      "output": {
        "json": {
          "indent": true
        }
      },
      "authorization": {
        "keys": [
          {
            "key": "94b79da7-e3a9-4152-9213-886f4c810bec",
            "user": "admin"
          },
          {
            "key": "public",
            "user": "user"
          }
        ]
      },
      "acl": {
        "categories": {
          "administrators": ".",
          "users": "GET"
        },
        "products|suppliers": {
          "administrators": "."
        }
      }
    }
  }
}

The word “public” is the fitting name for the public authorization key. In this example, the user account is associated with the public key.

The authorization key can be specified as the x-api-key or api_key query parameter. There is also a more elegant method of specifying the authorization key in the URL. The key may be included in the path right after the API version like this:

https://demo.codeontime.com/v2/public/categories/8/picture

The URL with the public key in the path will fetch the image in the incognito mode if the access control list allows it.
The URL with the public key in the path will fetch the image in the incognito mode if the access control list allows it.

The word “public” in the key name has no special meaning and can be replaced with any mnemonic. Any authorization key discoverable by the third party is the public key.

Developers must configure an access control list (ACL) to limit the API exposure to the unauthenticated users that will consume the resources with a public authorization key.

The ACL in the configuration above will allow the identities with the Users role to perform the GET requests to the categories resources. Users in the Administrators role can perform requests to the resources of categories, products, and suppliers with any HTTP verb.

The names of the server.rest.acl key properties are the controller rules (regular expressions) that will be evaluated against the names of the data controllers. If the rule of the access control list is matched with the data controller name in the resource path, then the restful API will evaluate the identity rules (the properties of the matched controller rule). The property names are the application user roles or the OAuth 2.0 scopes. If the current user is in role or has the scope in the access token, then the engine will try to match the HTTP method or the custom action identifier with the identity rule value (also a regular expression). If there is no match, then the access is denied.

This is the code that will use the public authorization key to fetch the category images when the category name is clicked in the product grid.

JavaScript
12345678910111213// the cell in the "Category" column was clicked
let productItem = products.collection[row.getAttribute("data-index")];
let img = document.createElement('img');
img.src =                             
    'https://demo.codeontime.com/v2/public/categories/' +  
    productItem.categoryId + '/picture'; // set the image src
img.title = productItem.categoryName;    // set the image tooltip
img.style.maxWidth =                     // set the maximum image width
    tableCell.getBoundingClientRect().width - 12 + 'px';
// clear the cell content
tableCell.innerHTML = '';
// insert image in the cell
tableCell.appendChild(img);

There are no explicit resource fetching requests. A simple assignment to the src property of the img element does the job. The only concern is the hard-coded URL pointing to the backend application.

File Names in Links

The Categories table does not store the attributes of the Picture image file. The original name, type, and length of the file is not known. The BLOB processing code of the framework detects the image data automatically and sets the appropriate content type and a generic file name in the response to the request to fetch a BLOB resource. The generic content type application/octet-stream will describe a BLOB that does not contain an image.

The resource /v2/public/categories/1/picture will fetch the BLOB data even though it appears to lack the physical file name.

Application framework relies on the optional utility fields to provide the extended information about the BLOB fields of a data controller. The field names FileName, ContentType, and Length will be treated as the default utility fields. Developers can be more specific and prefix the default utility field names with the name of the corresponding BLOB field.

Alter the Categories table by adding the FileName, ContentType, and Length columns to store the extended properties of the BLOB in the Picture column. Make sure that the BLOB and the utility columns allow null values.

image3.png

Select the backend application project on the start page of the app generator, choose Refresh, and proceed to incorporate the new database schema in the project metadata. Select the Model option in the summary, choose the Categories model, and select the new columns to include them in the entity data model.

Model Builder makes it easy to perform iterative enhancement of the data models when the database schema is changed.
Model Builder makes it easy to perform iterative enhancement of the data models when the database schema is changed.

Save the Categories model and proceed to generate the app. The new fields will become a part of the user interface. Begin adding a new category and observe how the File Name, Content Type, and Length are automatically set to the properties of the selected Picture file.

Touch UI automatically detects the "utility" fields and captures the File Name, Content Type, and Length of the binary data when a file is selected or dropped on the BLOB input field.
Touch UI automatically detects the "utility" fields and captures the File Name, Content Type, and Length of the binary data when a file is selected or dropped on the BLOB input field.

Changes to the model are also reflected in the RESTful API. Here is how the new categories singleton resource may appear to the apps and developers:

JSON
1234567891011121314151617181920212223242526{
    "_links": {
        "self": {
            "href": "/v2/public/categories/197"
        },
        "up": {
            "href": "/v2/public/categories"
        },
        "collection": {
            "href": "/v2/public/categories?count=true"
        },
        "first": {
            "href": "/v2/public/categories?page=0&limit=10"
        },
        "schema": {
            "href": "/v2/public/categories/197?_schema=true"
        }
    },
    "categoryId": 197,
    "categoryName": "Baked Goods",
    "description": "Breads, cookies, pastries",
    "picture": "/v2/public/categories/MTk3L3BpY3R1cmUvag.jpeg",
    "fileName": "bread.jpeg",
    "contentType": "image/jpeg",
    "length": 13155
}

Note that that picture value now has the file name but lacks the identifier of the singleton. The resource /v2/categories/197/picture transforms to /v2/categories/MTk3L3BpY3R1cmUvag.jpeg in the BLOB value. The URL is not affected by the original file name but inherits the file extension. The extension helps users to understand the nature of data.

The BLOB value with the authorization key in the path can be used in the public-facing websites. The extension of the file name gives a hint about the data type.
The BLOB value with the authorization key in the path can be used in the public-facing websites. The extension of the file name gives a hint about the data type.

If the “FileName” utility field is a part of the data controller, then its resource will have the BLOB value URL ending with the file name composed of its base64-url-encoded BLOB field name preceded by the previous path segment. The encoded file name will have the same extension as the original file.

ETag and 304 Not Modified

The headers of the response to the BLOB resource request will include the ETag (entity tag). The value is the unique hash of the BLOB content. Web browsers capture the ETag and send it with the subsequent requests to fetch the same resource.

The response of the BLOB resource request includes the ETag, Content-Type, Content-Disposition, and Content-Length headers. ETag value can be used to avoid the unnecessary transmission of the unchanged BLOB. Type, Disposition, and Length provide the client with the BLOB metadata.
The response of the BLOB resource request includes the ETag, Content-Type, Content-Disposition, and Content-Length headers. ETag value can be used to avoid the unnecessary transmission of the unchanged BLOB. Type, Disposition, and Length provide the client with the BLOB metadata.

The RESTful API Engine will compare the optional If-None-Match header of the request with the ETag of the resource. If both values are the same, then the engine will not send the BLOB data in the response. The body will be empty and the response status code will be set to 304 Not Modified. The client application will use the previously fetched resource data.

The "304 Not Modified" response includes the ETag of the resource that has not changed since the last fetch.
The "304 Not Modified" response includes the ETag of the resource that has not changed since the last fetch.

Web browsers and views automatically use the If-None-Match and ETag headers, which helps avoid the unnecessary transmission of data.

BLOBs in CRUD Requests

Binary field values can be specified in the CRUD operations with PUT, POST, and PATCH verbs. These HTTP methods correspond to the replace, create, and edit hypermedia controls in the resources of the RESTful API Engine.

The BLOB values can be found in the collection and singleton resources. The values of the BLOB fields are the API resources links.

Multipart Form Data

The content type multipart/form-data tells the server that the binary content is specified in the request body. The HTML forms with the “file” inputs are submitted with this content type in the “formdata” format by the web browsers and views.

Here is how the request with the binary data is constructed in Postman. This request will create a new category. Individual field values are listed as key-value pairs in the form-data tab of the request body. The picture field is configured as the file. The response body shows the new resource with the BLOB link in the picture value.

This is the "create" request in the Postman with the form-data fields in the request and the new category resource in the response. The "file" value is specified in the "picture" field of the request. The properties of the file are automatically captured by the RESTful API Engine in the "fileName", "contentType", and "length" fields of the new resource.
This is the "create" request in the Postman with the form-data fields in the request and the new category resource in the response. The "file" value is specified in the "picture" field of the request. The properties of the file are automatically captured by the RESTful API Engine in the "fileName", "contentType", and "length" fields of the new resource.

The plain JavaScript code that will create a category in the browser page is presented next. It uses the Fetch API to make the POST request. Note the use of the x-api-key header set to the authorization key of the admin user.

JavaScript
12345678910111213141516171819var myHeaders = new Headers();
myHeaders.append("x-api-key", "94b79da7-e3a9-4152-9213-886f4c810bec");

var formdata = new FormData();
formdata.append("categoryName", "Baked Goods");
formdata.append("description", "Breads, cookies, pastries");
formdata.append("picture", fileInput.files[0], "bread.jpeg");

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: formdata,
  redirect: 'follow'
};

fetch("https://demo.codeontime.com/v2/categories", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

The categoryName and description request fields can be specified in the single JSON object as the value of the unnamed field in the form-data. Its content type must be set to application/json. The binary fields of the resource must be specified as the named fields of the form-data. The order of the fields in the form-data is not important.

The non-binary fields of he request are specified in the form-data field without a name in the JSON format.
The non-binary fields of he request are specified in the form-data field without a name in the JSON format.

The raw HTTP request with the multipart/form-data content type is presented in the sample below. The request will create a new category. Client applications can configure HTTP requests on their own or use the libraries available with their chosen implementation technologies.

HTTP
1234567891011121314151617181920POST /v2/categories HTTP/1.1
Host: localhost:42439
x-api-key: 94b79da7-e3a9-4152-9213-886f4c810bec
Content-Length: 408
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="picture"; filename="bread.jpeg"
Content-Type: image/jpeg

(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name=""
Content-Type: application/json

{ 
   "categoryName": "Baked Goods",
   "description": "Breads, cookies, pastries"
}
----WebKitFormBoundary7MA4YWxkTrZu0gW

Method $app.restful

The standalone single page applications SPA4 and SPA5 are linking the lightweight external script with the definition of $app.restful method. The method automatically specifies the access token in the HTTP request headers to identify the user. The method refreshes the expired access token. An explicit resource URL or a hypermedia control can be specified in the url property of the method argument.

The restful.js resource of the backend application provides the standalone clients with a thin wrapper on top of the Fetch API.

The $app.restful method also detects the Blob fields specified in the body property of the argument. The request body with the Blob fields is automatically converted to an instance of the FormData object.

Let’s modify the CRUD-enabled version of SPA4 to create a category with the user-defined image in the picture field. Users will click on their avatar to activate the File Chooser prompt. The selected image file will become the picture of the new “Baked Goods” category. The name and the description of the category will be hard-coded for simplicity.

image15.png

Users can create new products in this category and observe the picture when the Category column is clicked in the product row.

image9.png

Add the following code at the bottom of the closure in the spa4.js. The code will attach the click handler to the avatar when the spa4.html page is loaded in the browser window.

JavaScript
123456789101112131415161718192021222324252627window.addEventListener('load', e => {
    // add 'click' event handler to the user avatar
    document.querySelector('#avatar').addEventListener('click', e => {
        // create a "file" input 
        var fileInput = document.createElement('input');
        fileInput.type = 'file';
        // wait for the "picture" file to be selected
        fileInput.addEventListener('change', e => {
            // create the "Baked Goods" category with the selected picture
            $app.restful({
                url: '/v2/categories',
                method: 'POST',
                body: {
                    categoryName: "Baked Goods",
                    description: "Breads, cookies, pastries",
                    picture: fileInput.files[0] // the picture image
                }
            }).then(newCategory => {
                // show the ID of the new category
                alert(newCategory.categoryId);
            }).catch(restfulException);

        });
        // display the File Chooser prompt in the browser 
        fileInput.click();
    });
});

The code dynamically creates an input of the file type and “clicks” it programmatically. The prompt to select a file is displayed. The change event will trigger on the input when a file is selected by the user. The $app.restful method executes the POST request with the categoryName, description, and picture specified in the body property of the method argument. The picture is set to the selected file.

Replacing and Deleting BLOB Values

The categories resource singleton hypermedia contains the replace-picture and delete-picture controls.

The blob image in the picture field of the resource can be replaced with the $app.restful method that has the replace-picture hypermedia object specified in its url property of the argument. The value field in the body property must be set to the new Blob or File value.

The delete-picture hypermedia control in the url property of the method argument will clear the BLOB value in the picture field.

The pair of the explicit url and method values can replace the hypermedia control in the $app.restful argument properties.

Next

Hypermedia in the resources provides instant documentation for developers and methods to transition the resource state or access the related data for the algorithms.

Learn to navigate the RESTful resources in the development tools and client apps.