A URL minifier which works with Azure Functions, and a couple of other Azure services, just because we can!
Action | HTTP VERB | Description |
---|---|---|
Get | GET | Retrieves the URL matching the slug and redirects, or returns a NotFound code (404 ). |
Create | POST | Creates a new slug in the repository, along with the redirect URL. The response is either BadRequest (400 ) or Created (201 ) |
Delete | DELETE | Removes the URL matching the specified slug from the repository. The response is either BadRequest (400 ), Ok (200 ) if the deletion is done, or ExpectationFailed (417 ) if anything forbid the deletion to be performed. |
Invoke the Azure Function like this.
GET http://{yourInstance}/someSlug
Replace {yourInstance}
with your actual host.
POST http://localhost:7071/api/Create?code=yourFunctionKey
{
"slug": "blog",
"url": "https://jan-v.nl"
}
This will result in the slug being stored in the repository. Make sure you have some authorization in place, like using a Function Key.
Not implemented, yet
DELETE http://localhost:7071/api/Delete?code=yourFunctionKey
{
"slug": "blog",
}
This will remove the specified slug from the repository. Make sure you have some authorization in place, like using a Function Key.
There are several configuration values the solution depends upon.
You should add a file called local.settings.json
, if you want to run the solution yourself.
While the deployment templates make sure the appropriate permissions are set for the managed identities, you need to do this for yourself when running on your own machine. Within Visual Studio you can set the used identity in Tools -> Options -> Azure Service Authentication -> Account Selection
. Most other tools use the identity configured via the Azure CLI.
The Azure Functions are using identity-based bindings, therefore you need to grant yourself the appropriate roles to use these. You can use the following script to grant yourself the appropriate roles for Cosmos DB.
$resourceGroupName='<myResourceGroup>'
$accountName='<myCosmosAccount>'
# Cosmos DB Built-in Data Reader: 00000000-0000-0000-0000-000000000001
# Cosmos DB Built-in Data Contributor: 00000000-0000-0000-0000-000000000002
$readOnlyRoleDefinitionId = '<roleDefinitionId>'
$principalId = '<aadPrincipalIdOfYourManagedIdentity>'
az cosmosdb sql role assignment create --account-name $accountName --resource-group $resourceGroupName --scope "/" --principal-id $principalId --role-definition-id $readOnlyRoleDefinitionId
The principalId
is the Object Id of your Managed Identity OR from your own Azure Active Directory account.
The contents of the Minifier.Backend
project should look similar to the following:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"MinifierIncomingMessages__fullyQualifiedNamespace": "{yourServiceBusNamespaceName}.servicebus.windows.net",
"IncomingUrlsTopicName": "incoming-minified-urls", // This one is defined in the Bicep template, but you can change it if you want.
"IncomingUrlsProcessingSubscription": "process", // This one is defined in the Bicep template, but you can change it if you want.
"UrlMinifierRepository__accountEndpoint": "https://{yourCosmosDbAccountName}.documents.azure.com:443/",
// Or this if you're running with the local emulator
"UrlMinifierRepository": "AccountEndpoint=https://localhost:8081/;AccountKey={theEmulatorKey}",
"UrlMinifierRepository__DatabaseName": "minifier", // This one is defined in the Bicep template, but you can change it if you want.
"UrlMinifierRepository__CollectionName": "urls" // This one is defined in the Bicep template, but you can change it if you want.
}
}
The contents of the Minifier.Frontend
project should look similar to the following:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"UrlMinifierRepository__accountEndpoint": "https://{yourCosmosDbAccountName}.documents.azure.com:443/",
"UrlMinifierRepository__DatabaseName": "minifier", // This one is defined in the Bicep template, but you can change it if you want.
"UrlMinifierRepository__CollectionName": "urls", // This one is defined in the Bicep template, but you can change it if you want.
"MinifierIncomingMessages__fullyQualifiedNamespace": "{yourServiceBusNamespaceName}.servicebus.windows.net",
"IncomingUrlsTopicName": "incoming-minified-urls", // This one is defined in the Bicep template, but you can change it if you want.
"IncomingUrlsProcessingSubscription": "updatefrontendweu" // This one is defined in the Bicep template, but you can change it if you want.
}
}
To get the necessary Azure resources, run the following Azure CLI commands in the folder ./deployment/infrastructure/
:
az deployment sub create --location WestEurope --template-file basic-infrastructure.bicep --parameters parameters.lcl.json
az deployment sub create --location WestEurope --template-file main.bicep --parameters parameters.lcl.json
This is all being handled by the Bicep template in this repository, so no need to worry about it.
To deploy this solution you need to create a service principal in Azure which has the appropriate roles to create resource groups, all resources and set permissions (RBAC) to all these resources. The easiest way to set this up is by using the Owner
role, as it has enough permissions to apply roles. However, keep in mind, this grants the service principal a lot of power on the entire subscription.
az ad sp create-for-rbac --name "minifier" --role owner --scopes /subscriptions/{subscriptionId} --sdk-auth
What I'm doing to limit this is to make this service principal a Contributor
, which still grants it a lot of power, and applying the Owner
role to the created resource group after the first (failed) deployment.
After executing the command above, you should have an output similar to the following:
{
"clientId": "d9816ed2-66f2-40f2-bcf0-1b222a910416",
"clientSecret": "someSuperSecret",
"subscriptionId": "fe2a1369-754c-4703-ba37-c3a864e1eac8",
"tenantId": "b491f32d-ecc5-43ba-9699-0860994360d7",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
Store this value in a GitHub secret called AZURE_DEV
and you're good to go!
The basics of the URL minfier are covered above. The following contents will be about additional features which are totally optional to add. During deployment the toggle additionalFeatures
can be set to either true
or false
depending on if you want to have this deployed too.
An API call can be made to the summarize
endpoint, using a slug.
GET https://{host}/summarize/{slug}
This wil result in the following response:
{
"summary": "lorem ipsum..."
}
The summary is created using Azure Open AI service with a specified LLM in the configuration.
The following settings are necessary, along with a deployed Azure Open AI service and model.
{
"OpenAiServiceCompletionEndpoint": "",
"OpenAiServiceKey": "",
"OpenAiServiceDeploymentId": "",
}
Note: At this moment in time, only specific Azure subscriptions can deploy the Azure Open AI service. While this repository contains the Bicep template for it, the service is deployed in a different subscription. Therefore, the settings necessary will be injected via GitHub secrets to the deployment.