I am trying to deploy Sveltekit to Azure Static Web Apps with a Fastapi backend. I think I am close, but not sure if what I want to do is even possible. I went through a Microsoft article about creating a react app with an api and followed the steps outlined in the svelte-adapter-azure-swa. I am using the fastapi function from another Microsoft learn, which I have successfully deployed on its own.
The Sveltekit function sk_render and the fastapi WrapperFunction are located in an api directory and are present within the staticwebapp project.
.
My app is deployed and renders, however I receive a 404 when trying to fetch from the fastapi function.
routes/+page.svelte
<script>
import { onMount } from "svelte";
let userName = ""
onMount(async function () {
const response = await fetch('api/hello/Jon');
const data = await response.json();
console.log(data);
userName = data.name
});
</script>
<h1>Welcome to SvelteKit {userName}</h1>
<p>Visit kit.svelte.dev to read the documentation</p>
I am not sure if there is some type of configuration I am missing in the host.json or function.json.
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[2.*, 3.0.0)"
},
"extensions":
{
"http":
{
"routePrefix": "api"
}
}
}
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "{*route}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
Thanks
Related
i am using azure functions written in nodejs.
I have this azure function
module.exports = async function (context, req) {
const title = req.body.title;
console.log('title', title);
if (title) {
req.body.completed = false;
context.bindings.outputDocument = req.body;
context.res = {
body: { success: true, message: `Todo added successfully` }
};
} else {
context.res = {
status: 400,
body: { success: false, message: `Please add title field` }
};
}
};
and the binding
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "cosmosDB",
"name": "outputDocument",
"databaseName": "xxx",
"collectionName": "items",
"createIfNotExists": false,
"connectionStringSetting": "xxx",
"partitionKey": "/all",
"direction": "out"
}
],
"disabled": false
}
locally when i run
func host start
i don't see my console log statement.
How can i see on localhost ?
And where i need to go in my azure portal to see the logs there after deployment.
I tried to go in Function App - open my function and there the azure function but i can't see any logs there...
How can i see on localhost ?
And where i need to go in my azure portal to see the logs there after
deployment.
I tried to go in Function App - open my function and there the azure
function but i can't see any logs there...
Of course, you can get the log files on local. I assume you are based on windows, then just edit the host.json like this:
{
"version": "2.0",
"logging": {
"fileLoggingMode": "always",
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
And go to
C:\Users\yourusernameonlocal\AppData\Local\Temp\LogFiles\Application\Functions\Function\yourfunctionname
After that you will see the log files.:)
This should probably resolve your issue.
Azure Functions JavaScript developer guide:
Don't use console.log to write trace outputs. Because output from console.log is captured at the function app level, it's not tied to a specific function invocation and isn't displayed in a specific function's logs.
Guided by this post I have written the following queuetrigger code intended to send emails when a message is queued.
import logging
import sendgrid
import azure.functions as func
import os
def main(msg: func.QueueMessage) -> None:
logging.info('Python queue trigger function processed a queue item: %s',
msg.get_body().decode('utf-8'))
data = {
"personalizations": [
{
"to": [
{
"email": "rrrrrrrr"
}
],
"subject": "Sending with SendGrid is Fun"
}
],
"from": {
"email": "ghyu"
},
"content": [
{
"type": "text/plain",
"value": "and easy to do anywhere, even with Python"
}
]
}
print('Sending email using SendGrid:', data)
with open(os.environ[_AZURE_FUNCTION_SENDGRID_OUTPUT_ENV_NAME], 'wb') as f:
json.dump(data,f)
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "queueTrigger",
"direction": "in",
"queueName": "outqueue1",
"connection": "storageaccountautom92bb_STORAGE"
},
{
"name": "outputMessage",
"type": "sendGrid",
"from": "ghyu",
"apiKey": "MY_SENDGRID_API_KEY",
"direction": "out"
}
],
"disabled": false
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "hjk",
"FUNCTIONS_WORKER_RUNTIME": "python",
"storageaccountautom92bb_STORAGE": "hjk",
"MY_SENDGRID_API_KEY": "tyhuE",
"_AZURE_FUNCTION_SENDGRID_OUTPUT_ENV_NAME" : "GIS klop",
"_AZURE_FUNCTION_QUEUE_INPUT_ENV_NAME" : "msg"
}
}
Whereas the function responds to messages as they queue, it is not able to send emails. It throws an error;
the following parameters are declared in function.json but not in Python: {'outputMessage'}
How best can I resolve this?
Are the outward bindings correct?
Azure Function banned the port of send email, so we must use sendgrid to send email.(This is a third part tools but it was been integrated into azure functions binding, so we can directly use it.)
For example, if you want to send email from email A to email B.
First, go to the sendgrid website, create a sender and verify the email A:
After that, email A is ready to send emails by sendgrid.
Now we need to generate a SendGrid API key and copy and store the API key:(This will be filled in the Values section of local.settings.json as an environment variable to read.)
Then, you can use it to send emails:
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 3.1.0)"
}
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=0730bowmanwindow;AccountKey=xxxxxx;EndpointSuffix=core.windows.net",
"FUNCTIONS_WORKER_RUNTIME": "python",
"SendGrid_API_Key": "SG._-yYnhzER2SEbAvzOxSHnA.xxxxxx",
"0730bowmanwindow_STORAGE": "DefaultEndpointsProtocol=https;AccountName=0730bowmanwindow;AccountKey=xxxxxx;EndpointSuffix=core.windows.net"
}
}
function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "queueTrigger",
"direction": "in",
"queueName": "myqueue",
"connection": "0730bowmanwindow_STORAGE"
},
{
"type": "sendGrid",
"name": "sendGridMessage",
"direction": "out",
"apiKey": "SendGrid_API_Key",
"from": "emailA#emailA.com"
}
]
}
__init__.py
import logging
import json
import azure.functions as func
def main(msg: func.QueueMessage, sendGridMessage: func.Out[str]) -> None:
logging.info('Python queue trigger function processed a queue item: %s',
msg.get_body().decode('utf-8'))
value = "Sent from Azure Functions"
message = {
"personalizations": [ {
"to": [{
"email": "emailB#emailB.com"
}]}],
"subject": "Azure Functions email with SendGrid",
"content": [{
"type": "text/plain",
"value": value }]
}
sendGridMessage.set(json.dumps(message))
After that, I send a message to 'myqueue', and emailB get the email:
By the way, this can only guarantee successful delivery, because some mailboxes refuse to accept mail sent through sendgrid. In this case, you will still get a 200 response, but the recipient will not receive the mail.(In this case, the recipient needs to go to the mailbox settings to lift the relevant restrictions.)
I have simple azure function which is triggered by http
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.res = {
// status: 200, /* Defaults to 200 */
body: "Success"
};
}
function.json
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
At this point I can trigger the function and see the response.
Then I try to add a service bus binding to function.json
{
"bindings": [
...
{
"type": "serviceBus",
"direction": "out",
"name": "outputSbTopic",
"topicName": "topicName",
"connection": "ServiceBusConnection"
}
]
}
When I add the binding the function returns 404 and there is nothing in log. I've even not started to use the binding.
What can be wrong? I'm struggling with the issue more than 2 hours and have no more ideas.
host.json (just in case)
{
"version": "2.0",
"extensions": {
"serviceBus": {
"prefetchCount": 100,
"messageHandlerOptions": {
"autoComplete": true,
"maxConcurrentCalls": 32,
"maxAutoRenewDuration": "00:05:00"
}
}
}
}
Runtime version ~2
Node.js Version Node.js 12 LTS
App is run in read only mode from a package file.
AppType functionAppLinux
UPDATE
I created the function with VS Code Azure Function Extension and deployed with DevOps. Later I created function in azure portal manually. Compared with App Service Editor files of both functions and found out that my first function doesn't have extensionBundle in host.json. That was the reason.
Use your host.json also get the same problem:
The problem seems comes from the host.json in your function app.
On my side those files is:
index.js
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var message = "This is a test to output to service bus.";
context.bindings.testbowman = message;
context.done();
context.res = {
status: 200,
body: "This is a test to output to service bus topic."
};
};
function.json
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"name": "testbowman",
"type": "serviceBus",
"topicName": "testbowman",
"connection": "str",
"direction": "out"
}
]
}
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"str":"Endpoint=sb://testbowman.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx="
}
}
And it worked:
I have NodeJS app in azure functions where I use "azure functions express" module. There is no method context.done() in this module. And 302 redirects every time return empty body with 200 status code. Redirection works with context.done() method for example see Azure Functions Redirect Header
How can I implement context.done() or smth like that to work with redirections.
Thank you!!!!
Since the idea behind the module seems to be to use express APIs themselves, I believe you could just call res.redirect(<url>) as required.
I've tested it with the following settings
HttpTrigger/index.js
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
// Create express app as usual
const app = express();
app.get("/api/", (req, res) => {
res.redirect('/api/abc/xyz');
});
app.get("/api/:foo/:bar", (req, res) => {
res.json({
foo: req.params.foo,
bar: req.params.bar
});
});
// Binds the express app to an Azure Function handler
module.exports = createHandler(app);
HttpTrigger/function.json
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "api/{*segments}"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
host.json
{
"version": "2.0",
"extensions": {
"http": {
"routePrefix": ""
}
}
}
Just got started with azure functions. I am using it as an httptrigger for an IoT device.
I am trying to setup one function that will work for httptrigger requests coming from several IoT devices - So I dont have to setup one function per device. So ideally, in my c# file, I will have something like this:
DeviceClient deviceClient;
string iotHubUri = "myhub";
string deviceName = "something dynamic here that changes with device";
string deviceKey = "something dynamic here that changes with device";
Then , I'd like to get my function url to look something like this:
"https://<functionapp>.azurewebsites.net/api/<function>/{device_id}?code=xxxxx"
where device_id is the IoT device id.
I am not sure how to first setup the reference in the c# file to be dynamic and also how to get the url to look the way I intend.
Some help will be appreciated. Thanks
There is a route parameter is HTTP trigger exactly for this. Your trigger definition should look something like this:
"bindings": [
{
"type": "httpTrigger",
"route": "something/{deviceid}",
"name": "request",
// possibly other parameters
}
],
If you are using precompiled C# functions, you can do the same via attribute property, e.g.
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "GET", Route = "something/{deviceid}")]
HttpRequest request,
string deviceid)
{
// do something based on device id
}
Customize your Azure function route
To customize your url you can use two files, the one in which is defined the function function.json and the host.json.
function.json suffix
in function.json you can define the base url adding to the bindings array the "route": "yourbaseurl" property. that should result in something like this
{
"scriptFile": "../dist/server.js",
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"route": "cool", ///// This is the line that you have to add /////
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
host.json prefix
On the host.jsonfile you can add a prefix to that route, let's say you want to add a fancy name group or so...
therefore your file should look something like this
{
"version": "2.0",
"extensions": {
"http": {
"routePrefix": "prefix" ///// here is that you include your prefix route /////
}
},
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
I just want one word or none
if you want to have just one word in your route leave the host.json "routePrefix": "" and the function.json "route": "therouteyouwant" or empty like "route": "".