Beyond Composability: Using Uniform as an Internal Tool

Explore what Internal Tool is and how to leverage Uniform as an Internal tool to build a News timeline application in Flutter.

avatar

Demola Malomo

Apr 17 2023

8 min read

avatar

According to Internal, one of the leading Internal Tools providers, IT and engineering teams spend 40% of their time building and maintaining internally-facing applications and workflows utilized within their organization. It has led to organizations having dedicated software engineering teams or leveraging internal tooling platforms to cater for their organization's needs.

In this article, we will explore what Internal Tool is and how we can leverage Uniform as an Internal tool to build a News timeline application in Flutter.

What are Internal Tools?

Internal Tools are any internal-facing software developed and utilized by a company to support internal operations. Based on the company’s needs, the decision about Internal Tooling usually boils down to building it internally (flexible and with no vendor lock-ins) or purchasing it as a service. The following are some of the advantages:

  • Cost-effective
  • Improved security
  • Time-saving
  • More control and increased productivity
  • Automate repetitive task

The most common internal tools help companies serve customer queries, analyze users’ behaviour, manage content, and manage APIs and requests.

Despite its offering, Internal Tools also comes with its baggage. Beyond the learning curve, the cost of subscription and maintenance, among others. It is especially difficult for small organizations with limited resources to either dedicate software engineering teams or subscribe to an Internal Tooling platform to help support internal operations.

Exploring Uniform and its offering

Uniform is a digital experience platform that allows companies or individuals to frictionlessly adopt traditional and headless technologies without the associated overheads. It allows businesses to deliver built-in high-performance testing and personalization orchestration. Beyond it being a digital experience platform for composing experience, it offers some unique functionalities that small to large companies can leverage as an internal tool.

Multiple integration support

Uniform supports more than 40 integrations ranging from Content Delivery Networks, Headless Content Management Systems, Analytic tools, Email Management and Media Management. The platform makes integration easy by eliminating the need for manual connections.

No-code solution

The platform provides an intuitive user experience that developers, marketers, content developers, and other practitioners need to cater for business operations with little to no IT and ops involvement.

Source of truth

Uniform provides a truly composable digital experience with support for multiple stacks ranging from Commerce, CMS, Data, CDNs, etc. It delivers it as a single source of truth through its secure and fast API.

Best-in-class User Experience

Beyond the intuitive User Interface, Uniform also caters for developers by providing best-in-class developer documentation, SDKs, and libraries.

Building the News timeline with Flutter and Uniform

Now that we understand what Internal tools are and how we can leverage Uniform functionalities as one, let’s now build a News timeline with Flutter and Uniform.

Prerequisites

To fully grasp the concepts presented in this tutorial, the following are required:

Getting started

To get started, we need to clone the project by navigating to the desired directory and running the command below:

1git clone https://github.com/Mr-Malomz/news_mobile && cd news_mobile

Running the project

First, we need to install the project dependencies by running the command below:

1flutter pub get

Then, run the project using the following command:

1flutter run

The command above will run the application on the selected device.

Running app

Image Sourcing and Upload to Cloudinary

To start building our application, we must upload sample images for our News timeline application.

Sample data:

News titleImage URL
You’re Using ChatGPT Wrong! Here’s How to Be Ahead of 99% of ChatGPT Usershttps://bit.ly/3zBNZYG
Web3 crash course: The essentialshttps://bit.ly/3UiOKzm
How to write and design good API documentationhttps://bit.ly/3GqxjqZ

In our Cloudinary dashboard, we uploaded the images by clicking on the Media Library tab, clicking on Upload, selecting the Web Address option, inputting the URL, and clicking on the Arrow Button to upload.

select web address and enter url

After uploading the image, we will see it displayed on the console.

displayed images

Putting it all together on Uniform

With that done, we can start creating component libraries on Uniform. To do this, we must sign up and fill in the required information.

Next, input desired project name and click Continue.

Next, navigate to the Security tab, select API Keys, and click on the Add API key button to create one. Input news_mobile as the API name, select Developer as the Role and click the Create API Key button to create the API key.

Create API key

Input details

With this done, we should see a screen containing our API Key and Project ID. We need to copy these values as they will come in handy when building our application with Flutter.

API Key and project ID

How modelling works in Uniform

Uniform uses the concept of Components and Compositions to model application needs. Components in Uniform application work similarly to those in software development; it lets us break our application into smaller reusable building blocks with properties, while a Composition is the combination of one or more components.

Application model

Add Cloudinary integration support

Uniform improves the product’s digital experience through integration with an existing system. To connect Cloudinary to our project, we need to navigate to the Home tab, click on the project, and navigate to the Integrations tab.

Add Integration

Search or browse through the available integrations, select the Cloudinary integration, click on the Add to project button, input the Cloudname, API Key, Test and Save.

Select BigCommerce

Add Integration

Add Cloudname & API Key

We can get our Cloud Name and API Key from our Cloudinary dashboard.

Cloudinary Details

Create components

To get started, navigate to the Home tab and click on the project. Then click on the Content menu, select the Components, and click the Add component button.

Create Component

Parameter NameHelp TextTyperequired
news_titlenews titletextYES
news_imagenews imageCloudinary ImageYES

Input news_timeline as the component name, select smartphone as the icon, add properties of news_title, and news_image as shown above, and then click OK.

component name component properties added properties

Then click on the Save and Close button.

save and close

Now that we have created the news_timeline, it will serve as a blueprint/building block for creating our News timeline application.

To start, navigate to the Component screen, click the Add component button, input news_screen as the component name, and check the Composition Component. Then navigate to the Slots section, and click the Add slot to create a slot.

Add slot

PS: Slots help us create instances of our component and allow them to accept data dynamically.*

Input news_screen as the Slot Name and click OK.

create slots

Then click on the Save and Close button.

With that done, we can start using the news_screen component to compose our News timeline application. To get started, navigate to the Composition tab, select the news_screen as the composition type, input news_mobile as the name, and Create.

create composition

Next, click on the Plus Icon to add a component to the composition.

create component

Select the news_timeline, add the corresponding name and image for the component.

select flower_component add data add data

We need to repeat the steps above to add the remaining news_timeline data. Then click on Publish. This makes our composition available to third-party applications.

Hover on the item and click on the plus icon to add component Save and publish changes

We also need to note the composition slug; it will be useful when querying Uniform for our News data.

composition slug

Integrating Uniform with Flutter

With that done, we can start building the user interface and use Uniform to deliver the list of news seamlessly.

Creating Application Model

Uniform ships with a language-agnostic Platform API for managing and composing experience. We can test the API by filling in the API Key, Project ID, and Slug.

API response from Uniform

With that in mind, we need to create a model to convert the response sent from Uniform to a Dart object. The model will also cater to JSON serialization. To do this, create an utils.dart file inside the libs folder and add the snippet below:

1class RootComposition { 2 Composition composition; 3 String created; 4 RootComposition({required this.composition, required this.created}); 5 factory RootComposition.fromJson(Map<String, dynamic> json) { 6 return RootComposition( 7 composition: Composition.fromJson(json['composition']), 8 created: json['created'], 9 ); 10 } 11} 12 13class Composition { 14 Slots slots; 15 Composition({required this.slots}); 16 factory Composition.fromJson(Map<String, dynamic> json) { 17 return Composition( 18 slots: Slots.fromJson(json['slots']), 19 ); 20 } 21} 22 23class Slots { 24 List<NewsScreen> news; 25 Slots({required this.news}); 26 factory Slots.fromJson(Map<String, dynamic> json) { 27 var data = json['newsScreen'] as List; 28 return Slots( 29 news: data.map((news) => NewsScreen.fromJson(news)).toList(), 30 ); 31 } 32} 33 34class NewsScreen { 35 Parameters parameters; 36 NewsScreen({required this.parameters}); 37 factory NewsScreen.fromJson(Map<String, dynamic> json) { 38 return NewsScreen( 39 parameters: Parameters.fromJson(json['parameters']), 40 ); 41 } 42} 43 44class Parameters { 45 NewsImage newsImage; 46 NewsTitle newsTitle; 47 Parameters({required this.newsImage, required this.newsTitle}); 48 factory Parameters.fromJson(Map<String, dynamic> json) { 49 return Parameters( 50 newsImage: NewsImage.fromJson(json['newsImage']), 51 newsTitle: NewsTitle.fromJson(json['newsTitle']), 52 ); 53 } 54} 55 56class NewsImage { 57 Value value; 58 NewsImage({required this.value}); 59 factory NewsImage.fromJson(Map<String, dynamic> json) { 60 return NewsImage( 61 value: Value.fromJson(json\['value'\][0]), 62 ); 63 } 64} 65 66class Value { 67 String url; 68 Value({required this.url}); 69 factory Value.fromJson(Map<String, dynamic> json) { 70 return Value( 71 url: json['url'], 72 ); 73 } 74} 75 76class NewsTitle { 77 String value; 78 NewsTitle({required this.value}); 79 factory NewsTitle.fromJson(Map<String, dynamic> json) { 80 return NewsTitle( 81 value: json['value'], 82 ); 83 } 84}

Next, we must create a service file to separate the application core logic from the UI. To do this, create a uniform_service.dart file inside the lib directory. Then, add the snippet below:

1import 'package:dio/dio.dart'; 2import 'package:news_mobile/utils.dart'; 3 4class UniformService { 5 final dio = Dio(); 6 static const _apiKey = "REPLACE WITH API KEY"; 7 static const _projectID = "REPLACE WITH PROJECT ID"; 8 static const _slug = "newsMobile"; 9 10 var headers = { 11 "content-type": "application/json", 12 "x-api-key": _apiKey, 13 }; 14 15 Future<RootComposition> getNews() async { 16 var response = await dio.get( 17 "https://uniform.app/api/v1/canvas?limit=100&projectId=$_projectID&slug=$_slug", 18 options: Options(headers: headers), 19 ); 20 21 if (response.statusCode == 200) { 22 var resp = response.data; 23 var news = RootComposition.fromJson(resp); 24 return news; 25 } else { 26 throw Exception('Error getting news'); 27 } 28 } 29}

The snippet above does the following:

  • Imports the required dependencies
  • Creates a UniformService class with _apiKey, _projectID, _slug and headers properties.
  • Creates the getNews method that uses the Dio package to configure permissions and make secure HTTPS request to the Uniform API and returns the appropriate responses

Consuming the service

With that done, we can use the service to perform the required operation. To do this, we need to modify the home.dart file in the screens directory as shown below:

1import 'package:flutter/material.dart'; 2import 'package:news_mobile/uniform_service.dart'; 3import 'package:news_mobile/utils.dart'; 4 5class Home extends StatefulWidget { 6 const Home({super.key}); 7 8 9 State<Home> createState() => _HomeState(); 10} 11 12class _HomeState extends State<Home> { 13 late RootComposition news; 14 bool _isLoading = false; 15 bool _isError = false; 16 17 18 void initState() { 19 _getNews(); 20 super.initState(); 21 } 22 _getNews() { 23 setState(() { 24 _isLoading = true; 25 }); 26 27 UniformService().getNews().then((value) { 28 setState(() { 29 news = value; 30 _isLoading = false; 31 }); 32 }).catchError((onError) { 33 setState(() { 34 _isLoading = false; 35 _isError = true; 36 }); 37 }); 38 } 39 40 41 Widget build(BuildContext context) { 42 return _isLoading 43 ? const Center( 44 child: CircularProgressIndicator( 45 color: Colors.blue, 46 )) 47 : _isError 48 ? const Center( 49 child: Text( 50 'Error getting news', 51 style: TextStyle( 52 color: Colors.red, 53 fontWeight: FontWeight.bold, 54 ), 55 ), 56 ) 57 : Scaffold( 58 appBar: AppBar( 59 title: const Text('News Timeline'), 60 backgroundColor: Colors.black, 61 ), 62 body: ListView.builder( 63 itemCount: news.composition.slots.news.length, 64 itemBuilder: (context, index) { 65 return Container( 66 decoration: const BoxDecoration( 67 border: Border( 68 bottom: BorderSide(width: .5, color: Colors.grey), 69 ), 70 ), 71 padding: const EdgeInsets.fromLTRB(10, 20, 10, 20), 72 child: Row( 73 children: [ 74 ClipRRect( 75 borderRadius: BorderRadius.circular(5.0), 76 child: Image.network( 77 news.composition.slots.news[index].parameters 78 .newsImage.value.url, 79 height: 80.0, 80 width: 80.0, 81 ), 82 ), 83 const SizedBox(width: 15.0), 84 Expanded( 85 child: Column( 86 crossAxisAlignment: CrossAxisAlignment.start, 87 children: [ 88 Text( 89 news.composition.slots.news[index].parameters 90 .newsTitle.value, 91 style: TextStyle( 92 color: Colors.black, 93 fontWeight: FontWeight.w800), 94 ), 95 SizedBox(height: 10.0), 96 Text( 97 news.created.substring(0, 10), 98 style: TextStyle( 99 color: Colors.grey, 100 ), 101 ) 102 ], 103 ), 104 ), 105 ], 106 ), 107 ); 108 }, 109 ), 110 ); 111 } 112}

The snippet above does the following:

  • Imports the required dependencies
  • Lines 13-15: Create the news, _isLoading, and _isError properties to manage the application state
  • Lines 17-39: Create a _getNews method to get the list of news from Uniform using the UniformService().getNews and set states accordingly
  • Modifies the UI to use the states and method created to get the news list

With that done, we restart the application using the code editor or run the command below:

1flutter run

Running app

Conclusion

This post discussed what Internal Tools are, Uniform’s uniqueness, and how to build a News timeline with Flutter. Beyond what was discussed above, Uniform also caters for marketers' and content strategies' operational needs with little or no IT and engineering team involvement.

These resources might be helpful:

Related posts