rpc

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package rpc lets one app call functions of another. The called app declares them in its own rpc/ folder, package rpc, as plain Go functions with an //ssr:access line:

// Contacts returns the phones and email addresses of a user.
//
//ssr:access caller=people role=staff
func Contacts(ctx context.Context, in ContactsIn) (ContactsOut, error)

caller= names the apps that may call the function. role= is the rule for calls made on a viewer's behalf: roles joined by |, or * for every viewer. apps=true lets the listed apps call with no viewer. Inside rpc/, import this package under another name, such as frameworkrpc.

aicoded generate writes the server, rpc/server_gen.go, whose rpc.Server() main passes to app.Main as RPC, and the snapshot .aicoded/rpc.json. In the calling app, aicoded rpc add <app> copies the snapshot and generates a typed client in services/<app>/. Call it with the context of the request being served, so that the call goes on behalf of its viewer. The runner and the called app both check every call against the permission lists of the two apps.

A function tells its caller why it failed with Error or Errorf and one of six codes: InvalidArgument, NotFound, AlreadyExists, PermissionDenied, FailedPrecondition and Unavailable. The caller reads the code with CodeOf. Any other error, and a panic, reach the caller as Internal with the message "internal error", so the called app's details stay in its own logs. A function that returns a viewer's records checks ownership itself, with auth.Viewer(ctx): the calling app's checks are not its own.

Read more in the guide docs/guides/calls-between-apps.md and the task docs/tasks/call-another-app.md, which aicoded explain and the MCP tool howto print as guides/calls-between-apps and tasks/call-another-app.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Call

func Call(ctx context.Context, app, method string, in []byte) ([]byte, error)

Call calls method of app with the encoded input in and returns the encoded output. The generated client functions call it; app code calls those instead. The call goes as the viewer of the request ctx belongs to, or as this app when ctx has no viewer. A call whose context has no deadline gets runnerproto.DefaultCallDeadline; the runner cuts any call at runnerproto.MaxCallDeadline.

A failed call returns an error whose message is the callee's or the runner's. Only a refusal the runner marks with runnerproto.OriginHeader reaches the caller as a coded error, whose text starts with the code and carries its fix line; a called app's own refusal reaches the caller as plain text, whatever it looks like. CodeOf reads the status of every error, and errors.Is matches context.Canceled or context.DeadlineExceeded when the call's context ended first.

Generated code only.

func Caller

func Caller(ctx context.Context) string

Caller returns the app whose call ctx serves, or "" outside a call.

func DecodeError

func DecodeError(err error) error

DecodeError marks err as a failure to decode a call's input. Generated code uses it; the caller gets InvalidArgument.

Generated code only.

func Error

func Error(code Code, msg string) error

Error returns an error that reaches the caller with code and msg. A code other than InvalidArgument, NotFound, AlreadyExists, PermissionDenied, FailedPrecondition or Unavailable reaches the caller as Internal with the message "internal error", like any other error.

Example

A function of an app's rpc/ package tells its caller why it failed with one of six codes. Any other error reaches the caller as Internal, with the message "internal error".

package main

import (
	"errors"
	"fmt"

	"aicoded.dev/framework/rpc"
)

func main() {
	err := rpc.Errorf(rpc.NotFound, "no user %q", "zoe")
	fmt.Println(rpc.CodeOf(err), err)
	fmt.Println(rpc.CodeOf(errors.New("database is locked")))
}
Output:
not_found no user "zoe"
internal

func Errorf

func Errorf(code Code, format string, args ...any) error

Errorf is Error with a formatted message.

Types

type Code

type Code int

Code is the status of a failed call.

const (
	InvalidArgument Code = iota + 1
	NotFound
	AlreadyExists
	PermissionDenied
	FailedPrecondition
	Unavailable
	Internal
)

The codes a function may return with Error. Internal is what the caller sees for any other error.

func CodeOf

func CodeOf(err error) Code

CodeOf returns the code of err: 0 for nil, the code of an error from Error, Errorf or a call, and Internal for any other error.

Example

The calling page turns the codes it expects into answers for the viewer, and fails on any other error.

package main

import (
	"fmt"

	"aicoded.dev/framework/rpc"
	"aicoded.dev/framework/web"
)

func main() {
	answer := func(err error) error {
		switch rpc.CodeOf(err) {
		case 0:
			return nil
		case rpc.PermissionDenied:
			return web.Forbidden()
		case rpc.NotFound:
			return web.NotFound()
		default:
			return err
		}
	}
	fmt.Println(answer(rpc.Error(rpc.PermissionDenied, "not your contacts")))
	fmt.Println(answer(rpc.Error(rpc.NotFound, "no such user")))
}
Output:
403 You do not have access to this page.
404 This page does not exist.

func (Code) String

func (c Code) String() string

type Method

type Method struct {
	Name string
	// Callers are the apps that may call the function.
	Callers []string
	// Require holds the rules a viewer must meet, each roles joined by "|", or "*" for any
	// viewer. With no rules, no viewer may call the function.
	Require []string
	// Apps allows calls an app makes as itself, with no viewer.
	Apps bool
	// Call decodes the input, runs the function and encodes its output.
	Call func(ctx context.Context, in []byte) ([]byte, error)
}

Method is one function an app serves, as the generated table describes it.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server serves an app's functions to the runner.

func NewServer

func NewServer(methods ...Method) *Server

NewServer returns a server for methods. aicoded generate writes the call of it, in the app's rpc.Server function.

Generated code only.

func (*Server) Handler

func (s *Server) Handler() (path string, h http.Handler)

Handler returns the path the runner sends calls to and the handler to serve there.

Directories

Path Synopsis
Package wire encodes and decodes the protobuf wire format for the code aicoded generate writes for calls between apps.
Package wire encodes and decodes the protobuf wire format for the code aicoded generate writes for calls between apps.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL