Skip to content
This repository has been archived by the owner on Feb 14, 2023. It is now read-only.

[PROPOSAL] Make Backbone work in-code, not from an OpenAPI Spec #22

Open
mtwichel opened this issue Apr 8, 2022 · 0 comments
Open

[PROPOSAL] Make Backbone work in-code, not from an OpenAPI Spec #22

mtwichel opened this issue Apr 8, 2022 · 0 comments
Labels
feedback wanted Opinions on addressing is requested

Comments

@mtwichel
Copy link
Owner

mtwichel commented Apr 8, 2022

Hey everyone 👋 first off I want to share a thank you to everyone that has checked out the package and shown interest! We'll figure out Dart on the server best practices together! 💙

My Experience With Backbone

While the current iteration of backbone works, there are a few issues I've come across:

  1. Writing an Open API spec by hand in YAML isn't fun. There are extensions that can improve it, but it still isn't as easy as writing Dart code.
  2. When making the Open API spec, picking an HTTP verb, route, and where to put params (in the query, path, headers, or request body) all take mental energy that I don't want to think about. Almost every time I just want to write a Dart function that I can run on a server and call from the client and I don't care what happens in between.
  3. I personally don't like backbone is its own CLI. We all already have too many CLI commands to remember, backbone shouldn't be one of them.

My Proposal

I would like to change backbone so that instead of writing an Open API spec and generating code from there, you write the Dart backend code, and it generates the client code and an Open API spec (for documentation). The code you write would look something like this:

@CloudFunction()
Future<GetItemsResponse> getItems(GetItemsRequest request, RequestContext context) async {
  // connect to db and get the items
}

The RequestContext would still contain a logger, the raw shelf request, userId, and dependency caching that backbone currently has. The GetItemsResponse and GetItemsRequest objects would just be regular Dart objects that can be serialized (have a fromJson and toJson method)

You would then use the build_runner package to generate your code. (dart run build_runner build). It would generate a client library for calling your functions that would look something like this:

class ItemsRepository {
  final BackboneApi api;

  // ...

  Future<List<Items>> getItems(String group) async {
    try {
      final response = await api.getItems(
        GetItemsRequest(group: group),
      );
      return response.items;
    } on BadRequestException catch (e) {
      // handle issues with the request being bad
    } catch (e) {
      // handle other exceptions thrown by the backend function
    }
  }
}

Challenges to This Proposal

Objects Shared Between Frontend and Backend

Right now, backbone generates 3 packages:

  • backend
  • frontend
  • functions_objects (request and response objects shared between the frontend and backend)

However, if you're defining the shared objects by hand in Dart, then you would probably put them in your backend package. Thus, for the frontend to use them, it would have to depend on the backend in its pubspec, which I don't love. Of course you could put your functions objects in their own package when you write them, but I don't think backbone could enforce that.

Mason

Right now, backbone uses Mason internally to generate the source code. It seems natural to use the Mason CLI to build your code (ie mason make backbone), and I would love to make it that easy. However, that would be tough because the configuration is stored as plain Dart code. Anyone who has ideas/experience merging the build_runner package and mason together, please share!

RPC vs REST

This point gets a bit nerdy, so be prepared 🤓 😆

Background

Two of the bigger theories for designing a web API are Remote Procedure Call (RPC) and Representational State Transfer (REST). As I understand it, from a high level:

  • In RPC, the backend defines a set of functions the frontend can call much like an interface of a Dart package (for example, getItems). They need to be documented because you'll need to know what methods are available to you and how to use them. Also, each function is generally specific to a single-use case.
  • In REST, the backend defines paths to entities and uses HTTP verbs to define what actions can be taken (ie the path /items points to all the Items in the system. A POST call to /items would add a new item, whereas a 'GET' call to /items/3 would retrieve the item with id 3). In theory, they don't need to be documented because they follow standard HTTP protocols, and each route can be used for different use-cases because when you retrieve an entity, you get the entire thing.
  • Of course, there's also gRPC, which is a specific protocol that implements an RPC style API, GraphQL, which is a distinct style from the other two, and probably others as well. I'm just focusing on the two I think are most relevant to the conversation.

Here are some resources I've read/watched to better understand the topic:

The Issue

Right now, backbone uses an Open API spec, which doesn't dictate a style you should use to design your API; it simply allows all the HTTP protocols to be used. You as the developer gets to decide if you follow a REST or RPC pattern. With this change, backbone forces an RPC style API because it takes functions from the backend and exposes them to the frontend. You won't get any control over your routes or HTTP verbs or anything like that. Thus, I think it would be impossible to make REST APIs with backbone, only RPC style APIs.

Feedback Wanted

If you've made it this far, here are some questions I'd love opinions on:

  • Do you use backbone or similar tools and agree with the issues I have with them?
  • Do you think this proposal would solve them?
  • Are you worried about not using Mason?
  • Do you have an RPC vs REST take? Is losing the ability to make a REST API a worthy concern?
  • Any other thoughts on the proposal :)

Thank you again to the wonderful Dart community, and I look forward to your ideas 💡 💙 🚀

@mtwichel mtwichel self-assigned this Apr 8, 2022
@mtwichel mtwichel added the feedback wanted Opinions on addressing is requested label Apr 8, 2022
@mtwichel mtwichel removed their assignment Apr 8, 2022
@mtwichel mtwichel pinned this issue Apr 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feedback wanted Opinions on addressing is requested
Projects
None yet
Development

No branches or pull requests

1 participant