I am trying to open, read and return an HTML files using Azure functions. I am developing locally and the logs says that the function executed successfully however on the browser I am getting 500 internal server error. Am I doing something wrong in here?
const fs = require('fs');
const path = require('path');
const mime = require('../node_modules/mime-types');
module.exports = function (context, req) {
const staticFilesFolder = 'www/build/';
const defaultPage = 'index.html';
getFile(context, req.query.file);
function getFile(context, file) {
const homeLocation = process.env["HOME"];
if(!file || file == null || file === undefined){
context.done(null,{status:200,body:"<h1>Define a file</h1>",headers:{
"Content-Type":" text/html; charset=utf-8"
}});
}
fs.readFile(path.resolve(path.join(homeLocation, staticFilesFolder, file)),
(err, htmlContent) => {
if (err) {
getFile(context, "404.html");
}
else {
const res = {
status: 200,
body: htmlContent,
headers:{
"Content-Type": mime.lookup(path.join(homeLocation, staticFilesFolder, file))
}
}
context.done(null,res);
}
})
}
};
Note
I am sure that 404.html exists and index.html exists. When I log the contents of htmlContent it is giving the correct output.
functions.json
{
"disabled": false,
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"methods":["get"],
"route":"home",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
Response on Chrome
If I removed "Content-Length" header the status code changes to 406.
Update 1 The code seems to be running normally on Azure Portal but it is not working when running it locally.
It looks like you are combining two methods of returning data from an http triggered function(context.res and context.done()): https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node#accessing-the-request-and-response
Since you are using context.res, try removing context.done();
You are making an incorrect use of context.res, you shouldn't be overwriting it but instead leveraging the methods provided by the Response class provided in the Azure NodeJS worker. If you are using using VSCode you'll get intellisense for these methods. Otherwise see: https://github.com/Azure/azure-functions-nodejs-worker/blob/dev/src/http/Response.ts
Your code should look something like this instead.
context.res.setHeader('content-type', 'text/html; charset=utf-8')
context.res.raw(htmlContent)
Using context.res.raw or context.res.send will already perform the context.done call for you.
Make sure you use content-type=text/html; charset-utf8 instead of content-type=text/html or you'll trigger an issue with the returned content-type. Instead of returning content-type=text/html you end up getting content-type=text/plain which will fail to render your html.
Addressed on: https://github.com/Azure/azure-webjobs-sdk-script/issues/2053
Related
I'm using External Secrets to sync my secrets from azure. And now I need a programmatic way to trigger the sync. With kubectl the command is
kubectl annotate es my-es force-sync=$(date +%s) --overwrite
So, I try to use k8s js sdk to do this. I can success fully get the External Secret
await crdApi.getNamespacedCustomObject("external-secrets.io", "v1beta1", "default", "externalsecrets", "my-es")
However, when I try to update it with patchNamespacedCustomObject, it always tells me "the body of the request was in an unknown format - accepted media types include: application/json-patch+json, application/merge-patch+json, application/apply-patch+yaml"
Here's my code
const kc = new k8s.KubeConfig();
kc.loadFromString(kubeConfig);
const crdApi = kc.makeApiClient(k8s.CustomObjectsApi);
let patch = [{
"op": "replace",
"path": "/metadata/annotations",
"value": {
"force-sync": "1663315075"
}
}];
await crdApi.patchNamespacedCustomObject("external-secrets.io", "v1beta1", "default", "externalsecrets", "my-es", patch);
I am referring their patch example here
const options = {
"headers": {
"Content-type": k8s.PatchUtils.PATCH_FORMAT_JSON_PATCH
}
};
is still required.
Hello I am testing out AWS Lambda and I keep getting the boilerplate output in my logs. I am new to AWS and this might be an easy fix but I have not been able to find a solution even in the docs.
Here is my index.js file
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Different OutPut'),
};
return response;
};
And here is the log output in the lambda console:
Response:
{
"statusCode": 200,
"body": "\"Hello from Lambda!\""
}
Request ID:
"dc746181-ec98-4c8a-8e09-c6157da669cb"
I am expecting to have 'Different OutPut' as the body.
Also here are the role permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
Thank you for any advice.
If you keep getting Hello from Lambda! then it probably means that you haven't deployed the function before you test/execute it.
You have to explicitly deploy (orange Deploy button) function after each change in the code, so that changes take effect.
The other possibility is that you are executing wrong/old version of your function. In this case you have to explicitly select correct version if you have created any versions of your function.
I want to define the response structure of my requests in the simplest way, and the first thing that comes in my mind to do this is a middleware.
My endpoints are returning the response content correctly:
{{base_url}}/users returns a list of users:
{
[
{
"id": 44,
"name": "some name"
[...]
}
]
}
What I want to do (in all requests) is to add the fields status and data (or any other I'd like to add), like this:
{
"status": 200,
"data": [
{
"id": 44,
"name": "some name"
[...]
}
]
}
I've created a middleware that waits for the resolution but I'm not able to get the content nor add some property to it.
[...]
async handle ({request, response}, next) {
await next()
const content = response._lazyBody.content
content.status = response.response.statusCode
}
[...]
I know this will not work but I want something similar to this. I've looked in Adonis docs and forum, but no answers fit to my needs.
Any help will be welcome
You can extend Response By extending the core. The simplest way is to create a file inside start folder and name it hooks.js and copy and paste the content below inside it:
const { hooks } = use('#adonisjs/ignitor')
const Response = use('Adonis/Src/Response')
hooks.after.providersBooted(() => {
Response.macro('customJson', function (status, data) {
this.status(status).json({
status,
data
})
})
})
this piece of code extends the Response module and add customJson method to it which takes two arguments, status and data, and send them back to the client.
And here you can see how to use it:
Route.get('/users', async ({ response }) => {
let status = ''// whatever you want
let data = ''// whatever you want
return response.customJson(status, data)
})
My Code looks like this :-
var vision = require('#google-cloud/vision');
handleSubmit = () =>{
console.log("encoded string submitted=",this.state.files);
this.useVisionCloud();
}
useVisionCloud = () =>{
const client = new vision.ImageAnnotatorClient();
const request_body = {
"requests": [
{
"image": {
"content": this.state.files
},
"features": [
{
"type": "TEXT_DETECTION"
}
]
}
]
};
client.textDetection(request_body).then(response => {
console.log("text got=",response);
// doThingsWith(response);
})
.catch(err => {
console.log("error got=",err);
});
}
I already tried setting environment variable but didn't work .
I have also created service account and downloaded the file.json
but dont know how to use it for authentication
im getting the following error :-
Uncaught Error: {"clientConfig":{},"port":443,"servicePath":"vision.googleapis.com","scopes":["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/cloud-vision"]}You need to pass auth instance to use gRPC-fallback client in browser. Use OAuth2Client from google-auth-library.
on triggering a post request to Google API .
Final Query is :- I am not able to understand how to authenticate API so that i can further use it to detect text in my images
Set the env variable eg:
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
I would recommend having a separate backend that calls vision api. Then have the javascript code in your browser call your backend.
I have made an target project script as instructed by google in the documentation and followed all the steps for deploying as a API Executable.Enabled the Google apps script execution API also.
In documentation, they have mentioned a Execution API's run method. By using this we can call the projects method. i don't know how to use this in GAS.
This is the target project's script,
/**
* The function in this script will be called by the Apps Script Execution API.
*/
/**
* Return the set of folder names contained in the user's root folder as an
* object (with folder IDs as keys).
* #return {Object} A set of folder names keyed by folder ID.
*/
function getFoldersUnderRoot() {
var root = DriveApp.getRootFolder();
var folders = root.getFolders();
var folderSet = {};
while (folders.hasNext()) {
var folder = folders.next();
folderSet[folder.getId()] = folder.getName();
}
return folderSet;
}
I'd tried following method to call execution API's run method, but it required access token, how can i get the access token in this code.
var access_token=ScriptApp.getOAuthToken();//Returning a string value
var url = "https://script.googleapis.com/v1/scripts/MvwvW29XZxP77hsnIkgD0H88m6KuyrhZ5:run";
var headers = {
"Authorization": "Bearer "+access_token,
"Content-Type": "application/json"
};
var payload = {
'function': 'getFoldersUnderRoot',
devMode: true
};
var res = UrlFetchApp.fetch(url, {
method: "post",
headers: headers,
payload: JSON.stringify(payload),
muteHttpExceptions: true
});
But in response i'm getting this,
{
"error": {
"code": 401,
"message": "ScriptError",
"status": "UNAUTHENTICATED",
"details": [
{
"#type": "type.googleapis.com/google.apps.script.v1.ExecutionError",
"errorMessage": "Authorization is required to perform that action.",
"errorType": "ScriptError"
}
]
}
}
How can i solve this? Code explanation would be appreciable. Thank you.
How about this sample script? From your question, I could know that you have already done deploying API Executable and enabling Execution API. In order to use Execution API, also an access token with scopes you use is required as you can see at Requirements. Have you already retrieved it? If you don't have it yet, you can retrieve it by checking the Auth Guide. By preparing these, you can use Execution API.
Following sample is for run getFoldersUnderRoot() in the project deployed API Executable. Please copy and paste this sample script to your spreadsheet script editor. Before you use this, please import your access token and script ID of the project deployed API Executable to the script.
Sample script :
var url = "https://script.googleapis.com/v1/scripts/### Script ID ###:run";
var headers = {
"Authorization": "Bearer ### acces token ###",
"Content-Type": "application/json"
};
var payload = {
'function': 'getFoldersUnderRoot',
devMode: true
};
var res = UrlFetchApp.fetch(url, {
method: "post",
headers: headers,
payload: JSON.stringify(payload),
muteHttpExceptions: true
});
Result :
Here, the result of getFoldersUnderRoot() is returned as follows.
{
"done": true,
"response": {
"#type": "type.googleapis.com/google.apps.script.v1.ExecutionResponse",
"result": {
"### folder id1 ### ": "### folder name1 ###",
"### folder id2 ### ": "### folder name2 ###",
}
}
}