or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

code-generation.mdindex.mdpresence.mdreal-time.mdsecurity.mdtesting.mdweb-foundation.md

web-foundation.mddocs/

0

# Web Foundation and Request Handling

1

2

Phoenix's web foundation provides the core infrastructure for handling HTTP requests, routing URLs to controllers, and generating responses. The system is built on a plug-based architecture that processes requests through configurable pipelines.

3

4

## Endpoint Configuration and Management

5

6

The endpoint is the entry point for all web requests and defines the foundational configuration.

7

8

### Phoenix.Endpoint

9

10

```elixir { .api }

11

defmodule Phoenix.Endpoint do

12

# Supervision and lifecycle

13

@callback start_link(keyword) :: Supervisor.on_start()

14

@callback config(atom, term) :: term

15

@callback config_change(term, term) :: term

16

17

# URL and path generation

18

@callback url() :: String.t()

19

@callback struct_url() :: URI.t()

20

@callback path(String.t()) :: String.t()

21

@callback static_url() :: String.t()

22

@callback static_path(String.t()) :: String.t()

23

@callback static_integrity(String.t()) :: String.t() | nil

24

@callback host() :: String.t()

25

@callback script_name() :: [String.t()]

26

27

# Server information

28

@callback server_info(Plug.Conn.scheme()) :: {:ok, {String.t(), pos_integer}} | :error

29

30

# PubSub integration

31

@callback subscribe(binary, keyword) :: :ok | {:error, term}

32

@callback unsubscribe(binary) :: :ok | {:error, term}

33

@callback broadcast(binary, binary, term) :: :ok | {:error, term}

34

@callback broadcast!(binary, binary, term) :: :ok

35

@callback broadcast_from(pid, binary, binary, term) :: :ok | {:error, term}

36

@callback broadcast_from!(pid, binary, binary, term) :: :ok

37

@callback local_broadcast(binary, binary, term) :: :ok

38

@callback local_broadcast_from(pid, binary, binary, term) :: :ok

39

end

40

```

41

42

### Usage Example

43

44

```elixir

45

defmodule MyAppWeb.Endpoint do

46

use Phoenix.Endpoint, otp_app: :my_app

47

48

# Static file serving

49

plug Plug.Static,

50

at: "/", from: :my_app, gzip: false,

51

only: ~w(assets fonts images favicon.ico robots.txt)

52

53

# Session configuration

54

plug Plug.Session,

55

store: :cookie,

56

key: "_my_app_key",

57

signing_salt: "signing_salt"

58

59

# Router

60

plug MyAppWeb.Router

61

end

62

63

# Start endpoint in application supervisor

64

children = [

65

MyAppWeb.Endpoint

66

]

67

68

Supervisor.start_link(children, strategy: :one_for_one)

69

```

70

71

## Routing System

72

73

Phoenix's router maps URLs to controller actions through a declarative DSL with support for pipelines, scoping, and resource routing.

74

75

### Phoenix.Router

76

77

```elixir { .api }

78

defmodule Phoenix.Router do

79

# HTTP verb macros

80

defmacro get(path, plug, plug_opts \\ [], options \\ [])

81

defmacro post(path, plug, plug_opts \\ [], options \\ [])

82

defmacro put(path, plug, plug_opts \\ [], options \\ [])

83

defmacro patch(path, plug, plug_opts \\ [], options \\ [])

84

defmacro delete(path, plug, plug_opts \\ [], options \\ [])

85

defmacro options(path, plug, plug_opts \\ [], options \\ [])

86

defmacro head(path, plug, plug_opts \\ [], options \\ [])

87

defmacro match(verb_or_verbs, path, plug, plug_opts \\ [], options \\ [])

88

89

# Resource routing

90

defmacro resources(path, controller, opts \\ [])

91

defmacro resources(path, controller, opts, do_block)

92

93

# Scoping and organization

94

defmacro scope(options \\ [], do: context)

95

defmacro scope(path, options \\ [], do: context)

96

defmacro scope(path, alias, options \\ [], do: context)

97

98

# Pipeline system

99

defmacro pipeline(name, do: block)

100

defmacro plug(plug, opts \\ [])

101

defmacro pipe_through(pipes)

102

103

# Forwarding

104

defmacro forward(path, plug, plug_opts \\ [], router_opts \\ [])

105

end

106

```

107

108

### Usage Examples

109

110

```elixir

111

defmodule MyAppWeb.Router do

112

use Phoenix.Router

113

114

# Define pipelines

115

pipeline :browser do

116

plug :accepts, ["html"]

117

plug :fetch_session

118

plug :fetch_live_flash

119

plug :put_root_layout, {MyAppWeb.LayoutView, :root}

120

plug :protect_from_forgery

121

plug :put_secure_browser_headers

122

end

123

124

pipeline :api do

125

plug :accepts, ["json"]

126

end

127

128

# Browser routes

129

scope "/", MyAppWeb do

130

pipe_through :browser

131

132

get "/", PageController, :index

133

resources "/users", UserController

134

resources "/posts", PostController, only: [:index, :show]

135

end

136

137

# API routes

138

scope "/api/v1", MyAppWeb do

139

pipe_through :api

140

141

resources "/users", UserController, except: [:new, :edit]

142

end

143

144

# Admin routes with scoping

145

scope "/admin", MyAppWeb.Admin, as: :admin do

146

pipe_through [:browser, :require_admin]

147

148

resources "/users", UserController

149

resources "/settings", SettingController

150

end

151

end

152

```

153

154

## Controller System

155

156

Controllers handle incoming requests, process parameters, interact with contexts, and render responses.

157

158

### Phoenix.Controller

159

160

```elixir { .api }

161

defmodule Phoenix.Controller do

162

# Request introspection

163

def action_name(Plug.Conn.t()) :: atom

164

def controller_module(Plug.Conn.t()) :: atom

165

def router_module(Plug.Conn.t()) :: atom

166

def endpoint_module(Plug.Conn.t()) :: atom

167

168

# Response rendering

169

def render(Plug.Conn.t(), binary | keyword) :: Plug.Conn.t()

170

def render(Plug.Conn.t(), binary, keyword) :: Plug.Conn.t()

171

def render(Plug.Conn.t(), atom, binary, keyword) :: Plug.Conn.t()

172

173

# Format-specific responses

174

def json(Plug.Conn.t(), term) :: Plug.Conn.t()

175

def text(Plug.Conn.t(), iodata) :: Plug.Conn.t()

176

def html(Plug.Conn.t(), iodata) :: Plug.Conn.t()

177

def redirect(Plug.Conn.t(), keyword) :: Plug.Conn.t()

178

179

# View and layout management

180

def put_view(Plug.Conn.t(), atom | keyword) :: Plug.Conn.t()

181

def put_new_view(Plug.Conn.t(), atom | keyword) :: Plug.Conn.t()

182

def view_module(Plug.Conn.t(), atom | nil) :: atom | nil

183

def put_layout(Plug.Conn.t(), binary | false | {atom, binary}) :: Plug.Conn.t()

184

def put_new_layout(Plug.Conn.t(), binary | false | {atom, binary}) :: Plug.Conn.t()

185

def put_root_layout(Plug.Conn.t(), binary | false | {atom, binary}) :: Plug.Conn.t()

186

def layout(Plug.Conn.t(), atom | nil) :: binary | false | {atom, binary} | nil

187

def root_layout(Plug.Conn.t(), atom | nil) :: binary | false | {atom, binary} | nil

188

189

# URL helpers

190

def put_router_url(Plug.Conn.t(), binary) :: Plug.Conn.t()

191

def put_static_url(Plug.Conn.t(), binary) :: Plug.Conn.t()

192

def current_path(Plug.Conn.t()) :: binary

193

def current_path(Plug.Conn.t(), map | keyword) :: binary

194

def current_url(Plug.Conn.t()) :: binary

195

196

# Content negotiation

197

def accepts(Plug.Conn.t(), [binary]) :: Plug.Conn.t()

198

def put_format(Plug.Conn.t(), atom) :: Plug.Conn.t()

199

def get_format(Plug.Conn.t()) :: atom

200

201

# Security

202

def protect_from_forgery(Plug.Conn.t(), keyword) :: Plug.Conn.t()

203

def put_secure_browser_headers(Plug.Conn.t(), map) :: Plug.Conn.t()

204

def scrub_params(Plug.Conn.t(), binary) :: Plug.Conn.t()

205

206

# Flash messages

207

def fetch_flash(Plug.Conn.t(), keyword) :: Plug.Conn.t()

208

def put_flash(Plug.Conn.t(), atom | binary, term) :: Plug.Conn.t()

209

def get_flash(Plug.Conn.t()) :: map

210

def get_flash(Plug.Conn.t(), atom | binary) :: term

211

def clear_flash(Plug.Conn.t()) :: Plug.Conn.t()

212

def merge_flash(Plug.Conn.t(), Enumerable.t()) :: Plug.Conn.t()

213

214

# File downloads

215

def send_download(Plug.Conn.t(), atom, keyword) :: Plug.Conn.t()

216

217

# JSONP support

218

def allow_jsonp(Plug.Conn.t(), keyword) :: Plug.Conn.t()

219

end

220

```

221

222

### Usage Examples

223

224

```elixir

225

defmodule MyAppWeb.UserController do

226

use Phoenix.Controller, formats: [:html, :json]

227

228

def index(conn, _params) do

229

users = MyApp.Accounts.list_users()

230

render(conn, "index.html", users: users)

231

end

232

233

def show(conn, %{"id" => id}) do

234

case MyApp.Accounts.get_user(id) do

235

nil ->

236

conn

237

|> put_flash(:error, "User not found")

238

|> redirect(to: "/users")

239

240

user ->

241

case get_format(conn) do

242

"html" -> render(conn, "show.html", user: user)

243

"json" -> json(conn, %{user: user})

244

end

245

end

246

end

247

248

def create(conn, %{"user" => user_params}) do

249

case MyApp.Accounts.create_user(user_params) do

250

{:ok, user} ->

251

conn

252

|> put_flash(:info, "User created successfully")

253

|> redirect(to: "/users/#{user.id}")

254

255

{:error, changeset} ->

256

render(conn, "new.html", changeset: changeset)

257

end

258

end

259

260

def delete(conn, %{"id" => id}) do

261

user = MyApp.Accounts.get_user!(id)

262

{:ok, _user} = MyApp.Accounts.delete_user(user)

263

264

conn

265

|> put_flash(:info, "User deleted successfully")

266

|> redirect(to: "/users")

267

end

268

end

269

```

270

271

## Verified Routes

272

273

Phoenix provides compile-time route verification using the `~p` sigil.

274

275

### Phoenix.VerifiedRoutes

276

277

```elixir { .api }

278

defmodule Phoenix.VerifiedRoutes do

279

defmacro sigil_p(path, modifiers)

280

281

def path(Plug.Conn.t() | Phoenix.Socket.t(), binary) :: binary

282

def url(Plug.Conn.t() | Phoenix.Socket.t(), binary) :: binary

283

end

284

```

285

286

### Usage Examples

287

288

```elixir

289

# In controllers, views, templates

290

def show(conn, %{"id" => id}) do

291

user = MyApp.Accounts.get_user!(id)

292

redirect(conn, to: ~p"/users/#{user}")

293

end

294

295

# In templates

296

<%= link "View User", to: ~p"/users/#{@user}" %>

297

<%= link "Edit", to: ~p"/users/#{@user}/edit" %>

298

299

# With query parameters

300

~p"/search?#{[q: @query, page: @page]}"

301

302

# Static paths (verified at compile time)

303

~p"/assets/app.css"

304

```

305

306

## Configuration Options

307

308

### Endpoint Configuration

309

310

```elixir

311

# config/config.exs

312

config :my_app, MyAppWeb.Endpoint,

313

url: [host: "localhost"],

314

secret_key_base: "your_secret_key_base",

315

render_errors: [view: MyAppWeb.ErrorView, accepts: ~w(html json), layout: false],

316

pubsub_server: MyApp.PubSub,

317

live_view: [signing_salt: "your_signing_salt"],

318

server: true

319

```

320

321

### Router Configuration

322

323

```elixir

324

# Enable helpers in controllers and views

325

use Phoenix.Router, helpers: false # Disable route helpers

326

327

# Custom pipeline plugs

328

pipeline :auth do

329

plug MyAppWeb.Plugs.RequireAuth

330

plug MyAppWeb.Plugs.LoadCurrentUser

331

end

332

```

333

334

## Error Handling

335

336

```elixir

337

# Custom errors

338

defmodule Phoenix.Router.NoRouteError do

339

@moduledoc "Exception raised when no route is found"

340

defexception [:conn, :router]

341

end

342

343

defmodule Phoenix.MissingRequiredKeys do

344

@moduledoc "Exception raised when required configuration is missing"

345

defexception [:keys]

346

end

347

348

# In controllers

349

def show(conn, %{"id" => id}) do

350

case MyApp.Accounts.get_user(id) do

351

nil ->

352

raise Phoenix.Router.NoRouteError, conn: conn, router: __MODULE__

353

user ->

354

render(conn, "show.html", user: user)

355

end

356

end

357

```