You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Every Functions app is executed by a language-specific handler. While Azure Functions supports many [language handlers](./supported-languages.md) by default, there are cases where you may want additional control over the app execution environment. Custom handlers give you this additional control.
13
13
14
-
Custom handlers are lightweight HTTP servers that receive events from the Functions host. Any language that supports HTTP primitives can implement a custom handler.
14
+
Custom handlers are lightweight web servers that receive events from the Functions host. Any language that supports HTTP primitives can implement a custom handler.
15
15
16
16
Custom handlers are best suited for situations where you want to:
17
17
18
18
- Implement a Functions app in a language beyond the officially supported languages
19
-
- Implement a Functions app in a language version not supported by default
19
+
- Implement a Functions app in a language version or runtime not supported by default
20
20
- Have granular control over the app execution environment
21
21
22
-
With custom handlers, all [triggers and input and output bindings](./functions-triggers-bindings.md) are supported.
22
+
With custom handlers, all [triggers and input and output bindings](./functions-triggers-bindings.md) are supported via [extension bundles](./functions-bindings-register.md).
23
+
24
+
## Overview
25
+
26
+
The following diagram depicts the relationship between the Functions host and a web server implemented as a custom handler.
- Events trigger a request sent to the Functions host. The event carries either a raw HTTP payload (for HTTP-triggered functions), or a payload that holds the input binding data for the function.
31
+
- The Functions host then proxies the request to the web server by issuing a [request payload](#request-payload).
32
+
- The web server executes the individual function, and returns a [response payload](#response-payload) to the Functions host.
33
+
- The Functions host proxies the response as an output binding payload to the target.
34
+
35
+
An Azure Functions app implemented as a custom handler must configure the *host.json* and *function.json* files according a few conventions.
23
36
24
37
## Application structure
25
38
26
-
To implement a custom handler, you need the following files:
39
+
To implement a custom handler, you need the following aspects in your application:
27
40
28
41
- A *host.json* file at the root of your app
42
+
- A *function.json* file for each function (inside a folder that matches the function name)
29
43
- A command, script, or executable which runs a web server
30
-
- A *function.json* file for each function
31
44
32
45
The following diagram shows how these files look on the file system for a function named "order".
33
46
@@ -38,67 +51,129 @@ The following diagram shows how these files look on the file system for a functi
38
51
| host.json
39
52
```
40
53
41
-
### App configuration
54
+
### Configuration
55
+
56
+
The application is configured via the *host.json* file. This file tells the Functions host where to send requests by pointing to a web server capable of processing HTTP events.
57
+
58
+
A custom handler is defined by configuring the *host.json* file with details on how to run the web server via the `httpWorker` section.
59
+
60
+
```json
61
+
{
62
+
"version": "2.0",
63
+
"httpWorker": {
64
+
"description": {
65
+
"defaultExecutablePath": "server.exe"
66
+
}
67
+
}
68
+
}
69
+
```
70
+
The `httpWorker` section points to a target as defined by the `defaultExecutablePath`. The execution target may either be a command, executable or file where the web server is implemented.
71
+
72
+
For scripted apps, `defaultExecutablePath` points to the script language's runtime and `defaultWorkerPath` points to the script file location. The following example shows how a JavaScript app in Node.js is configured as a custom handler.
73
+
74
+
```json
75
+
{
76
+
"version": "2.0",
77
+
"httpWorker": {
78
+
"description": {
79
+
"defaultExecutablePath": "node",
80
+
"defaultWorkerPath": "server.js"
81
+
}
82
+
}
83
+
}
84
+
```
85
+
86
+
You can also pass arguments using the `arguments` array:
87
+
88
+
```json
89
+
{
90
+
"version": "2.0",
91
+
"httpWorker": {
92
+
"description": {
93
+
"defaultExecutablePath": "node",
94
+
"defaultWorkerPath": "server.js",
95
+
"arguments": [ "--argument1", "--argument2" ]
96
+
}
97
+
}
98
+
}
99
+
```
100
+
101
+
Arguments are necessary for many debugging setups. See the [Debugging](#debugging) section for more detail.
102
+
103
+
> [!NOTE]
104
+
> The *host.json* file must be at the same level in the directory structure as the running web server. Some languages and toolchains may not place the this file at the application root by default.
42
105
43
-
The application is configured via the *host.json* file. This file tells the Functions host where to send requests by pointing to an executable that implements a server capable of processing HTTP events.
106
+
#### Bindings support
44
107
45
-
Ensure the *host.json* file is at the same level in the directory structure as the running web server. Some languages and toolchains may not place the this file at the application root by default.
108
+
Standard triggers along with input and output bindings are available by referencing [extension bundles](./functions-bindings-register.md) in your *host.json*file.
46
109
47
110
### Function metadata
48
111
49
-
By convention, each function must have a folder named to match the function name, containing a *function.json* file.
112
+
When used with a custom handler, the *function.json* contents are no different from how you would define a function under any other context. The only requirement is that *function.json* files must be in a folder named to match the function name.
113
+
114
+
### Request payload
115
+
116
+
todo
50
117
51
118
### Response payload
52
119
53
120
By convention, function responses are formatted as key/value pairs. Supported keys include:
|`Outputs`|key/value pair| Holds response values as defined by the `bindings` array the *function.json* file.<br /><br />For instance, if a function is configured with a blob storage output binding named "blob", then `Outputs` contains a key named `blob`, which is set to the blob's value. |
58
-
|`Logs`| array | Messages appear in the Functions invocation logs.<br /><br />When running in Azure, logged messaged appear in Application Insights. |
59
-
|`ReturnValue`| string | Used to provide a response when an output is configured as `$return` in the *function.json* file. |
|`Outputs`|JSON | Holds response values as defined by the `bindings` array the *function.json* file.<br /><br />For instance, if a function is configured with a blob storage output binding named "blob", then `Outputs` contains a key named `blob`, which is set to the blob's value. |
125
+
|`Logs`| array | Messages appear in the Functions invocation logs.<br /><br />When running in Azure, logged messaged appear in Application Insights. |
126
+
|`ReturnValue`| string | Used to provide a response when an output is configured as `$return` in the *function.json* file. |
60
127
61
128
See the [example for a sample payload](#server-implementation).
62
129
63
-
### Considerations
130
+
##Examples
64
131
65
-
- Your app must respond to requests within 60 seconds or the host considers the request a failure and attempts a retry.
132
+
Custom handlers can be implemented in any language that supports HTTP events. While Azure Functions [fully supports JavaScript and Node.js](./functions-reference-node.md), the following examples show how to implement a custom handler using JavaScript in Node.js for the purposes of instruction.
66
133
67
-
## Create a custom handler
134
+
> [!TIP]
135
+
> While being a guide for learning how to implement a custom handler in other languages, the Node.js-based examples shown here may also be useful if you wanted to run a Functions app in a non-supported version of Node.js.
68
136
69
-
Custom handlers can be implemented in any language that supports HTTP events. While Azure Functions [fully supports JavaScript and Node.js](./functions-reference-node.md), the following example shows how to implement a custom handler using JavaScript in Node.js for the purposes of instruction.
137
+
## HTTP-only function
70
138
71
-
The scenario implemented in this example features a function named `order` that accepts a `POST` with a payload representing a product order.
139
+
The following example demonstrates how to configure a simple HTTP-triggered function with no additional bindings or outputs. The scenario implemented in this example features a function named `http` that accepts a `GET` or `POST` .
140
+
141
+
The following snippet represents how a a request to the function is composed.
72
142
73
143
```http
74
-
POST http://127.0.0.1:7071/api/order HTTP/1.1
144
+
POST http://127.0.0.1:7071/api/hello HTTP/1.1
75
145
content-type: application/json
76
146
77
147
{
78
-
"id": 1005,
79
-
"quantity": 2,
80
-
"color": "black"
148
+
"message": "Hello World!"
81
149
}
82
150
```
83
151
84
-
### Application configuration
152
+
### Implementation
85
153
86
-
A custom handler is defined by configuring the *host.json* file with details on how to start your HTTP server. The `httpWorker` section points to an execution target as defined by the `defaultExecutablePath`. The execution target may either be an executable or the combination of an executable and a target file.
87
-
88
-
For an app written in a compiled language, `defaultExecutablePath` points to an executable file.
154
+
In a folder named *http*, the *function.json* file configures the HTTP-triggered function.
89
155
90
156
```json
91
157
{
92
-
"version": "2.0",
93
-
"httpWorker": {
94
-
"description": {
95
-
"defaultExecutablePath": "server.exe"
96
-
}
158
+
"bindings": [
159
+
{
160
+
"type": "httpTrigger",
161
+
"direction": "in",
162
+
"name": "req",
163
+
"methods": ["get", "post"]
164
+
},
165
+
{
166
+
"type": "http",
167
+
"direction": "out",
168
+
"name": "res"
97
169
}
170
+
]
98
171
}
99
172
```
100
173
101
-
For scripted apps, `defaultExecutablePath` points to the script language's executable and `defaultWorkerPath` points to the script file location. The following example shows how to a JavaScript app in Node.js is configured as a custom handler.
174
+
The function is configured to accept both `GET` and `POST` requests and the result value is provided via an argument named `res`.
175
+
176
+
At the root of the app, the *host.json* file is configured to run Node.js and point the `server.js` file.
102
177
103
178
```json
104
179
{
@@ -112,28 +187,59 @@ For scripted apps, `defaultExecutablePath` points to the script language's execu
112
187
}
113
188
```
114
189
115
-
You can also pass arguments using the `arguments` array:
190
+
The file *server.js* file implements a web server and HTTP function.
191
+
192
+
```javascript
193
+
constexpress=require("express");
194
+
constapp=express();
195
+
196
+
app.use(express.json());
197
+
198
+
constPORT=process.env.FUNCTIONS_HTTPWORKER_PORT;
199
+
200
+
constserver=app.listen(PORT, "localhost", () => {
201
+
console.log(`Your port is ${PORT}`);
202
+
const { address:host, port } =server.address();
203
+
console.log(`Example app listening at http://${host}:${port}`);
204
+
});
205
+
206
+
app.get("/hello", (req, res) => {
207
+
res.json("Hello World!");
208
+
});
209
+
210
+
app.post("/hello", (req, res) => {
211
+
res.json({ value:req.body });
212
+
});
213
+
```
214
+
215
+
In this example, Express is used to create a web server to handle HTTP events and is set to listen for requests via the `FUNCTIONS_HTTPWORKER_PORT`.
216
+
217
+
The function is defined at the path of `/hello` . `GET` requests are handled by returning a simple JSON object, and `POST` requests have access to the request body via `req.body`.
218
+
219
+
The route for the order function here is `/hello` and not `/api/hello` because the Functions host is proxying the request to the custom handler.
220
+
221
+
>[!NOTE]
222
+
>The `FUNCTIONS_HTTPWORKER_PORT` is not the public facing port used to call the function. This port is used by the Functions host to call the custom handler.
223
+
224
+
## Function with bindings
225
+
226
+
The scenario implemented in this example features a function named `order` that accepts a `POST` with a payload representing a product order.
227
+
228
+
```http
229
+
POST http://127.0.0.1:7071/api/order HTTP/1.1
230
+
content-type: application/json
116
231
117
-
```json
118
232
{
119
-
"version": "2.0",
120
-
"httpWorker": {
121
-
"description": {
122
-
"defaultExecutablePath": "node",
123
-
"defaultWorkerPath": "server.js",
124
-
"arguments": [ "--inspect" ] // allows you to set breakpoints for debugging
125
-
}
126
-
}
233
+
"id": 1005,
234
+
"quantity": 2,
235
+
"color": "black"
127
236
}
128
237
```
129
238
130
-
Arguments are necessary for many debugging setups. See the [Debugging](#debugging) section for more detail.
131
239
132
-
Standard triggers and input and output bindings are available by referencing [extension bundles](./functions-bindings-register.md) in your *host.json* file.
240
+
### Implementation
133
241
134
-
### Function definition
135
-
136
-
The following *function.json* file is no different from how you would define a function under any other context. Since the function name is *order*, this file is saved in a folder named "order".
242
+
In a folder named *order*, the *function.json* file configures the HTTP-triggered function.
137
243
138
244
```json
139
245
{
@@ -164,12 +270,21 @@ The following *function.json* file is no different from how you would define a f
164
270
165
271
This function is defined as an [HTTP triggered function](./functions-bindings-http-webhook-trigger.md) that returns an [HTTP response](./functions-bindings-http-webhook-output.md) and outputs a [Queue storage](./functions-bindings-storage-queue-output.md) message.
166
272
167
-
### Server implementation
273
+
At the root of the app, the *host.json* file is configured to run Node.js and point the `server.js` file.
168
274
169
-
A web server is used to listen for requests coming through the `FUNCTIONS_HTTPWORKER_PORT`.
275
+
```json
276
+
{
277
+
"version": "2.0",
278
+
"httpWorker": {
279
+
"description": {
280
+
"defaultExecutablePath": "node",
281
+
"defaultWorkerPath": "server.js"
282
+
}
283
+
}
284
+
}
285
+
```
170
286
171
-
>[!NOTE]
172
-
>The `FUNCTIONS_HTTPWORKER_PORT` is not the public facing port used to call the function. This port is used by the Functions host to call the custom handler.
287
+
The file *server.js* file implements a web server and HTTP function.
173
288
174
289
```javascript
175
290
constexpress=require("express");
@@ -179,6 +294,12 @@ app.use(express.json());
179
294
180
295
constPORT=process.env.FUNCTIONS_HTTPWORKER_PORT;
181
296
297
+
constserver=app.listen(PORT, "localhost", () => {
298
+
console.log(`Your port is ${PORT}`);
299
+
const { address:host, port } =server.address();
300
+
console.log(`Example app listening at http://${host}:${port}`);
console.log(`Example app listening at http://${host}:${port}`);
201
-
});
202
-
203
317
```
204
318
205
-
Express.js is used to create a web server to handle HTTP events and is set to listen for requests via the `FUNCTIONS_HTTPWORKER_PORT`.
319
+
In this example, Express is used to create a web server to handle HTTP events and is set to listen for requests via the `FUNCTIONS_HTTPWORKER_PORT`.
206
320
207
-
The order function is defined at the path of `/order` and extracts the request payload to save as a queue message.
321
+
The function is defined at the path of `/order`. The route for the order function here is `/order`and not `/api/order` because the Functions host is proxying the request to the custom handler.
208
322
209
-
The route for the order function here is `/order` and not `/api/order` because the function host is proxying the request to the custom handler. Once the Functions host receives the request, the proxied request sent to the handler at the handler's application root.
323
+
As `POST` requests are sent to this function, data is exposed through a few points:
210
324
211
-
The message contents are available from the request via `req.body.Data.req.Body`.
325
+
- The request body is available via `req.body`
326
+
- The data posted to the function is available via `req.body.Data.req.Body`
212
327
213
-
The function's response is formatted into a key/value pair where the `Outputs` member holds another key/value pair where the keys match the outputs as defined in the *function.json* file.
328
+
The function's response is formatted into a key/value pair where the `Outputs` member holds a JSON value where the keys match the outputs as defined in the *function.json* file.
214
329
215
330
By setting `message` equal to the message that came in from the request, and `res` to the expected HTTP response, this function outputs a message to Queue Storage and returns an HTTP response.
216
331
217
332
## Debugging
218
333
219
-
To debug your Functions custom handler app, the `--inspect` flag needs to be included as an argument in the *host.json* file.
334
+
To debug your Functions custom handler app you need to add arguments appropriate for the language and runtime to enable debugging.
220
335
221
-
> [!NOTE]
222
-
> The debugging configuration is part of your *host.json* file, which means that you may need to remove the `--inspect` argument before deploying to production.
336
+
For instance, to debug a Node.js application, the `--inspect` flag is passed as an argument in the *host.json* file.
223
337
224
338
```json
225
339
{
@@ -228,24 +342,28 @@ To debug your Functions custom handler app, the `--inspect` flag needs to be inc
228
342
"description": {
229
343
"defaultExecutablePath": "node",
230
344
"defaultWorkerPath": "server.js",
231
-
"arguments": [ "--inspect" ]// allows you to set breakpoints for debugging
345
+
"arguments": [ "--inspect" ]
232
346
}
233
347
}
234
348
}
235
349
```
236
350
351
+
> [!NOTE]
352
+
> The debugging configuration is part of your *host.json* file, which means that you may need to remove the some arguments before deploying to production.
353
+
237
354
With this configuration, you can start the Function's host process using the following command:
238
355
239
356
```bash
240
357
func host start
241
358
```
242
-
243
359
Once the process is started, you can attach a debugger and hit breakpoints.
244
360
245
361
### Visual Studio Code
246
362
247
363
The following example is a sample configuration that demonstrates how you can set up your *launch.json* file to connect your app to the Visual Studio Code debugger.
248
364
365
+
This example is for Node.js, so you may have to alter this example for other languages or runtimes.
366
+
249
367
```json
250
368
{
251
369
"version": "0.2.0",
@@ -264,3 +382,11 @@ The following example is a sample configuration that demonstrates how you can se
264
382
## Deploying
265
383
266
384
A custom handler can be deployed to any Azure Functions hosting option. If your handler requires custom dependencies (such as a language runtime), you may need to use a [custom container](./functions-create-function-linux-custom-image.md).
385
+
386
+
## Restrictions
387
+
388
+
Custom handlers are not supported in Linux consumption plans.
389
+
390
+
## Samples
391
+
392
+
Refer to the custom handler samples GitHub repo for examples of how to implement functions in a variety of different languages.
0 commit comments