Skip to content

onelson/e2e-rs

Repository files navigation

This project is not arranged in the usual fashion you might manage a software project. There are several branches, some built on top of others, but they are not meant to be viewed in terms of their history per se. It may be interesting to look at them as total diffs via a "compare" view, but the lineage of each branch isn't that important.

Each of the branches named here represents a different approach, tech-wise, to solve the problem keeping server and client applications aligned via type-safety enforced by rust and typescript.

In order of implementation, we've got:

  1. wasm-bindgen branch - uses wasm-bindgen to export an HTTP client package. Alignment is maintained by using rust itself to write the HTTP client, mostly.
  2. master branch - aka "wasm removal" dumps wasm-bindgen, but uses the typescript-definitions crate to export types used in a hand-written Typescript HTTP client package. This is the version with the most manual upkeep required.
  3. graphql branch - uses juniper for the server, and apollo on the client. Both server and client use codegen based on a common schema to enforce alignment.
  4. grpc branch - a similar approach to the graphql branch. Codegen is used on a common .proto file to produce code for a tonic server and grpc-web client.

The work in this branch was carried forward from wasm-bindgen branch.

In this iteration, the broad strokes are much the same, however we shed the adoption of wasm-bindgen, instead using a small binary crate to dump out typescript definitions in a mostly handwritten HTTP client.

The sections of this document to follow have been updated to account for the changes, but many of the items that have been removed/simplified will be shown with a strikethrough treatment, or pulled out and noted specifically.

Aims

When building http server and client apis it can sometimes be a challenge to keep request and response payload shapes aligned.

This project aims to explore options to build both client and server with a shared collection of types. It is my hope that we'll be able to publish client libraries to match servers in lock-step by having a mutual dependency on a rust crate which contains all the "shapes" that can be seen from each side.

The high-level goal here is to:

  • build a json-based web api server.
  • build a client to match.
  • import and use the client from a react app.
  • if possible, export Typescript info with the client.
  • static analysis (the rust type system) to enforce all projects are aligned at any given time.

Part of the idea here is that adding or removing endpoints in a web api happen more infrequently (in my experience) than changes to the shapes of the payloads.

With this in mind, having to write client calls manually isn't that big of a deal. Having some type checking on both ends for the shapes of the payloads is of higher value, and potentially easier to achieve with less "magic" involved.

The Moving Parts

There's some complexity in how this all fits together so here's the gist.

In the top level of the repo, there are 4 distinct sections:

  • e2e-core (rust): common types shared between client and server
  • e2e-server (rust): an actix-web api server
  • e2e-client (rust, js, Typescript): A higher-level js http client, written in Typescript wrapping the wasm module from e2e-client-wasm. Now, a handwritten HTTP client in Typescript, bundling typescript defs generated by a small binary cargo project.
  • web-frontend (js): this is a create-react-app project with some tweaks to add wasm support. This project depends on both the e2e-client-wasm and e2e-client.

The notable omission here is the e2e-client-wasm package, which means we no longer need the nightly rust toolchain for anything and have one fewer package to juggle.

It also means we don't have any weird peerDependency relationship between npm packages, no longer need rewire to add custom loaders to our webpack project AND don't have any weird async module imports to deal with.

Tools and Building

This section describes the various tools you'd need to be able to build and run this project.

Once you've got all this stuff installed, you should be able to run the following:

$ cargo build -p e2e-server
$ cd e2e-client
$ npm i
$ npm run build
$ cd ../web-frontend
$ npm i

Ordering is important here in so much as web-frontend won't be able to install e2e-client unless it has already been built.

At this point you should be able to run the project.

In one shell, from the project root directory, run

$ cargo run -p e2e-server

and in another, from the web-frontend directory, run

$ npm run start

Developer Notes

This section describes what was done to put all the pieces together, more or less discussing just the happy path used to bootstrap the project from the ground up.

The e2e-core and e2e-server crates are not really that notable. They are written plainly as any other conventional rust crates are, and so we'll move directly on to the other sections of the project.

e2e-client

In the wasm-bindgen branch, this package was largely just a wrapper around our wasm module (which was provided by another package for a long list of annoying reasons).

In this version, we've got a small cargo project in there which we call from a script entry point defined in the package.json. If you npm run dump it will produce a _structs.ts in the root of the package. This uses the same underlying typescript generation code we got with the wasm-bingen output previously, but it means we need to maintain this list of types to dump (in the main.rs).

The dump is automatically run as a part of npm run build.

Other than the above, this is a plain Typescript project that uses fetch to make requests to the backend. Nothing weird or annoying about it.

web-frontend

In the wasm-bindgen branch this project was bootstrapped with Create React App, and then we had to customize it with something called rewire to inject new loaders into the webpack config.

Since this version doesn't rely on wasm, we don't need to do any of that. This time, we only use a plain CRA typescript setup.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published