Help us shape the future of Go! Take the 2026 Go Developer Survey

outbound

package
v0.10.1 Latest Latest
Warning

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

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

Documentation

Overview

Package outbound calls outside services. Client returns an *http.Client whose requests go to the runner, which sends each one only to a host that egress in the permission list names:

egress:
  - api.weather.example
  - {host: api.partner.example, secret: partner_api_key, header: Authorization, prefix: "Bearer "}

A host bound to a secret gets the secret's value, after the prefix, in the header of every request; the app never reads the key, and secrets.Get of it is E-RUN-015.

Rules:

  • Build each request with http.NewRequestWithContext and the context of the request or job it serves; a request without the app's context is E-RUN-004.
  • Only https to port 443 (E-OUT-002) of a host that egress lists (E-OUT-001). The platform's own hosts and private networks are never reachable (E-OUT-003).
  • A request body and a response body are at most 10 MiB each (E-OUT-004, E-OUT-005). The runner ends a request after 30 s with E-OUT-006; the client itself gives up 5 s later, only when the runner does not answer. An instance runs at most 16 requests at once (E-OUT-007).
  • Redirects are not followed: a 3xx response comes back with its Location.
  • Any other HTTP client, such as http.Get or an http.Client of the app's own, is E-LINT-009.

A refusal comes back as a coded error, which the response's error wraps. A new outside service is a change of the permission list, and a new key binding always needs approval.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Client

func Client() *http.Client

Client returns a client whose requests go to the runner, which sends them to the outside service. Each request must carry the context of the request or job it serves, as http.NewRequestWithContext gives it. The client follows no redirect: a 3xx response comes back with its Location. The runner ends a request after 30 s with E-OUT-006; the client gives up 5 s later, on a runner that does not answer.

Example

Call an outside service that egress in the permission list names, from a method of the app's Deps, with the context of the request or job the call serves. The example only compiles: it needs the runner of a running app.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"aicoded.dev/framework/outbound"
)

// Deps is what an app's pages share, as deps.Deps is in an app. It keeps the client in an
// unexported field: aicoded check refuses a value that holds a client in an exported field when
// it becomes an interface value, as each page's data provider does in the generated code
// (E-LINT-009).
type Deps struct {
	weather *http.Client
}

// New returns Deps with the client whose requests go through the runner.
func New() *Deps {
	return &Deps{weather: outbound.Client()}
}

// Today returns the weather service's summary of today in city. ctx is the context of the
// request or job it serves. The service's host, api.weather.example, is in egress in the
// permission list, and the runner adds the key that egress binds to it.
func (d *Deps) Today(ctx context.Context, city string) (string, error) {
	u := "https://api.weather.example/v1/today?city=" + url.QueryEscape(city)
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, http.NoBody)
	if err != nil {
		return "", err
	}
	resp, err := d.weather.Do(req)
	if err != nil {
		return "", err
	}
	defer func() { _ = resp.Body.Close() }()
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("the weather service answered %s", resp.Status)
	}
	var today struct{ Summary string }
	if err := json.NewDecoder(resp.Body).Decode(&today); err != nil {
		return "", err
	}
	return today.Summary, nil
}

// Call an outside service that egress in the permission list names, from a method of the app's
// Deps, with the context of the request or job the call serves. The example only compiles: it
// needs the runner of a running app.
func main() {
	_ = New().Today
}

Types

This section is empty.

Jump to

Keyboard shortcuts

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