Tools
Tools: Part 2: Hands-on tc Framework: Building a Full-Stack Async API with Pages - Analysis
Introduction: The Practical Graph
Prerequisites & Environment Setup
Set up local dev environment
Defining the Topology (topology.yml)
States (Orchestration)
Functions (Business Logic / Compute)
Events (Asynchronous Messaging)
Routes (REST API Entry Points)
Mutations (GraphQL Operations)
Queues (Buffering)
Channels (Real-Time/Sockets)
Pages (Static Content)
The "Graph-First" Automation
The "Pages" Entity: Frontend as a First-Class Citizen
The Build Process: Bundling Logic
Implementing the Async Response & Progress Tracking
Algorithmic IAM Policies & Roles
Deployment: Moving into the Cloud
Wrap Up: The Cloud is Your Computer This post will show a practical, hands-on example that implements a serverless topology using the tc (Topology Composer) framework. It supports synchronous entry points with asynchronous real-time updates. You will construct a REST API (API Gateway Routes) backed by a Lambda producer. This Lambda producer emits an event to a an EventBridge Bus, which the framework routes to an AppSync Channel for Websocket broadcast via a secondary notifier function. Finally will show how to include a Web GUI by incorporating S3/CloudFront Pages for the frontend. By defining the system as a directed graph of logical connections rather than a list of static resources, tc derives all IAM policies, event rules, and infrastructure glue automatically, enforcing “least privilege” algorithmically. Before we start, make sure you have the following in place: A Note on Environment: This guide assumes you are working in a proper *nix environment (macOS or Linux). Only tested on macOS. Create a working directory and cd into it To set the context for this tutorial, copy and paste the following into your terminal: tc supports many conventions based on filenames and directory hierarchies. The core of your Functor is the topology.yml. This defines the graph: the logical connections where relationships are primary and infrastructure glue is derived algorithmically. There are currently 8 "atoms" that can be elements of a topology. You can compose these in the topology.yml file. In general tc supports convention over configuration with sensible automatic defaults for many things. But these can also be overriden in the topology.yml or function.json files. Abstraction: Represents the flow control, error handling, and decision-making logic of a system. In the "Cloud Functor" model, States coordinate tasks and delegate work to Functions or other subsystems, ensuring that business logic remains completely decoupled from the execution flow. Automation: Maps directly to AWS Step Functions. tc automates the state machine definition and the complex IAM roles required for the state machine to transition between states and invoke other resources. Abstraction: Represent pure business logic and act as side-effect-free compute units. They are the core computational workers of your topology where the actual application code lives and executes. Automation: Maps to Lambdas or ECS Containers. tc helps with the whole lifecycle of creating, maintaining and deploying Lambdas. There is support for a variety of languages, and packaging as it supports both zip and container image builds. We only use image builds for very large lambda images. Abstraction: Represents the "nerves" of the system—decoupled signals broadcast to interested subscribers without direct point-to-point dependencies. Automation: Maps to Amazon EventBridge. tc automates the creation of buses (or use of existing ones) and the definition of Rules that filter and route specific messages to targets (like queues or functions). Abstraction: Represents synchronous HTTP entry points into the topology. Automation: Maps to Amazon API Gateway (REST APIs). tc automates the creation of the API resources, methods (GET, POST, etc.), and the integration permissions required to invoke the backend logic. Abstraction: Represents data modification operations, typically used in modern frontend-backend interactions. Automation: Maps to AWS AppSync (GraphQL). tc automates the schema definition and resolver mapping, allowing developers to define a "Mutation" that triggers a function or updates a data source. Abstraction: Represents load leveling and asynchronous buffering between components. Automation: Maps to Amazon SQS. tc automates the queue creation and the "glue" permissions allowing specific functions to produce to or consume from the queue. Abstraction: Represents real-time communication pathways, allowing the server to push updates to clients (e.g., for chat apps or progress trackers). Automation: Maps to AWS AppSync Events (Websockets). tc automates the connection logic, allowing a topology to push messages to a "Channel" that connected frontend clients are subscribed to. Abstraction: Represents the frontend assets or static UI components of the application. Automation: Maps to Amazon S3 (storage) and CloudFront (CDN). tc manages the deployment of HTML/JS/CSS assets associated with the topology. Details: In most serverless frameworks, the frontend is a second-class citizen; just some files you manually shove into a bucket. In tc, the Pages entity brings the UI into the graph. Pages manages your static assets (HTML/JS/CSS) via S3 and CloudFront. To understand where this fits, look at our "Bones and Muscles" model. While you might use Terraform to build the "Bones": the heavy, static infrastructure like VPCs or RDS instances that provide rigidity Pages is part of the "Muscles." These are the high-velocity components that provide the actual motion of your application. Unlike Terraform, which relies on a brittle local state file, tc is stateless. It queries the "universe" (AWS) directly via the resolver to find those bones and attach the muscles. The Pages entity automates the "magic spells" of the cloud: provisioning the S3 bucket, setting up the CloudFront CDN, and handling invalidations. You define the path, and the system ensures the UI is wired to the same logical topology as your API. The true power of tc lies not just in creating these resources, but in automating the relationships between them. If a developer defines a topology where a Route triggers a Function, which puts a message on a Queue, tc automatically compiles the necessary: API Gateway Integration. IAM Policies (e.g., sqs:SendMessage scoped strictly to that queue). Event Source Mappings (connecting the Queue to a worker Function).This allows developers to define the system as a clean graph (Topology) while the tool handles the "spaghetti" of infrastructure configuration. In this graph, the composer sees that a route calls a function, which emits an event, which triggers a channel update. You aren't writing IAM policies or configuring EventBridge rules; you are describing how the data flows. Once your topology is defined, you run tc build. This command packages your business logic into deployable artifacts using the builder . If the Lambda function is relatively simple, like in our example here, there are little to no library dependencies, at least none that have CPYTHON or other transitive dependencies that require compiling/linking. In this simple case, tc build will just bundle up using Docker buildx all the Python (or other interpreted language) code in a standard ZIP file as for normal AWS Lambda images. Because tc uses Docker buildx for multi-architecture support (linux/amd64), your builds are consistent whether you’re on your laptop or running in a CI/CD pipeline. No more "it worked on my machine" excuses. By integrating Pages with Channels, we stop making the user stare at a loading spinner. Instead of a black-box backend that leaves the UI hanging, we make the application feel alive. Initiating the Request: The Pages frontend sends a POST request to the /request route. Async Processing: The processor function acknowledges the request immediately. Tracking Progress: As the function works, it emits events. These "nerves" of the system travel through the graph to the AppSync Channel. Real-Time Feedback: The frontend listens to the Websocket Channel. The UI updates in real-time as the backend moves through stages, providing a seamless, responsive experience. tc kills this problem through Algorithmic Authorization. The composer uses tested templates to automatically infer the intent of your graph: The compiler generates mathematically correct policies scoped to exact ARNs. You literally cannot forget a security condition because you don't write the JSON: the system derives it from the relationship. To move your Functor into the cloud, we use tc create and tc update. Let’s cut to the chase: tc does not manage a local state file. Instead, the resolver uses the AWS SDK to query the "universe" to find the ARNs of your "Bones" (VPC, etc.) and wires your "Muscles" to them. Run the following command to deploy: If you change the code or the topology graph, run tc update. The resolver will detect what changed in the cloud and apply only the necessary updates to the "muscle" layer, making the iteration cycle nearly instantaneous. In just a few steps, we have deployed a full-stack, event-driven application with a secured REST API and an async, Websocket-enabled frontend. By using a single graph definition, we’ve eliminated the manual "spaghetti" of infrastructure glue. We’ve seen how Functions (Pure Logic), Events (Nerves), and Pages (UI) work together. Turns out, once you stop fighting low-level primitives and start thinking in graphs, building complex systems becomes way too easy. You are no longer an infrastructure manager; you are a cloud programmer. Stay tuned for Part 3, where we will cover States the "Managers" (Step Functions) that handle flow control and error recovery in truly massive fractal architectures. tc Documentation: https://tc-functors.org/
tc Github: https://github.com/tc-functors/tc Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse