Open Vikas252 opened 2 years ago
Update: Its weird but when i send a raw data to the above api im getting the response hi
i had changed the serverless.yml in this case to:
service: serverless
provider:
name: azure
region: West US 2
runtime: nodejs14
environment:
VARIABLE_FOO: foo
plugins:
- serverless-azure-functions
package:
patterns:
- "!local.settings.json"
- "!.vscode/**"
functions:
serverless:
handler: src/handlers/hello.handlertest
events:
- http:
path: /
method: ANY
cors: true
- http:
path: /{any+}
method: ANY
cors: true
it was only working with /api/serverless any other routes its showing 404 not found
is it broken or im doing it wrong
I was able to get past this like this:
req.rawBody = req.rawBody || '';
context.res = await handler(context, req);
Also: In the serverless.yaml
, you'll want to change path
to route and (I think) get rid of that + after any
!
Thank you for the response @TaylorBeeston
After updating the code now its showing 204 No Content
in the postman, and no response is been shown.
and had to update the serverless.yml to this
service: serverless
provider:
name: azure
region: West US 2
runtime: nodejs14
environment:
VARIABLE_FOO: foo
plugins:
- serverless-azure-functions
package:
patterns:
- "!local.settings.json"
- "!.vscode/**"
functions:
api:
handler: dist/handler.handler
events:
- http: ANY /
name: res
route: '{*segments}'
authLevel: anonymous
- http: 'ANY {proxy}'
x-azure-settings:
direction: out
name: $return
because i was getting 404 error in the old yml file any help is appreciated been stuck here since forever. Researching
Okay, I've done a bunch of work myself getting this to run, and I've finally just gotten it working correctly both offline and deployed!
To start, I've started using ESBuild to drastically lower the cycle time when deploying. I did that by first adding esbuild:
pnpm i -D esbuild rimraf # You don't have to use pnpm, but I highly recommend it!
Then adding a build script:
// esbuild.mjs
import { build } from 'esbuild';
const startTime = Date.now();
console.log('🎁 Building main bundle...');
const finalBuildObj = {
entryPoints: ['src/index.ts'], // add whatever src files your handler is in!
platform: 'node',
bundle: true,
format: 'cjs',
outfile: 'dist/index.js',
target: 'node12',
plugins: [],
external: [],
minify: true,
};
if (process.env.NODE_ENV !== 'production') {
finalBuildObj.sourcemap = 'inline';
finalBuildObj.minify = false;
}
build(finalBuildObj).then(() => {
console.log(`🎁 Done building main bundle! (${Date.now() - startTime}ms)`);
});
Then with that in place, I wrapped the sls commands to add a build step first:
// package.json
"scripts": {
"test": "echo \"No tests yet...\"",
"build": "rimraf dist && node esbuild.mjs",
"sls-deploy": "pnpm build && sls deploy",
"sls-offline": "pnpm build && sls offline",
"start": "pnpm sls-offline"
},
(Again, you don't have to use pnpm. Just replace pnpm
with npm run
in the scripts)
With this in place, you'll use pnpm start
or pnpm sls-offline
to start offline, and pnpm sls-deploy
to deploy.
The last thing to do is update your serverless file to only include the built code:
# serverless.yaml
package:
patterns:
- "!**"
- dist/**
- app/**
- host.json
- local.settings.json
This change brought my "minimal" azure.zip
from ~500MB down to 704KB! It also allows you to write your function in TS if that's your thing.
One more thing: You'll now be using the built js file inside of dist
and not the source file inside of src
, so you'll need to update your function in your serverless.yaml to point to that:
# serverless.yaml
functions:
app:
handler: dist/index.app
If that part is confusing to you, I can elaborate by showing you my directory structure, as well as what gets put inside of dist
for me!
Okay, with ESBuild out of the way, it should be much easier for you to start testing a config that works for you. I found that adding the manual x-azure-settings
event was giving me 204s locally, just like you, so I axed it. I also found that if I tried changing the routePrefix
in host.json
, it would break when deploying, so make sure that file just looks like this:
// host.json
{
"version": "2.0"
}
So, in the end, my serverless.yaml
file looks like this (comments stripped)
service: azure
frameworkVersion: '3'
provider:
name: azure
region: West US 2
runtime: nodejs12
plugins:
- serverless-azure-functions
package:
patterns:
- "!**"
- dist/**
- app/**
- host.json
- local.settings.json
functions:
app:
handler: dist/index.app
events:
- http: true
route: "{test}"
method: ANY
cors: true
authLevel: anonymous
I have a simple express app that exposes /api/hello
, /api/nice
, and /api/:test
, echoing different things for each route, and they all work successfully for me! Hope this helps you solve your problem!
Just to be extra helpful, I decided to upload my code here!
Thank you for the response and for a working example @TaylorBeeston currently i have changed the folder structure a little bit and goes like app.ts
has server initialization with express handler.ts
has the azure serverless-http then routes.ts
has all the routes when i implemented the same as you said with all the configs i'm getting can not GET /api/sls
app.ts
"use strict"
//const serverless = require('serverless-http')
import express from "express"
//import compression from "compression"
import cors from "cors"
import bodyParser from "body-parser"
import setRoutes from "./routes"
const app = express()
app.use(cors())
app.set("port", 3000)
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*")
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
)
next()
})
async function main(): Promise<any> {
try {
setTimeout(() => {
setRoutes(app)
app.listen(app.get("port"), () => {
console.log(`listening on port ${app.get("port")}`)
})
console.log("Testing")
}, 30000)
} catch (err) {
console.error(err)
}
}
main()
export { app, express }
handler.ts
import serverless from 'serverless-http';
//import { app } from "./app";
import express, { Router, json } from "express"
const app = express()
const router = Router();
router.get("/hello", (req, res) => {
console.log("You are there");
return res.status(200).send("Nice!");
});
const handler = serverless(app,{provider:'azure'})
module.exports.app = async (context, req) => {
req.rawBody = req.rawBody || '';
context.res = await handler(context, req);
}
routes.ts:
//import { express } from "./app"
import express from "express"
import {app} from "./app"
function setRoutes(app): void {
const router = express.Router()
router.route("/serverless").get((req, res) => {
return res.json("hi")
})
router.route("/sls").get((req, res) => {
return res.json("bye")
})
app.use("/api", router)
}
export default setRoutes
not able to hit either hello in the handler.ts or routes in routes.ts
meanwhile i'll be also trying to rectify what silly mistake i would had done
Update: The routes are working in postman but not in normal URL's
With the same code of the issue https://github.com/dougmoscrop/serverless-http/issues/252 I'm getting an request.body error which says undefined.
The context parameter log:
the only one api im using:
the error:
I'm also trying to implement and debug as the azure is untested
Extra added line to debug in hello.js :
this didnt resolve the issue