Http Trigger #Azure functions with CosmosDB SQL API #serverless

Examples how to get routing parameters with SQL API working for Cosmos DB in Azure functions.

icon of user profile

Published 17th of October 2018
Version .net 4.7

All these example are used in the back end of this app Find an Episerver Partner with Certified Developers

Http Trigger Function apps

Example 1: Getting data from Cosmos DB with SQL API and routing parameter then deserializing the data to custom object.

Test URL: https://gosso-epiworld.azurewebsites.net/api/GetDevs/CmsCert/Gosso Systems AB

Route = “GetDevs/{type}/{company}” and then using {type} in SQL:

[DocumentDB(Manager.DatabaseName, “devs”, ConnectionStringSetting = Manager.DbConnString, SqlQuery = “SELECT top 1 * FROM c where c.type={type} and c.count>0 order by c._ts desc”)]

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;

namespace EpiWorldFunctions.CertifiedDevs
{
    public static class GetDevs
    {
        [FunctionName("GetDevs")]
        public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "GetDevs/{type}/{company}")]HttpRequestMessage req, 
            string company,
            string type,
            [DocumentDB(Manager.DatabaseName, "devs", ConnectionStringSetting = Manager.DbConnString, SqlQuery = "SELECT top 1 * FROM c where c.type={type} and c.count>0 order by c._ts desc")] IEnumerable<object> documents
            , TraceWriter log)
            {
                Manager.DbDocument deserializedDbDocument = JsonConvert.DeserializeObject<Manager.DbDocument>(documents.FirstOrDefault()?.ToString());

                 if (company == "Unknown")
                    deserializedDbDocument.Devs = deserializedDbDocument.Devs.Where(item => item.Company=="")
                        .Select(x => x)
                        .ToList();
                else if (company!="everyone")
                    deserializedDbDocument.Devs = deserializedDbDocument.Devs.Where(item => System.Net.WebUtility.HtmlDecode(item.Company).Contains(company))
                    .Select(x=>x)
                    .ToList();

                 string message = $"type: {type} | company: {company} | returns: {deserializedDbDocument.Devs.Count}";
                 log.Info(message);
                System.Diagnostics.Trace.WriteLine(message);

            return req.CreateResponse(HttpStatusCode.OK, deserializedDbDocument, "application/json");
            }
    }
}

Business logic (Manager) and structs:

using Microsoft.Azure.WebJobs.Host;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace EpiWorldFunctions
{
    public class Manager
    {
        public const string DbConnString = "AzureWebJobsDocumentDBConnectionString"; //this file is set in local.settings.json
        public const string DatabaseName = "databasename-not-collection";

        public enum DevType
        {
            Emvp = 0, ComCert = 1, CmsCert = 2
        }
        public struct DbDocument {
            [JsonProperty("date")]
            public DateTime Date;
            [JsonProperty("devs")]
            public List<Developer> Devs;
            [JsonProperty("count")]
            public int Count;
            [JsonProperty("type")]
            public string Type;
        }
        public struct Developer
        {
            [JsonProperty("name")]
            public string Name;

            [JsonProperty("company")]
            public string Company;

            [JsonProperty("url")]
            public string Url;
        }
    }
}

Example 2: Getting data from Cosmos DB with SQL API and routing parameter then deserializing the data to custom object. Grouping devs by Company

Test URL: https://gosso-epiworld.azurewebsites.net/api/GetCompanies/ComCert/

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;

namespace EpiWorldFunctions.CertifiedDevs
{
    public static class GetCompanies
    {
        [FunctionName("GetCompanies")]
        public static HttpResponseMessage Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "GetCompanies/{type}/")] HttpRequestMessage req,
            string type,
            [DocumentDB(Manager.DatabaseName, "devs", ConnectionStringSetting = Manager.DbConnString, SqlQuery = "SELECT top 1 * FROM c where c.type={type} and c.count>0 order by c._ts desc")] IEnumerable<object> documents, TraceWriter log)
        {
            if (documents.Count() == 0)
                return req.CreateResponse(HttpStatusCode.NoContent, "[]", "application/json");

            Manager.DbDocument deserializedDbDocument = JsonConvert.DeserializeObject<Manager.DbDocument>(documents.FirstOrDefault()?.ToString());

            var list = deserializedDbDocument.Devs.GroupBy(item => item.Company)
                .Select(group => new {company = group.Key, count = group.Count()})
                .OrderByDescending(x=> x.count).ThenBy(x => x.company)
                .ToList();

            TimeSpan span = DateTime.Now.Subtract(deserializedDbDocument.Date);

            var returnObj = new {date = span.Hours, companies = list};

            log.Info($"Logmessage type: {type} | returns: {list.Count}");
            System.Diagnostics.Trace.WriteLine($"System.Diagnostics.Trace.WriteLine type: {type} | returns: {list.Count}");

            return req.CreateResponse(HttpStatusCode.OK, returnObj, "application/json");
        }
    }
}

 

Example 3: Get a subsequence of the data from cosmos, retrieve and return a smaller json for statistics.

Used here: https://devblog.gosso.se/find-an-episerver-certified-dev-company/certification-over-time/

Test url: https://gosso-epiworld.azurewebsites.net/api/GetStatsByDate/ComCert/

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace EpiWorldFunctions.CertifiedDevs
{
    public static class GetStatsByDate
    {
        [FunctionName("GetStatsByDate")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "GetStatsByDate/{type}/")]HttpRequestMessage req,
            string type,
            [DocumentDB(Manager.DatabaseName, "devs", ConnectionStringSetting = Manager.DbConnString, SqlQuery = "SELECT c.date, c.count FROM c where c.type={type} and c.count>0 order by c._ts desc")] IEnumerable<object> documents,
            TraceWriter log)
          {
              var docs = documents.ToList();
              log.Info("C# HTTP trigger function processed a request. Found documents: " + docs.Count);

             return req.CreateResponse(HttpStatusCode.OK, docs, "application/json");
        }
    }
}

 

Tip: Local diagnostics with System.Diagnostics.Trace.WriteLine(message);

Further reading and testing

SEO Terms

  • Serverless Cosmos db example
  • Using routing in function app

About the author

Image of Luc GossoLuc Gosso
– Independent Senior Web Developer
working with Azure and Episerver

Twitter: @LucGosso
LinkedIn: linkedin.com/in/luc-gosso/
Github: github.com/lucgosso