-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to access request.body in an Azure Function using Node.js (programming model v4) ? #172
Comments
Update: I changed two main things in the Azure Function code above and am now getting a successful response. The modified code is at the end of this message. It includes examples of passing data through to the endpoint via either query parameters or the request body. Change 01) I changed the syntax of the Graph API endpoint from this: const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items?$expand=fields&$filter=ChoiceCol01/Value eq '${choice_col_01_value}' and ChoiceCol02/Value eq '${choice_col_02_value}'`; to this (just added const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items?$expand=fields&$filter=fields/ChoiceCol01/Value eq '${choice_col_01_value}' and fields/ChoiceCol02/Value eq '${choice_col_02_value}'`; Change 02) I indexed the SharePoint library columns that I wanted to filter on. However I am still uncomfortable about the following behavior in Azure Functions:
I would love it if anyone could alleviate, explain or resolve any of the above concerns so that I could confidently use Azure Functions. Otherwise, it seems it would be a lot less stress to set up a conventional web app with backend Node.js/Express server etc so that I could confidently use my normal approach, conventions and folder structure when developing apps in Node.js and not be 'caught out' by any unexpected behavior that may exist in Azure Functions. Modified Azure Function Code // required libraries
const { app } = require('@azure/functions');
// to handle token management
const msal = require('@azure/msal-node');
// to make requests
const axios = require('axios');
app.http('MyHttpTriggerFunction', {
methods: ['GET', 'POST'],
authLevel: 'function',
handler: async (request, context) => {
try {
// sanity check to see if this function is being called when requested
context.log(`The http function processed a request for the req.url "${request.url}"`);
/*
below are two approaches to sending data to the endpoint using a POST request
01. via query parameters (values are displayed in the request URL)
02. in the request body (values are not displayed in the request URL)
*/
// // BEGIN approach 01: using query parameters - this works if values are passed through in query parameters
// const requestQueryParams = request.query;
// context.log(requestQueryParams);
// // get target_site_id from the request query parameters
// const target_site_id = requestQueryParams.get('target_site_id');
// // get target_library_id from the request query parameters
// const target_library_id = requestQueryParams.get('target_library_id');
// // get choice_col_01_value from the request query parameters
// const choice_col_01_value = requestQueryParams.get('choice_col_01_value');
// // get choice_col_02_value from the request query parameters
// const choice_col_02_value = requestQueryParams.get('choice_col_02_value');
// // END approach 01: using query parameters
// BEGIN approach 02: using request body - this works if values are passed through in request body
const requestData = await request.json();
// get target_site_id from the request body
const target_site_id = requestData.target_site_id;
// get target_library_id from the request body
const target_library_id = requestData.target_library_id;
// get choice_col_01_value from the request body
const choice_col_01_value = requestData.choice_col_01_value;
// get choice_col_02_value from the request body
const choice_col_02_value = requestData.choice_col_02_value;
// END approach 02: using request body
// all of the context.log() statements from this point onwards are displayed in a seemingly random order, i.e not synchronously
// this makes it very confusing to ascertain how the function is progressing
context.log("target_site_id:");
context.log(target_site_id);
context.log("target_library_id:");
context.log(target_library_id);
context.log("choice_col_01_value:");
context.log(choice_col_01_value);
context.log("choice_col_02_value:");
context.log(choice_col_02_value);
const msal_config = {
auth: {
clientId: process.env["azure_ad_app_registration_client_id"],
authority: `https://login.microsoftonline.com/${process.env["azure_ad_app_registration_tenant_id"]}`,
clientSecret: process.env["azure_ad_app_registration_client_secret"],
}
};
// create MSAL client instance
const cca = new msal.ConfidentialClientApplication(msal_config);
// acquire token
const clientCredentialRequest = {
scopes: ["https://graph.microsoft.com/.default"],
};
const response = await cca.acquireTokenByClientCredential(clientCredentialRequest);
const token = response.accessToken;
context.log("token:");
context.log(token);
// get all library items - this works
// const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items`;
// get matching library items - this works ONLY if the SharePoint library columns you are filtering on have been indexed!
// const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items?$expand=fields&$filter=fields/ChoiceCol01/Value eq '${choice_col_01_value}' and fields/ChoiceCol02/Value eq '${choice_col_02_value}'`;
// get matching library items and only return selected fields as well as the default fields returned, which it does not seem possible to suppress
// as above - this works ONLY if the SharePoint library columns you are filtering on have been indexed!
const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items?$expand=fields($select=ChoiceCol01,ChoiceCol02,Slot01,Slot02,Slot03)&$filter=fields/ChoiceCol01/Value eq '${choice_col_01_value}' and fields/ChoiceCol02/Value eq '${choice_col_02_value}'`;
// this works when the columns are indexed, but it only returns basic details about the file:
// const graphRequestURL = `https://graph.microsoft.com/v1.0/sites/${target_site_id}/lists/${target_library_id}/items?$filter=fields/ChoiceCol01/Value eq '${choice_col_01_value}' and fields/ChoiceCol02/Value eq '${choice_col_02_value}'`;
context.log("graphRequestURL");
context.log(graphRequestURL);
const graphResponse = await axios.get(graphRequestURL, {
headers: {
Authorization: `Bearer ${token}`
}
});
context.log("This is JSON.stringify(graphResponse.data):");
context.log(JSON.stringify(graphResponse.data));
// return { body: graphResponse.data } <--- this returns [object Object]
return { body: JSON.stringify(graphResponse.data) }
} catch (error) {
context.res = {
status: 500,
body: `Error: ${error.message || error}`
};
}
}
}); |
I'm not sure what you mean by "halting execution". Can you expand on your desired behavior? There's nothing unique to Azure Functions in terms of how the
This is unfortunately a known issue. @brettsam is actively working on this, related to Azure/azure-functions-host#9238. Apparently some improvements to performance made a while ago caused this behavior, and they want to be careful when fixing it to make sure they don't lose the performance gains.
There will be some abstractions necessary, but we are getting closer and closer to "just like Node.js" every day. If you notice any standard features missing, please file a new issue for each feature you would like to use.
v3 to v4 was the biggest change we've done for Node.js in many years. It was inspired by one of the most-upvoted issues for Azure Functions and took at least 2+ years from the first design to the GA release. We have a lot of exciting new features in the works (top of mind is stream support), but nothing nearly as disruptive. We also have no plans to deprecate v3 for a while, so even in this case no one will be "forced" to refactor their code.
You could try
We don't have any direct integrations with Express.js. We have an issue to track something like that, but have no real plans to work on it soon unless we get more feedback asking for it: #16 |
I very much appreciate your thoughtful and detailed response. For reference, I recognize my message was a little 'all over the place', but I was just trying to 'cram understand' Azure Functions over the space of a few days and thought there might be some value in documenting all of the newbie experiences I was having. Thank you again. Also, I can confirm that using |
Can I please ask how I should reference query parameters in a GET request. This doesn't seem to work: const requestQueryParams = request.query;
// get target_site_id from the request query parameters
const target_site_id = requestQueryParams.target_site_id;
// get target_library_id from the request query parameters
const target_library_id = requestQueryParams.target_library_id;
// get choice_col_01_value from the request query parameters
const choice_col_01_value = requestQueryParams.choice_col_01_value;
// get choice_col_02_value from the request query parameters
const choice_col_02_value = requestQueryParams.choice_col_02_value; Whilst this does work: const requestQueryParams = request.query;
// get target_site_id from the request query parameters
const target_site_id = requestQueryParams.get('target_site_id');
// get target_library_id from the request query parameters
const target_library_id = requestQueryParams.get('target_library_id');
// get choice_col_01_value from the request query parameters
const choice_col_01_value = requestQueryParams.get('choice_col_01_value');
// get choice_col_02_value from the request query parameters
const choice_col_02_value = requestQueryParams.get('choice_col_02_value'); Edit: If I am reading it right, it seems that query parameters are in a And the docs for that object are here: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams And therefore I do need to use |
No problem! We'll have to split any action items into separate issues moving forward, but this type of feedback is always helpful and informative! And yes your "Edit" about the query parameters is correct |
I don't know whether my response is going to help someone or not. Unlike NodeJs's traditional const { app } = require('@azure/functions');
app.http('CreatePost', {
methods: ['POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`)
const { name } = JSON.parse(await request.text())
if(!name) {
return {
status: 411,
body: "Bad Request"
}
}
return {
status: 201,
body: `Hello, ${name}!`
};
}
catch(error) {
return {
status: 501,
body: error.message
}
}
}
}) |
Hi @ihnaqi thanks for the sample. You can also use Fyi, the HTTP request docs specific to Azure Functions are here: And here are some docs for the fetch standard, which we are based off of: |
Closing this issue - it covered several areas, but I think the most impactful ones already have separate issues for tracking. If not, please create a new issue for each one. Thanks again! |
I've looked at the official docs:
Azure Functions Node.js developer guide
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=javascript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4
Azure Functions developer guide
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob&pivots=programming-language-javascript
Azure Functions overview
https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview?pivots=programming-language-javascript
Blog Post - Azure Functions: Version 4 of the Node.js programming model is in preview
https://techcommunity.microsoft.com/t5/apps-on-azure-blog/azure-functions-version-4-of-the-node-js-programming-model-is-in/ba-p/3773541
The are no code samples that demonstrate how to access
request.body
.The docs state:
In order to access a request or response's body, the following methods can be used:
arrayBuffer()
returnsPromise<ArrayBuffer>
blob()
returnsPromise<Blob>
formData()
returnsPromise<FormData>
json()
returnsPromise<unknown>
text()
returnsPromise<string>
I am sending a POST request to the Azure Function endpoint in the local environment.
I have tried in both Postman and using curl in Windows 11 terminal.
The headers defined in both cases are:
The body defined in both cases is:
I have tried numerous approaches to access
request.body
.Below are details of one of the approaches that has not worked, using the
json()
method onrequest
.I am choosing to ask about this approach because it seems like it should be the most straightforward.
Environment
-- Node.js (v18.18.1)
-- Azure CLI
-- Azure Functions Core Tools
package.json
Azure Function Code
The text was updated successfully, but these errors were encountered: