Can Bunjs be used as a backend server? - bun

Now we can start a react App with bun as a server
Can we use Bunjs as complete backend server?
For Example, Can bun run this code?
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('hello world')
})
app.listen(3000)

I guess Bun does not YET implement all node.js api's. I tried http and it seems currently missing. And as much I understand it currently has its own built-in HTTP server.
Check the "Getting started" section on -> https://bun.sh/
A sample server:
export default {
port: 3000,
fetch(request) {
return new Response("Welcome to Bun!");
},
};
(This example reminds me of serverless functions.)
As this is the case, it seems you can not rely on Node.js http, or most probably any server framework like express.
At least for now, bun's roadmap (https://github.com/oven-sh/bun/issues/159) shows a line, which I am not sure is talking about node's http server or sth. else about Bun's own server.
Once complete, the next step is integration with the HTTP server and
other Bun APIs

Bun api is really different from nodejs, I created a library called bunrest, a express like api, so new user does not need to learn much about bun.
Here is how to use it
Install the package from npm
npm i bunrest
To create a server
const App = require('bunrest');
const server = new App.BunServer();
After that, you can call it like on express
server.get('/test', (req, res) => {
res.status(200).json({ message: 'succeed' });
});
server.put('/test', (req, res) => {
res.status(200).json({ message: 'succeed' });
});
server.post('/test', (req, res) => {
res.status(200).json({ message: 'succeed' });
});
To start the server
server.listen(3000, () => {
console.log('App is listening on port 3000');
});

Other way is using Hono: https://honojs.dev/
There is a working demo: https://github.com/cachac/bun-api
Import package and set new instance
import { Hono } from 'hono'
const app = new Hono()
Create routes:
Instead of NodeJs res.send(), use c.json({})
app.get('/hello', c => c.json({ message: 'Hello World' }))
export and run api server:
export default {
fetch: app.fetch,
port: 3000
}

Related

MERN Project Deploy to Heroku, axios function fail

I tried to deploy my local running MERN stack project to Heroku. The UI is showing fine, but the axios calls continue to fail. Here is how I wrote the axios URL.
axiosConfig.js:
import axios from "axios";
const api = axios.create({
baseURL: process.env.REACT_APP_BASE_URL // or process.env.BASE_URL if not using CRA
});
export default api
Arrival.js:
import api from '../../axiosConfig';
const Arrivals = () => {
const baseURL = api || "http://localhost:5000";
useEffect(() => {
axios.get(baseURL + '/flights/arrivals/' + timeDuration)
.then((response) => {
setData(response.data);
console.log(data)
})
.catch(err => {
console.log(err)
})
}, [timeDuration]);//eslint-disable-line
When I call the api, the network showing it's tring to get from:
https://minions-airport-202.herokuapp.com/function()%7Breturn%20e.apply(t,arguments)%7D/flights/arrivals/28800000
And it is getting 500 Internal Server Error. Any idea why?

How to Connect to localhost Mongodb using an emulator?

First time making a question here so sorry for anything that isn't clear.
Basically I took a react course that set up a functional site with crud and now I'm trying to set up something similar in react native. So I'm new to react, react-native, and mongodb; basically everything I'm working with. This is for self study as well, so just trying to expand my skills.
This is the code that works in my react app under server.js from the backend
const client = await MongoClient.connect("mongodb://localhost:27017", {
useUnifiedTopology: true,
});
//api inbetween these two
app.listen(8000, () => console.log("Listening on port 8000"));
On my front end in my package.json I have this
"proxy": "http://localhost:8000/",
from my understanding this basically lets my frontend "proxy"/mask itself as if its coming from port 8000. Then I can call it using a url like below.
useEffect(() => {
const fetchData = async () => {
const result = await fetch(`/api/articles/${name}`);
const body = await result.json();
setArticleInfo(body);
};
fetchData();
}, [name]);
In my react-native app I get an unhandled promise rejection and in postman I get an internal 500 error with no associated error seems to be null since nothing is printed. Doing some research, I think the issue is because now I'm running this app on an emulator so I think it can't identify the main computer or localhost?
I've tried changing the localhost part of the address to my ipv4 address, to the expo connection url, 0.0.0.0, and also to what I believe is the android localhost 10.0.2.2 but none of them seems to work. example of android localhost change.
server.js
const client = await MongoClient.connect("mongodb://10.0.2.2:27017", {
useUnifiedTopology: true,
});
//api inbetween these two
app.listen(8000, () => console.log("Listening on port 8000"));
package.json
"proxy": "http://10.0.2.2:8000/",
When it's set to 10.0.2.2 postman times out and the app still has the unhandled promise error.
When it's set to 0.0.0.0 postman returns a 500 error with no details and the app still has the unhandled promise error.
When it's set to the expo url it straight up doesn't work.
When its set to my ipv4 address I get the unhandled promise and postman returns this error
"error": {
"name": "MongoServerSelectionError",
"reason": {
"type": "Single",
"setName": null,
"maxSetVersion": null,
"maxElectionId": null,
"servers": {},
"stale": false,
"compatible": true,
"compatibilityError": null,
"logicalSessionTimeoutMinutes": null,
"heartbeatFrequencyMS": 10000,
"localThresholdMS": 15,
"commonWireVersion": null
}
}
Posts I've looked at
Connect to MongoDB Atlas Cluster db with react-native app
Mongodb connection with react native form
React Native / Expo : Fetch throws “Network request failed”
why do we use 10.0.2.2 to connect to local web server instead of using computer ip address in android client
Your useEffect is wriiten wrong
Write it like this
useEffect(() => {
GetArticles(); // Called whenever there's a change in name
}, [name]);
// Create this function outside useEffect
const GetArticles = async () => {
try {
// Also in your fetch you have yo write url like this
const result = await fetch(
`http://${YOUR_IPv4_ADDRESS}:8000/api/articles/${name}`
);
const body = await result.json();
setArticleInfo(body);
} catch (error) {
console.log(error);
}
};
Also this is 100% correct
const client = await MongoClient.connect("mongodb://localhost:27017", {
useUnifiedTopology: true,
});
//api inbetween these two
app.listen(8000, () => console.log("Listening on port 8000"));
Don't change it to this
const client = await MongoClient.connect("mongodb://10.0.2.2:27017", {
useUnifiedTopology: true,
});
//api inbetween these two
app.listen(8000, () => console.log("Listening on port 8000"));

I'm getting a Web Push Error Code Status 403, which is driving me nuts, because its telling me to use firebase. What's going on?

I keep getting a WebPush Error (Status Code 403) fro Chrome for a PWA I'm building and the body says that I need to use the VAPID server key from the 'firebase console' but I used nodes Web-Push library to generate the VAPID Keys, whats going on? Do I have to use firebase to build PWAs in Chrome?
Here's the Error Message I'm getting from the browser when I send a push notification:
name: 'WebPushError',
message: 'Received unexpected response code',
statusCode: 403,
headers:
{ 'content-type': 'text/plain; charset=utf-8',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '0',
date: 'Thu, 31 Oct 2019 19:59:02 GMT',
'content-length': '194',
'alt-svc':
'quic=":443"; ma=2592000; v="46,43",h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
connection: 'close' },
body:
'the key in the authorization header does not correspond to the sender ID used to subscribe this user. Please ensure
you are using the correct sender ID and server Key from the Firebase console.\n',
endpoint:
'https://fcm.googleapis.com/fcm/send/exXmW3OFOTY:APA91bEKW_vxnvOZohog34pprDH6XvBsxtfnUpBdYY7z_7q4GZGa4wrmtBBg4kTRwLtgy3lNpCs8SMlvOr4nY-Fu_4zUus6zEJh69581Ier14QZxkEEVXyZHKRaZcmHa3zmbZRB4VD7Z
and here's the code that is running my node server:
//Handle imports
const express = require('express')
const cors = require('cors')
const bodyParser = require('body-parser')
const webPush = require('web-push')
const vapidKeys = require('./vapid.json')
const path = require('path')
//Setup application
const app = express()
app.use(cors())
app.use(bodyParser.json())
app.use('/static', express.static(path.join(__dirname,'frontend')))
const port = 8080
//Set up webpush
webPush.setVapidDetails(
'mailto: <email>',
vapidKeys.publicKey,
vapidKeys.privateKey
)
const pushOptions = {
proxy: '<proxy>'
}
//setup Push Notification
const sendNotification = (subscription, dataToSend='') => {
webPush.sendNotification(subscription, dataToSend, pushOptions).catch(error => { console.log('Damn it: ', error.message, '||', error)
})
}
//Server Routes Defined
app.get('/', (req, res) => res.sendFile('index.html', { root: './' }))
//Setup Database Methods
const dummyDb = {subscription: null}
const saveToDatabase = async subscription => {
dummyDb.subscription = subscription
}
//Other Server Routes
app.post('/save-subscription', async (req, res) => {
const subscription = req.body
await saveToDatabase(subscription)
console.log('subscribed!')
res.json({message: 'success'})
})
app.get('/send-notification', (req, res) => {
const subscription = dummyDb.subscription
const message = 'hello world'
sendNotification(subscription, message)
res.json({message: dummyDb.subscription})
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I have node.js express, postgres, angular 8 app.
I had the same problem and I got it working by adding the "gcm_sender_id": in the manifest.webmanifest file (or manifest.json I also used firebase generated public and private keys.
your gcm_sender_id is your project id in google cloud or firebase sender id
Same situation and almost lost my sanity. I tried inserting gcm_sender_id with a Firebase senderId and worked finally. I didn't have a Firebase account, but I was able to create a project in seconds and my senderId was ready to be used in the messaging settings.
But a caveat: After my modification in the manifest.json (in my case) in the root's folder, it was needed to uninstall the current service worker and restart my React project. Then I followed again all steps back by asking permissions and subscribe the user and finally trigger a push notification.
During my heat researches for a solution, I found that gcm_sender_id is also used to send and validate push messages from other browsers. According to Google Web Updates:
For Chrome prior to version 52, Opera Android and the Samsung Browser,
you're also still required to include a 'gcm_sender_id' in your web
app's manifest.json. The API key and sender ID are used to check
whether the server making the requests is actually allowed to send
messages to the receiving user.

Connecting Vue to Express - 404 Not Found

I'm creating a simple app to practice connecting Vue to an Express server. I have a form that I'm attempting to send to the back end, but I can't seem to get my data to the back-end.
The error I'm receiving is:
POST http://localhost:8080/login 404 (Not Found)
My best guess is that the method in my Vue can't find a matching route on my server? If so, I'm confused as I have a route for login.
In my Vue script:
const axios = require('axios');
export default {
data: function() {
return {
user: {
email: '',
password: ''
}
}
},
methods: {
sub() {
var user = {
email: this.user.email,
password: this.user.password
}
axios.post('/login', user)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
}
On by back-end:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '..')));
app.post('/login', function(req, res) {
console.log("Server HIT!!!!!!!!!!!!!!!!!!!!")
})
app.get('*', function (req, res) {
return res.sendFile('../index.html');
});
app.listen(3000);
console.log('Express server listening on port 3000');
Express is running on another port than your vue application. Vue is standard http which is 8080, but express runs on 3000 with this line:
app.listen(3000);
You are sending the request to /login, which from the point of view of your frontend is http://localhost:8080, but that's not where express is available.
Basically all you have to do is send the request to http://localhost:3000/login, simple as that.
By default express do not allow cross origin request i.e CORS. You have to enable it by setting middleware. add below lines in you server file and must be before declaring any routes
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}