-
Notifications
You must be signed in to change notification settings - Fork 0
[WIP] New Telefunc guide #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,20 +4,21 @@ Remote functions, callable in the browser. | |
|
|
||
| - Telefunc is an RPC framework you can attach to your server. | ||
| - It enables full-stack teams to adopt development patterns that | ||
| - Improve application security and performance, | ||
| - And allow for rapid and flexible iteration. | ||
| - Telefunc makes it easy to add RPC to your server, but it's up to you to take advantage of the benefits RPC has to offer. | ||
| - Improve performance. | ||
| - Improve application security. | ||
| - Telefunc is easy to add RPC to your server — you can use Telefunc in parallel to your server. It's up to you how much RPC you want to use (you can progressively migrate back and forth between your server API endpoints and Telefunc). It's up to you to take advantage of the benefits RPC has to offer. | ||
|
|
||
| > A [remote procedure call](https://en.wikipedia.org/wiki/Remote_procedure_call) (RPC) is when a \[...] computer programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. | ||
|
|
||
| - RPC is a pattern for calling a remote function as if it were colocated with the client. No adapters or injection needed. | ||
| 1. Create named Telefunctions to call the database or do other backend work. | ||
| - RPC is a pattern for calling a remote function as if it were define in the client. Zero boilerplate. | ||
| 1. Create telefunctions (on the server) to call the database or do other backend work. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the parenthetical feels a little redundant. the context of this list is "a pattern for calling a remote fn", so to me it's clear that telefunctions are remote. if i'm wrong about the clarity, i'd suggest that's a more general issue, and that the outline needs to do a better job of explaining the control flow early-on.
but it could also be helpful to add a simple flow diagram. sequenceDiagram
Client->>Server: Request
Server-->>Telefunction: Telefunction args
Telefunction--)Server: Telefunction return
Server->>Client: Response
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Good point. I can see that I'm often too conservative in my writing (repeating myself too much). So far I think we don't need a diagram (for this). Although it could be nice to use diagrams for things that are hard to communicate succinctly. E.g. for the RPC vs REST/GraphQL page, a diagram could be very helpful. Or maybe https://telefunc.com/event-based could also benefit a diagram — not sure how the diagram would look like, but that could be very powerful. The mental model is quite important (a lot more important than the RPC vs REST/GraphQL page). |
||
| 2. Import and call the function from your frontend, passing any required arguments (e.g., `await onNewTodo(text)`). | ||
| 3. Telefunc creates a lightweight HTTP client to call your Telefunction, which returns only what the caller needs. | ||
|
|
||
| ::: info | ||
| - The term RPC is often used loosely to denote RPC-like approaches, like creating JSON endpoints. | ||
| - RPC-like describes an API that is schemaless — in contrast to RESTful and GraphQL APIs that always have a schema. | ||
| - RPC-like describes an API that is schemaless — in contrast to RESTful and GraphQL APIs which have a schema. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: i'm actually not sure which is correct. "that" vs "which" is a confusing english rule. as i understand it, it basically depends on whether the clause you're adding is required or supplemental "The cat, which is hungry, ran away from home"
"The scratch that the cat gave me stings"
the guide i use is basically "which" if i use a comma, otherwise "that", but it's imperfect. this case seems like a gray area to me, but i would lean towards "that", because "have a schema" is clarifying info, rather than definitional. either works though
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Didn't know that. My main motivation was to remove |
||
|
|
||
| ::: | ||
|
|
||
|
|
@@ -75,8 +76,8 @@ async function TodoList() { | |
| - You can think of RPC as a type-safe `fetch` call to a registered server-side function. | ||
|
|
||
| ## Securing resources | ||
| - Always keep in mind that your **telefuncs are public**. | ||
| - A simple HTTP request could be used to extract, modify, or destroy user secrets or business-critical data from an unprotected function. | ||
| - Always keep in mind that your **telefunctions are public**. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it might be good to more prominently introduce/define the term "telefunction" earlier in the docs |
||
| - A simple HTTP request could be used to extract, modify, or destroy user secrets or business-critical data from an unprotected telefunction. | ||
|
|
||
| - Add guards to Telefunctions to prevent illegitimate access. | ||
| - Use `throw Abort()` to exit early if the client is unauthenticated or doesn't have permission to access the requested resource | ||
|
|
@@ -85,7 +86,7 @@ async function TodoList() { | |
| - Use `shield()` to validate incoming requests. | ||
| - Don't forget to sanitize SQL arguments | ||
| - Allows argument types to be inferred. | ||
| - Telefunc generates a `shield` automatically from TypeScript types, if available. | ||
| - Telefunc generates a `shield` automatically from TypeScript types. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what was your motivation here? if i understand the docs correctly, a shield is only generated if you use typescript/add types to your telefunctions.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, |
||
|
|
||
| ```js | ||
| // When using TypeScript, Telefunc automatically generates | ||
|
|
@@ -144,14 +145,14 @@ export async function MarkAllComplete() { | |
| } | ||
| ``` | ||
|
|
||
| - To the consumer, these are all just functions, that do some async work. | ||
| - To the client, these are all just functions, that do some async work. | ||
| - RPC abstracts away the request management. | ||
| - This is nice, but the real value comes from the (framework-agnostic) colocation of browser and server code it enables. | ||
| - You can write a Telefunction for each view and interaction, just as if you were loading data from local storage, but with all the power of a remote server. | ||
|
|
||
| ### Design patterns | ||
| - RPC is a full-stack pattern, and projects that use a monorepo will get the most out of the acceleration it has to offer. | ||
| - It allows you to colocate (and codevelop) highly-tailored server functions with client code. | ||
| - It allows you to colocate (and co-develop) highly-tailored server functions with client code. | ||
|
|
||
| ```jsx | ||
| // /Todos.jsx | ||
|
|
@@ -164,8 +165,9 @@ import { | |
| } from './Todos.telefunc.js' | ||
|
|
||
| async function TodoList() { | ||
| // No need for an adapter, or "server only" flag | ||
| const todoItems = await onLoad() | ||
| // @ambergristle We'll implement useData() after we merged Dani's streaming PR | ||
| // No need for an adapter, or "server only" flag, works for both Client and Server components | ||
| const todoItems = await useData(() => onLoad()) | ||
|
|
||
| async function onClick(form) { | ||
| const text = form.input.value | ||
|
|
@@ -196,9 +198,12 @@ async function TodoList() { | |
| } | ||
| ``` | ||
|
|
||
| - The naming convention enforces coupling, which is a cornerstone of keeping RPC calls lithe (i.e., avoiding function scope creep). | ||
| - The naming convention enforces coupling, which is a cornerstone of keeping RPC calls slim (i.e., avoiding function scope creep). | ||
| - Opting out of the naming convention is perfectly fine, though we recommend having a clear reason for doing so. | ||
| > @ambergristle I didn't know the word "lithe" — I guess many non-native English speakers won't know it either | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good call-out! i studied literature for years, and still talk like an english professor sometimes. 😆 usually i catch stuff like that in review, but i appreciate the reminder to keep a global audience in mind! |
||
|
|
||
| - Accordingly, RPC versioning is typically equivalent to project versioning. You will need a custom solution if you choose to use RPC with a monorepo. | ||
| > @ambergristle The best pattern here is to always deploy the frontend and JS server at the same time. Versioning telefunctions are a pain (even more than versionin RESTFul/GraphQL APIs because telefunctions change a *lot* more change generic RESTful/GraphQL APIs) — it's a core Telefunc philosophy: you develop frontend hand-in-hand with telefunctions. The backend can be decoupled using a three party setup: static files (frontend) + JS server for SSR + telefunctions (frontend) + backend (Java/Ruby/...) — this setup is commonly called "BFF" (backend-for-frontend). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for the added detail! this was one of the weaker sections, and some of the detail about monorepos/project structure got lost in the shuffle.
i tried to emphasize this in the outline, but i think there's opportunity for improvement. it's a really important point to make, but also quite difficult to communicate. i'm still trying to figure out what helped me shift my mental model/understand it.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the best is to have a single repository that holds both the frontend and telefunctions. No monorepo. |
||
|
|
||
| ## Schema-less vs schema-full | ||
| - Comparing RPC to GraphQL or REST is a bit like comparing apples to oranges. They each make trade-offs to achieve different goals. | ||
|
|
@@ -215,12 +220,12 @@ async function TodoList() { | |
|
|
||
| ### Should I use it? | ||
| > Premature optimization is the root of all evil. | ||
| > - *Turing Award winner, Donal Knuth* | ||
| > - *Donal Knuth, Turing Award winner* | ||
|
|
||
| - In most cases you can start with RPC, and switch to REST or GraphQL as needed. | ||
| - RPC enables you to stay lean, iterating faster and pivoting more flexibly. | ||
| - Many apps will never need a public (or schema-full) API. | ||
| - RPC functions are just functions; migrating to REST or GraphQL is fairly straightforward. | ||
| - RPC functions are just functions; migrating to REST or GraphQL is straightforward. | ||
| - There's a simple litmus test for whether RPC is the right solution: | ||
| - If your goal is to enable third party developers to access your data, then you need a generic API and you'll have to use REST or GraphQL | ||
| - If your goal is to seamlessly add data and interactivity to a front-end, then RPC can improve DX and enable security and performance optimizations. | ||
| - If your goal is to seamlessly add data and interactivity to a front-end, then RPC improves DX and enable security and performance optimizations. | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed that there needs to be more emphasis on how easy it is to migrate to/from telefunc, but
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wanted to expand on this a bit
as i understand it, RPC's main value prop is the design pattern, which allows for
in my mind, these are two main values, from which all the rest follow. in the introduction, i think it's helpful to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 It all makes sense.
Nice idea 😍 How about:
Btw. I'd suggest we avoid the term "RPC" outside the
/RPCand/RPC-vs-GraphQL-RESTpages. Most users don't know what RPC means. If the user doesn't want to learn then it's better we don't confront him with the term "RPC".