One of the greatest advantages of working with Azure Functions is being able to prototype easily applications. For this post I will create a simple Fortune cookie app, which will send you a phrase to your email using Sendgrid and phone via SMS using Twilio. The app will be composed of three pieces
- Front-end web page using HttpTrigger
- POST request processing with HttpTrigger
- Queue processing using Azure Queue Storage Trigger
Front-end
We will use a HTTP trigger for our front-end. Since it will be just that, we don’t really need to create and upload a full web app that will contain only a single page.
So create a new function, of type HTTP Trigger
You will get asked for the name wich can be anithing you want. The important step here is to set the Authorization Level to Anonymous, since it will be public.
Once the function is created, as you can see, it’s already templated with many of the parts we need. Remove all the current code, except for the logging line. Since we want to return a different type of response, first we will create the response message object
HttpResponseMessage m = req.CreateResponse(HttpStatusCode.OK);
Notice we are assigning the Response
to a variable, instead of returning directly as it was before. This is because we want to modify the Content, declaring it will be of type text/html as follows
m.Content = new StringContent(sb.ToString(), Encoding.UTF8, "text/html");
sb will be a < code >StringBuilder object that will help creating the HTML we want to return. We might be able to create it also with HtmlTextWriter, but for this example I prefer to have a string that gives a better visual cue.
On line 40, I’m using string interpolation to provide the value corresponding to the URL that will actually process my requests. We will get the value from the FunctionApp Settings,
string httptriggerurl = ConfigurationManager.AppSettings["httptriggerurl"];
This completes our front-end
Processing the requests
Create a new function of type HTTP Trigger, and this time set the authorization level value to Function. The function (again) contains some templated code. It is desgined to read data from the query string or the request body. Since we are passing the data using a POST, the querystring part can be removed. Your data reading should be something like this
dynamic data = await req.Content.ReadAsAsync<object>();
our desired values can be retrieved as
string phone = data?.phone;
string email = data?.email;
we will also tweak the response to validate that we get at least one of the values
return string.IsNullOrEmpty(phone) || string.IsNullOrEmpty(email)
? req.CreateResponse(HttpStatusCode.BadRequest, "Es necesario pasar teléfono o email")
: req.CreateResponse(HttpStatusCode.OK);
Now, since the process of getting your fortune can take a long time to complete and we want to ensure everybody actually gets it, we will insert the received requests into an queue. For this, create a new output of type Azure Queue Storage in the Integrate section.
Specify the names you want to use and the Storage Connection (which will be read from the App Settings). If the queue doesn’t exist yet, Azure Functions will create it for you automatically.
Go back to develop section and add a new binding parameter of type ICollector named outputQueueItem, and for inserting the values into the queue just add
if(!string.IsNullOrEmpty(phone)){
outputQueueItem.Add($"{{'type': 'phone', 'value':'{phone}'}}");
}
if(!string.IsNullOrEmpty(email)){
outputQueueItem.Add($"{{'type': 'email', 'value':'{email}'}}");
}
Since we are sending a POST request from the front-end function, we can disallow the other verbs. Go to Integrate section, select the trigger and in the Allowed HTTP methods list pick Selected methods and in the Selected HTTP methods section that will appear on the bottom-right, uncheck everything except POST.
Now, we need to link both triggers together by adding the URL of this function to the corresponding App Setting we described in the previous step. Go to Function App Settings on the bottom-left of your screen, and click on Configure app settings button. Scroll down to the App settings section and add httptriggerurl to the list
Processing the queue
We now need to process the messages that have been inserted into the queue. For this, go to the Integrate section again, and click on the Azure Queue Storage output. Scroll down to Action section, and click Go button beside Create a new function triggered by this output legend.
For each message in the queue, we want to deliver it using the corresponding method, so we need to add two outputs for the function.
Go to Integrate and first add the Twilio SMS output (you will need to have a Twilio account already created). Since Account SID, Auth Token and From number values will be read from the app settings we can just add the output as is, since To number and the Message values will be provided at runtime.
Next we need to add the SendGrid output (you will need to have a SendGrid account, that can be created from Azure Portal Marketplace). Similar case, the API key will be retrieved from App Settings, but now you need to define the From address and Message Subject (you can read them from App Settings also if required). Message Text and To address values will be set at runtime.
Go back to Develop, and add the corresponding bindings at the end of your function signature
ICollector<SMSMessage> message, ICollector<Mail> email
Remove the current function code, and replace it with the following. We will be processing each queue item, check the type and send the corresponding message.
dynamic queueItem = JsonConvert.DeserializeObject(myQueueItem);
string to = queueItem?.value;
if(queueItem?.type == "phone"){
log.Info($"Sending SMS to {to}");
SMSMessage sms = new SMSMessage();
sms.Body = fortune;
sms.To = $"+52{to}";
sms.From = ConfigurationManager.AppSettings["TwilioFrom"];
message.Add(sms);
}
if(queueItem?.type == "email"){
log.Info($"Sending Email to {to}");
Mail mail = new Mail();
Personalization personalization = new Personalization();
personalization.AddTo(new Email(to));
mail.AddPersonalization(personalization);
mail.AddContent(new Content("text/plain", fortune));
email.Add(mail);
}
fortune
value can be retrieved from a database or a different storage source. In this case I defined a class called FortuneCookieEngine that will do that work for us.
FortuneCookieEngine f = new FortuneCookieEngine();
string fortune = f.Fortunes[new Random().Next(0, f.Fortunes.Length - 1)];
Now we need to add the corresponding App Setting values for each of the settings we need for the outputs, so you will end up with something like this
Result
Once you complete all the steps, when sending a request from front-end page you should receive something like this
As you can see we created a simple yet somehow full application using only Azure Functions.
Code from this post it is on GitHub, in case you want to download it.