Azure Functions with Go and SharePoint integration

Azure Functions with Go and SharePoint integration

Just found out I didn't published an article about using Go with Azure Functions and SharePoint integration. So here it is.

Why Serverless?

Serverless is a paradigm of computing. It's a way of building and running applications and services without thinking about servers. It's a way of building applications where you don't have to worry about managing infrastructure, scaling, high availability, etc.

Azure Functions is a serverless compute service that lets you run code on-demand without having to explicitly provision or manage core infrastructure. Azure Functions can scale based on demand and you pay only for the time your code runs and the resources you consume.

It's very handy for the cases when you need a backend service of job with a relatively small or unpredictable consumption.

Why Go?

Support for custom handlers in Azure Functions is a great feature. It allows to use any language or framework to build a custom handler. Go is a great choice for a number of reasons: it's a...

  • compiled language, so it's fast and efficient
  • statically typed language, so it's easy to debug and maintain
  • modern language, so it's easy to learn and use
  • simple language, so it's easy to read and understand
  • language with a great community, so it's easy to find help and support

Why SharePoint?

In a majority of enterprise projects with Microsoft 365; SharePoint is a platform which is already there, you can use it for business data or document management. Nice to have option for a flavor of collaborative scenarios.

What's in the box?

Let's combine this together: Azure Functions + Go + SharePoint. Sounds like a good idea, right? Yep, but could be tricky to start with as it's a bit unusual combination. I've created a sample project to help you get started.

Code source: https://github.com/koltyakov/az-fun-go-sp

Prerequisites

Mac or Linux machine, or Windows WSL2 are preferred.
All the commands within the sample assumed running in `bash`.

Create Azure Function Resource

This flow is dev friendly when it comes to quick experiments. For production deployments please consider infrastructure as code and automation via DevOps.

In VS Code with Azure Functions extension installed:

  • `CMD+Shift+P` type `Azure Functions: Create Function App in Azure... (Advanced)` and follow the wizard (further is the example of the steps)
  • Select dev subscription
  • Enter a globally unique name for the new function app
  • Select a runtime stack: `Custom Handler`
  • Select an OS: `Linux`
  • Select a hosting plan: `Consumption`
  • Create a new resource group
  • Enter the name of the new resource group
  • Create new storage account
  • Enter the name of the new storage account
  • Create new Application Insights resource
  • Enter the name of the new Application Insights resource
  • Select a location for new resources (closer to your location)

Don't forget to remove the resource group after experiments to avoid any unexpected charges. Yet, with Serverless you mostly can expect almost zero paycheck if it's not used.

Project structure highlights

`.vscode/` - VSCode settings folder, mostly standard, however, `settings.json` has important modification `"azureFunctions.deploySubpath": "./functions"` which changes root folder for functions deployment via `ms-azuretools` extension

`functions/` - everything related to Azure Functions, isolation makes things simpler while no mixing with custom handler related project files

- Functions folders, containing `function.json` file

- `.funcignore` - functions ignore file with handy ignore options

- `host.json` - host configuration file, mostly standard, interesting and important section is `customHandler`, especially `"enableForwardingHttpRequest": true` which is not added by default

- `local.settings[.sample].json` - contains configuration which is needed for local development and debug, local settings should be excluded from Git to avoid secrets leak

- `proxies.json` - bypassing endpoints to external resources

`handlers/` - Handlers sub package grouping by extensible handlers methods

`debug.go` - grabs Azure Functions settings to use when starting the handlers' server separately, is not included into production build

`main.go` - Custom Handler Go server entry point

`mux.go` - routes and handler binding configuration

`sp.go` - SharePoint Client and authentication constructor

`Makefile` - useful tasks/commands collection for project automation

Local start/debug

Copy/rename `local.settings.sample.json` to `local.settings.json`.

Provide authentication parameters:

  • SPAUTH_SITEURL
  • SPAUTH_CLIENTID
  • SPAUTH_CLIENTSECRET

Add-in Only auth is used as a sample.

Start the local server with `make start`

Navigate to one of the URL endpoints printed in the console

Debugging Go code

For breaking points debugging in VSCode a number of approaches can be used: attaching to process or connecting to server. In most cases, one would prefer restarting Go server without stoping and restarting `func start` session. Also, it's simpler to place a breakpoint, switch to `main.go` file, and launch debug. Such a scenario can be covered with:

make debug        

The local function app is started without actually starting the Go side-car server, but mimicking the process for functions core utility.

Then, the Go application can be started or restarted as many times as needed, e.g. using `go run ./` or launch debug UI.

Build and deploy

1. Run build command:

make build-prod        

The assumption is that a Linux plan was selected for the function app.

The build creates `bin/server` binary with the Go custom handler.

2. In VSCode,

  • `CMD+Shift+P` type `Azure Functions: Deploy to Function App...`
  • Select subscription
  • Select Function App in Azure
  • Confirm deployment

Publish via CLI

Publishing via CLI is a faster and more robust scalable way.

make appname="functionapp_name" publish        

where `"functionapp_name"` is the name of your Function App instance.

`az` CLI is required.

Configure environment variables

In the Azure Function app, create and provide the following environment variables:

  • SPAUTH_SITEURL
  • SPAUTH_CLIENTID
  • SPAUTH_CLIENTSECRET

Depending on the SharePoint environment and use case, auth strategy can be different. For a production installation Azure Certificate Auth might be preferred.

`sp.go/getSP` handler should be aligned with authentication parameters.

Overriding host's settings

Azure Functions use .Net native approaches dealing with settings. Hierarchical settings can be overriden with environment variables.

E.g., you need `server.exe` locally but a Linux Functions host still needs `server` (without extention) in `hosts.json`, it can be redefined in `local.settings.json` with a value:

{
  // ...
  "Values": {
    // ...
    "AzureFunctionsJobHost__customHandler__description__defaultExecutablePath": "bin/server.exe"
  }
}
        

Adding new function

1. `CMD+Shift+P` type `Azure Functions: Create Function...`

2. Select a template for your function, e.g. `HTTP trigger`

3. Provide a function name. e.g. `HttpTrigger1`

4. Select authorization level, e.g. `Function`

A function's folder and bindings definition is created `functions/HttpTrigger1/function.json`:

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}        

5. Run `make start` and follow via `https://localhost:7071/api/HttpTrigger1` for just created function's binding

The Echo service handler will response with URL path `/api/HttpTrigger1`, that's because created function is not processed with specific route Go custom handler yet.

`Ctrl+C` to stop running functions host.

6. Create `handlers/HttpTrigger1.go` and paste:

package handler

import (
  "fmt"
  "net/http"
)

// HTTPTrigger1 handles a function's logic
func (h *Handlers) HTTPTrigger1(w http.ResponseWriter, r *http.Request) {
  name := r.URL.Query().Get("name")
  fmt.Fprintf(w, "Hello, %s!", name)
}        

7. Bind a handler with a route in `mux.go` in API routes section:

http.HandleFunc("/api/HttpTrigger1", h.HTTPTrigger1)        

8. Run `make start` and navigate to `https://localhost:7071/api/HttpTrigger1?name=Function`

`Hello, Function!` should be responded back.

SharePoint API in Go

Check `handlers/fields.go` and `handlers/lists.go` as samples of comuting with SharePoint instance.

In a handler, `h.sp.` exposes access to SharePoint object model.

The API layer is powered by gosip.

Reference


Andrew Koltyakov

Solutions Architect, Microsoft MVP

2 年

On Friday there will be the part two with Infrastructure as Code with #terraform diving in.

回复

要查看或添加评论,请登录

Andrew Koltyakov的更多文章

社区洞察

其他会员也浏览了