Create REST API with Azure Function App
Tags: azurefunctionapp, rest, api, dotnet
Published: 2021-03-28 21:16:47

When we create a function for an HTTP trigger, the function is addressable with a route of the form
`http://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>`
We can customize this route using the optional route property on the HTTP trigger's input binding. 
With this concept of route I tried to implement REST style API for contacts.

| Function  | REST verb & route|
| ------------- | ------------- |
| CreateContact  | POST api/contact  |
| GetContacts  | GET api/contact  |
| GetContactById  | GET api/contact/{id}  |
| UpdateContact  | PUT api/contact/{id}  |
| DeleteContact  | DELETE api/contact/{id}  |

We can use Visual Studio Code with Azure Functions extensions or directly use the Azure portal for my sample API. For brevity I'm skipping the project creation procedure and focused mainly on the Azure Function implementation to get the desired result. Relied on the in-memory collection for simplicity. The complete code is placed here {% github amk07/FunctionAppAsAPI no-readme %}.


**Create a contact, POST api/contact**


```csharp
        [FunctionName("CreateContact")]
        public static async Task<IActionResult> CreateContact(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "contact")] HttpRequest req, ILogger log)
        {
            log.LogInformation("Creating a new contact");
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            var input = JsonConvert.DeserializeObject<ContactModel>(requestBody);

            var contact = new Contact() { FirstName = input.FirstName, LastName = input.LastName, Phone = input.Phone };
            contacts.Add(contact);
            return new OkObjectResult(contact);
        }
```

**Get all contacts, GET api/contact**
```csharp
        [FunctionName("GetContacts")]
        public static IActionResult GetContacts(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "contact")] HttpRequest req, ILogger log)
        {
            log.LogInformation("Getting contacts");
            return new OkObjectResult(contacts);
        }
```

**Get contact by id, GET api/contact/{id}**
I'm using the `{id}` parameter to the Route binding `Route = "contact/{id}"`
```csharp
        [FunctionName("GetContactById")]
        public static IActionResult GetContactById(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "contact/{id}")] HttpRequest req,
            ILogger log, string id)
        {
            var contact = contacts.FirstOrDefault(t => t.Id == id);
            if (contact == null)
            {
                log.LogWarning("contact not found");

                return new NotFoundResult();
            }

            log.LogInformation("Getting contact by Id");

            return new OkObjectResult(contact);
        }
```

**Update contact, PUT api/contact/{id}**
```csharp
        [FunctionName("UpdateContact")]
        public static async Task<IActionResult> UpdateContact(
            [HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "contact/{id}")] HttpRequest req,
            ILogger log, string id)
        {
            var contact = contacts.FirstOrDefault(t => t.Id == id);
            if (contact == null)
            {
                log.LogWarning("contact not found");

                return new NotFoundResult();
            }

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            var updatedContact = JsonConvert.DeserializeObject<ContactModel>(requestBody);

            if (!string.IsNullOrEmpty(updatedContact.FirstName))
            {
                contact.FirstName = updatedContact.FirstName;
            }
            if (!string.IsNullOrEmpty(updatedContact.LastName))
            {
                contact.LastName = updatedContact.LastName;
            }
            if (!string.IsNullOrEmpty(updatedContact.Phone))
            {
                contact.Phone = updatedContact.Phone;
            }

            return new OkObjectResult(contact);
        }        
```

**Delete a contact, DELETE api/contact/{id}**
```csharp
        [FunctionName("DeleteContact")]
        public static IActionResult DeleteContact(
            [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "contact/{id}")] HttpRequest req,
            ILogger log, string id)
        {
            var contact = contacts.FirstOrDefault(t => t.Id == id);
            if (contact == null)
            {
                return new NotFoundResult();
            }
            contacts.Remove(contact);
            return new OkResult();
        }
```
After these Functions are published in Azure FunctionApp we can take the url as shown in following screenshot
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6w57pe0kgg0l80aqkuqi.png)
 

and use postman to test the API.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jo73ea0c9hzyzl7ip474.png)
 

References:
1. [Develop Azure Functions with Visual Studio Code](https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs-code?tabs=csharp)
2. [Customize http endpoint in azure function](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=csharp#customize-the-http-endpoint
)