Why
I have spend way too much time on figuring out how to create local development environment for
working on Azure Functions. Most of the time was spent on reading Microsoft’s documentation on this
topic. Hopefully this guide will save you some time 🙂
The guide had been prepared on Ubuntu and verified as well. Additionaly my coworker verified it to work on macOS High Sierra.
If you are here to create your first Azure Function locally please read along.
What are azure functions
Azure Functions are small pieces of code that are run on Azure infrastructure in a serverless fashion.
The Infrastructure, provisioning, scaling is Azure’s responsibility. If you wish to read more below are
links to detailed explanation by Azure team. I’d recommend at least skimming the first one.
Software required for local development
There are a couple of tools required to be able to develop locally.
- npm, tooling is mostly in JS/TS
- .NET Core SDK, required for function extensions
- Azure Functions Core Tools (later referred as AFCT)
- Azurite legacy, for storage emulation. It works with Blob, Table, and Queue storages. Legacy is required as the current one supports only Blob storage.
- Docker
Handling http requests
This part explains how to create a function that is triggered by HTTP request and responds with HTTP response.
Create Azure Function project
Start with calling func init HTTPFunc
in the directory of your choosing. You will be asked a couple of questions regarding your project.
majki@enchilada ~/projects/azure-tracker-local
% func init HTTPFunction
Select a worker runtime:
1. dotnet
2. node
3. python (preview)
4. powershell (preview)
Choose option: 2
node
Select a Language:
1. javascript
2. typescript
Choose option: 2
typescript
Writing .funcignore
Writing package.json
Writing tsconfig.json
Writing .gitignore
Writing host.json
Writing local.settings.json
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/.vscode/extensions.json
Create Azure Function
Create function next. As in the previous step you will be asked questions regarding the function you wish to create.
I selected 8. HTTP Trigger as this function should respond to HTTP requests.
majki@enchilada ~/projects/azure-tracker-local
% cd HTTPFunction
majki@enchilada ~/projects/azure-tracker-local/HTTPFunction
% func new
Select a template:
1. Azure Blob Storage trigger
2. Azure Cosmos DB trigger
3. Durable Functions activity
4. Durable Functions HTTP starter
5. Durable Functions orchestrator
6. Azure Event Grid trigger
7. Azure Event Hub trigger
8. HTTP trigger
9. IoT Hub (Event Hub)
10. Azure Queue Storage trigger
11. SendGrid
12. Azure Service Bus Queue trigger
13. Azure Service Bus Topic trigger
14. Timer trigger
Choose option: 8
HTTP trigger
Function name: [HttpTrigger]
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/HttpTrigger/index.ts
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/HttpTrigger/function.json
The function "HttpTrigger" was created successfully from the "HTTP trigger" template.
Install dependencies
npm install
Run function
npm run start
Verify
majki@enchilada ~
% curl http://localhost:7071/api/HttpTrigger
Please pass a name on the query string or in the request body%
majki@enchilada ~
% curl "http://localhost:7071/api/HttpTrigger\?name\=Mike"
Hello Mike
Handling Queue Storage
This part explains how to create a function that is triggered by HTTP request to send a message onto Queue Storage.
Install storage emulation
On windows, you may go with emulator provided by Microsoft.
On Ubuntu, there is community sourced Azurite. Unfortunately, the most recent version does not support Queue Storage. For queues, install version 2.7.0
by following instructions.
Create Azure Function project
Start with calling func init HTTPFunc
in directory of your choosing. You will be asked couple questions regarding your project.
majki@enchilada ~/projects/azure-tracker-local
% func init HTTPFunction
Select a worker runtime:
1. dotnet
2. node
3. python (preview)
4. powershell (preview)
Choose option: 2
node
Select a Language:
1. javascript
2. typescript
Choose option: 2
typescript
Writing .funcignore
Writing package.json
Writing tsconfig.json
Writing .gitignore
Writing host.json
Writing local.settings.json
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/.vscode/extensions.json
Create function
Create function next. As in previous step you will be asked questions regarding function you wish to create.
I selected 8. HTTP Trigger as this function should respond to HTTP requests, it will in response send message to Queue Storage.
majki@enchilada ~/projects/azure-tracker-local
% cd HTTPFunction
majki@enchilada ~/projects/azure-tracker-local/HTTPFunction
% func new
Select a template:
1. Azure Blob Storage trigger
2. Azure Cosmos DB trigger
3. Durable Functions activity
4. Durable Functions HTTP starter
5. Durable Functions orchestrator
6. Azure Event Grid trigger
7. Azure Event Hub trigger
8. HTTP trigger
9. IoT Hub (Event Hub)
10. Azure Queue Storage trigger
11. SendGrid
12. Azure Service Bus Queue trigger
13. Azure Service Bus Topic trigger
14. Timer trigger
Choose option: 8
HTTP trigger
Function name: [HttpTrigger] HTTP2Queue
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/HTTP2Queue/index.ts
Writing /home/majki/projects/azure-tracker-local/HTTPFunction/HTTP2Queue/function.json
The function "HTTP2Queue" was created successfully from the "HTTP trigger" template.
Configure function output
In the editor open function.json
file located in the directory named after the name of the function. Remove the section related to http output and replace with the queue output as shown below:
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outgoingqueue",
"connection": "MyQueueConnectionString"
}
The file is suppose to look like this:
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outgoingqueue",
"connection": "MyQueueConnectionString"
}
],
"scriptFile": "../dist/HTTP2Queue/index.js"
}
Configure queue connection
Some connections defined in function.json
require to have a connection string. After adding an outgoing queue
connection you need to add a connection string as well. String has to be added to
Define connection in local.settings.json
by adding "MyQeueueConnectionString". The value of this string is taken from documentation of Azurite.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsStorage": "{AzureWebJobsStorage}",
"MyQueueConnectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;"
}
}
Install dependencies
npm install
Install extensions
Since we are using an output that is different than http, we have to install storage extensions to make the queue work.
func extensions install
Run azurite
Run Azurite by using Docker
docker run -e executable=queue -d -t -p 10001:10001 -v queue_Storage:/opt/azurite/folder arafato/azurite
More information on how to run it is here.
Run function
In order to put any message on the queue, the function needs to be modified a bit. Please change it accordingly.
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.log('HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
context.bindings.msg = name;
context.done();
};
And then
npm run start
Verify
Now we can see how this is working. We are going to call our function a couple of times and then see what messages had been put on the queue.
majki@enchilada ~
% curl "http://127.0.0.1:7071/api/HTTP2Queue?name=Mike"
HTTP/1.1 204 No Content
Content-Length: 0
Date: Tue, 14 May 2019 06:39:25 GMT
Server: Kestrel
majki@enchilada ~
% curl "http://127.0.0.1:7071/api/HTTP2Queue?name=Mickey"
HTTP/1.1 204 No Content
Content-Length: 0
Date: Tue, 14 May 2019 06:39:28 GMT
Server: Kestrel
There should be two messages on the queue at this moment. We can query the queue by running:
majki@enchilada ~
% curl "http://127.0.0.1:10001/devstoreaccount1/outgoingqueue/messages?peekonly=true&numofmessages=10"
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 885
Content-Type: application/xml; charset=utf-8
ETag: W/"375-pdRmS0dxI0dhZlfRbwGMunhL+WM"
X-Powered-By: Express
date: Tue, 14 May 2019 06:42:39 GMT
x-ms-request-id: 77856d80-7613-11e9-afc4-b5f560b4039e
x-ms-version: 2016-05-31
<?xml version='1.0'?><QueueMessagesList><QueueMessage><MessageId>cae264ef-74bd-4bde-b03e-01be8821968a</MessageId><InsertionTime>Tue, 14 May 2019 06:29:04 GMT</InsertionTime><ExpirationTime>Tue, 21 May 2019 06:29:04 GMT</ExpirationTime><DequeueCount>0</DequeueCount><MessageText>TWlrZQ==</MessageText></QueueMessage><QueueMessage><MessageId>13732448-a498-4fc5-85cf-8c4afafe082b</MessageId><InsertionTime>Tue, 14 May 2019 06:39:25 GMT</InsertionTime><ExpirationTime>Tue, 21 May 2019 06:39:25 GMT</ExpirationTime><DequeueCount>0</DequeueCount><MessageText>TWlrZQ==</MessageText></QueueMessage></QueueMessagesList>
Azurite
supports Queue Storage API, so if you need to know more operations read linked docs.