DEV Community

Cover image for Now you can build API like LEGO
Bao Ngo
Bao Ngo

Posted on

Now you can build API like LEGO

Hey again devs! Quick update on CFFBRW (my visual API builder I posted about earlier).

So I got some feedback that the workflow builder felt... well, kinda basic while being overwhelming (I am confused!). One dev literally said "this looks like my nephew's Scratch project" πŸ˜… Fair point. The drag-and-drop Sortable was functional but not exactly inspiring confidence for production use.

Two big updates that I have implemented over the week:
1. Rebuilt the whole visual editor with Google Blockly
I know, I know - Blockly is what they use to teach kids programming. But hear me out. After wrestling with custom drag-and-drop for weeks, I realized Blockly is actually perfect for this use case. It handles all the connection logic, validation, and visual feedback I was struggling to build, by actually making it look more like a Scratch project 🀣

Now workflows snap together like LEGO blocks. You can see the data flow, nest components properly, and it actually feels solid. Plus, Blockly is battle-tested by millions of students worldwide - if it can survive middle schoolers, it can handle my API workflows.

2. Added a Python runtime component (!)
This was the #1 request - "can I just write some Python for complex logic?"
So I spun up a shared Python runtime (sandboxed, don't worry) that you can drop into any workflow. It's literally a component called "Code" where you write Python, and it executes inline with your other components.
Example - I needed to calculate some custom metrics from API data:

import pandas as pd
import numpy as np

df = pd.DataFrame(responsedData)

df['Price'] = pd.to_numeric(df['Price'], errors='coerce')

if df['Price'].isna().any():
    print(f"Warning: {df['Price'].isna().sum()} price values could not be converted")
    df = df.dropna(subset=['Price'])  # Remove rows with invalid prices

summary_stats = {
    'total_records': len(df),
    'average_price': round(df['Price'].mean(), 2),
    'price_range': {
        'min': float(df['Price'].min()),
        'max': float(df['Price'].max())
    }
}

output_data = {
    'transformed_data': df.to_dict('records'),
    'summary': summary_stats,
    'columns': list(df.columns),
    'data_types': df.dtypes.astype(str).to_dict(),
}
Enter fullscreen mode Exit fullscreen mode

Just dropped this between my Fetch and Response components. No server setup, no Docker, no Lambda configs. Just... Python that runs.

Currently it's a shared instance (so be nice, don't mine Bitcoin πŸ˜„), but working on multiple runtimes. The tricky part is keeping it fast - nobody wants to wait 5 seconds for a cold start on their API.
Real use case from this week:
Client needed an API that:

  • Fetches data from their Shopify store
  • Runs some pandas transformations (inventory calculations)
  • Formats it for their warehouse system
  • Forward it to one or fan-out to multiple API endpoints

Instead of my usual "let me set up a FastAPI server" dance, I just:

  • Drag Request block β†’ Code block (30 lines of Python) β†’ Transform block
  • Deploy It was done in 15 minutes. I am not saying building your own API is a waste of time, but you need to do something more important for now.

The Python code handles all the weird business logic that would be painful to express in visual components. Best of both worlds - visual for the flow, code for the complexity.

What's next:

  • New Python environments (soonβ„’)
  • Packages support (so you're not limited to standard library)
  • Better error handling (currently it just... fails silently πŸ™ˆ)
  • Shareable workflow templates

Still learning as I go. The Blockly integration was humbling - spent days building a custom solution when a "kids' tool" was perfect all along. And the Python runtime? Total hack job with exec() and prayer, but it works!

And if anyone has experience with sandboxing Python execution at scale, please share your wisdom. I am sure someone will find a way to break out (and break my bank)
Keep shipping! πŸš€

P.S. - I do need to do something more important now.

Top comments (0)