breadboard-ai / breadboard

A library for prototyping generative AI applications.
Apache License 2.0
164 stars 22 forks source link

[board-server] Refactor board-server to use express #3172

Open wfaithfull opened 3 days ago

wfaithfull commented 3 days ago

The current node:http based request parser pattern that the board server uses has some disadvantages.

I'm proposing that we reorganise the board server request handling code into straightforward handler-per-route style so that we can automatically generate the openapi spec from these and so that the request handling code is a bit more approachable for the uninitiated. I'd like run the board server on express so that we can take advantage of the routing layer semantics e.g.

app.get('/', (req, res) => {
  res.send('Hello World!')
})

This would let us organise each route with a function and integrate automatic generation of the openapi spec. Express, as far as I know, is just about the lightest HTTP server after node:http.

The 1000ft view

I want to drastically decrease the friction to get folks deploying their own board servers and integrating them into their applications. Therefore;

Therefore;

Therefore;

Therefore;

wfaithfull commented 3 days ago

@dglazkov would like to hear your thoughts on this

dglazkov commented 2 days ago

Can you help me understand why we want the SDK for the board server API? Most of it (aside from the /boards endpoint) is more like internal guts that shouldn't be super-interesting and is still in flux.

dglazkov commented 2 days ago

Overall, the idea of refactoring the routing to use something more robust SGTM.

dglazkov commented 2 days ago

@timswanson-google would love your thoughts, too

wfaithfull commented 1 day ago

Most of it (aside from the /boards endpoint) is more like internal guts that shouldn't be super-interesting and is still in flux.

I think this is great point, actually. What I really want to wrap up in a client SDK is primarily the complexity of the run API, along with a few other bits to make it really easy to invoke and run boards remotely. I currently have all this plumbing in the integration tests to call the run api - adapted from your code for testing it locally. I'd like to box this up into something that is very slick to bring into your own server-side application and start running boards.

const scriptedRun = async (
  boardName: string,
  script: { inputs?: Record<string, any>; expected: ExpectedResult[] }[],
  apiKey: string
) => {
  let next;
  for (const [index, { inputs, expected }] of script.entries()) {
    const inputData = {
      ...inputs,
      $key: apiKey,
      ...(next ? { $next: next } : {}),
    };

    const { statusCode, data: body } = await makeRequest({
      path: `/boards/@${account.account}/${boardName}.api/run`,
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: inputData,
    });

    assert.strictEqual(statusCode, 200);

    const events = body
      .split("\n\n")
      .filter(Boolean)
      .map((event) => {
        const jsonStr = event.replace("data: ", "");
        return JSON.parse(jsonStr);
      });

    assertResults(events, expected, index);
    next = getNext(events[events.length - 1]);
  }
};
timswanson-google commented 1 day ago

Disclaimer: this is a very uninformed opinion. I've never done any real JS server work

I think we should do this. I've also found the server code hard to parse.

When I first looked at the server code for Board Server, I found it a bit hard to read, but I feel like that's mostly because I was used to "path-first" server frameworks that use things like annotations or decorators to define routes (e.g. Bottle for Python, or net/http for Go 1.22+).

Express roughly follows this same pattern.

https://expressjs.com/en/starter/hello-world.html

So using Express for routing would have some benefits right away as far as cleaning up of the code. We could also replace some of our manual "middleware" layers for things like CORS with the Express counterparts that do the same thing.

https://expressjs.com/id/resources/middleware/cors.html

timswanson-google commented 1 day ago

Can you help me understand why we want the SDK for the board server API? Most of it (aside from the /boards endpoint) is more like internal guts that shouldn't be super-interesting and is still in flux.

I don't feel like this is a reason not to use a server framework. Ultimately, having something that's easy to understand and change is valuable especially for something that's in flux. And the code will always be interesting to someone who's trying to change it.

dglazkov commented 1 day ago

SGTM.

wfaithfull commented 1 day ago

Disclaimer: this is a very uninformed opinion. I've never done any real JS server work

I think we should do this. I've also found the server code hard to parse.

When I first looked at the server code for Board Server, I found it a bit hard to read, but I feel like that's mostly because I was used to "path-first" server frameworks that use things like annotations or decorators to define routes (e.g. Bottle for Python, or net/http for Go 1.22+).

Express roughly follows this same pattern.

https://expressjs.com/en/starter/hello-world.html

So using Express for routing would have some benefits right away as far as cleaning up of the code. We could also replace some of our manual "middleware" layers for things like CORS with the Express counterparts that do the same thing.

https://expressjs.com/id/resources/middleware/cors.html

I agree with this @timswanson-google. The thing that gets me is that currently we have leaky abstraction layers in the code. We are passing requests all the way down the call stack and responses all the way back up. There are examples at the moment where we are doing authentication-y bits as deep down as the database I/O code, which I think isn't a great separation of concerns - ideally we do auth in a filter-style pattern for example.

I think express is quite a light touch framework to manage the plumbing of our separation of concerns in this manner, and it should make the request handling code a lot cleaner and more approachable.

wfaithfull commented 1 day ago

@bertiespell and I tentatively started on this yesterday as a bit of a pathfinder to feel out how hard it's going to be. It feels achievable but it is definitely a substantial undertaking that may be better approached in backwards compatible stages given the pace of change.