OpenMetadata/FLUENT_API_COMPARISON.md
Sriharsha Chintalapani bb1395fc72
Implement Modern Fluent API Pattern for OpenMetadata Java Client (#23239)
* Implement Modern Fluent API Pattern for OpenMetadata Java Client

* Add Lineage, Bulk, Search static methods

* Add all API support for Java & Python SDKs

* Add Python SDKs and mock tests

* Add Fluent APIs for sdks

* Add Fluent APIs for sdks

* Add Fluent APIs for sdks, support async import/export

* Remove unnecessary scripts

* fix py checkstyle

* fix tests with new plural form sdks

* Fix tests

* remove examples from python sdk

* remove examples from python sdk

* Fix type check

* Fix pyformat check

* Fix pyformat check

* fix python integration tests

* fix pycheck and pytests

* fix search api pycheck

* fix pycheck

* fix pycheck

* fix pycheck

* Fix test_sdk_integration

* Improvements to SDK

* Remove SDK coverage for Python 3.9

* Remove SDK coverage for Python 3.9

* Remove SDK coverage for Python 3.9
2025-09-29 16:07:02 -07:00

4.1 KiB

Pure Fluent API vs Previous Approach

Key Differences

1. Creation

Previous Approach (Request Objects):

CreateTable request = new CreateTable();
request.setName("customers");
request.setDatabaseSchema("mysql.sales.public");
Table table = Tables.create(request);

Pure Fluent API:

Table table = Tables.create()
    .name("customers")
    .in("mysql.sales.public")
    .withColumn("id", BIGINT).asPrimaryKey()
    .withColumn("email", VARCHAR(255)).asUnique()
    .execute();

2. Retrieval

Previous Approach (Request Objects):

RetrieveRequest<Table> request = Tables.retrieve(id);
Table table = request.include("owner", "tags").fetch();

Pure Fluent API:

Table table = Tables.find(id)
    .includeOwner()
    .includeTags()
    .fetch();

3. Update

Previous Approach (Request Objects):

UpdateRequest<Table> request = Tables.update(id);
Table updated = request.set(modifiedTable).execute();

Pure Fluent API:

Table updated = Tables.find(id)
    .fetch()
    .withDescription("New description")
    .addTag("PII")
    .save();

4. Delete

Previous Approach (Request Objects):

DeleteRequest<Table> request = Tables.delete(id);
request.recursive().hardDelete().execute();

Pure Fluent API:

Tables.find(id)
    .delete()
    .recursively()
    .permanently()
    .confirm();

5. Listing

Previous Approach (Request Objects):

ListRequest<Table> request = Tables.list();
var response = request.filter("database", "sales").limit(50).fetch();

Pure Fluent API:

Tables.list()
    .from("mysql.sales")
    .withTag("PII")
    .limit(50)
    .forEach(table -> process(table));

Benefits of Pure Fluent API

1. Natural Language Flow

The API reads like English sentences:

  • "Create a table named customers in sales database"
  • "Find table by id and delete it recursively"
  • "List tables from sales with PII tag"

2. No Intermediate Objects

No need to understand request/response objects. Direct method chaining.

3. Entity-Centric Operations

Work directly with entities:

table.withDescription("New")
     .addTag("PII")
     .save();

4. Contextual Methods

Methods make sense in context:

  • delete().recursively().permanently()
  • create().withColumn().asPrimaryKey()

5. Type Safety

Still maintains full type safety with proper return types.

6. Discoverable

IDE autocomplete naturally guides you through the available operations.

Entity-Specific Operations

The pure fluent API also supports entity-specific operations:

// Table-specific
table.addColumn("new_col", "VARCHAR(100)")
     .dropColumn("old_col")
     .updateProfilerConfig(config)
     .save();

// User-specific
user.joinTeam("engineering")
    .assignRole("DataSteward")
    .save();

// Dashboard-specific
dashboard.addChart("chart-id")
         .removeChart("old-chart")
         .updateLayout(layout)
         .save();

Migration Guide

For Developers

  1. Replace static methods with fluent chains:

    • Tables.retrieve(id)Tables.find(id).fetch()
    • Tables.delete(id)Tables.find(id).delete().confirm()
  2. Use natural method names:

    • recursive()recursively()
    • hardDelete()permanently()
    • execute()confirm() for deletes
  3. Entity operations:

    • Get entity first: var table = Tables.find(id).fetch()
    • Then operate: table.addTag("PII").save()

For Test Writers

Tests become more readable:

// Old
when(mockService.create(any(CreateTable.class))).thenReturn(table);

// New - same mock, but usage is cleaner
Table table = Tables.create()
    .name("test")
    .in("service.db.schema")
    .execute();

Summary

The pure fluent API provides:

  • Natural language-like syntax
  • No intermediate request/response objects
  • Entity-centric operations
  • Contextual method names
  • Better discoverability
  • Cleaner, more readable code
  • Maintains type safety
  • Supports bulk operations
  • Extensible for entity-specific features