How to use a custom Express server with Ember CLI? - ember-cli

I'm using Ember CLI 0.0.36. When I run ember server in my project folder, my understanding is that a server buried in some Brocoli process gets started. However I would like to program a custom Express server and have my app point to that Node.js code for its backend. How would I go about doing that within the Ember CLI framework?
UPDATE:
Following #user3155277's answer, I added an adapter file like so:
app-name/app/adapters/application.js:
import DS from 'ember-data';
export default DS.RESTAdapter.reopen({ namespace: 'api' });
I created an Express server that I put at the root of my app:
app-name/server.js:
var express = require("express"),
app = express(),
path = require("path");
app.get("/api/test", function(req, res) {
res.json({
hello: "world"
});
});
var server = app.listen(8147);
In the Ember app, my index route is defined as so:
app-name/app/routes/index.js:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return Ember.$.getJSON("/api/test").then(function(data) {
return data;
});
}
});
On the command line I then start the server like so:
ember serve --proxy http://localhost:8147/
I get the following error:
version: 0.0.35-master-86abdb11ba
Proxying to http://localhost:8147/
object is not a functionTypeError: object is not a function
at Class.module.exports.Task.extend.start (D:\ember-cli\lib\tasks\server\express-server.js:41:43)
at Class.module.exports.Task.extend.run (D:\ember-cli\lib\tasks\serve.js:40:23)
at Class.module.exports.Command.extend.run (D:\ember-cli\lib\commands\serve.js:35:18)
at Class.Command.validateAndRun (D:\ember-cli\lib\models\command.js:74:15)
at CLI.<anonymous> (D:\ember-cli\lib\cli\cli.js:33:20)
at tryCatch (D:\ember-cli\node_modules\rsvp\dist\commonjs\rsvp\-internal.js:163:16)
at invokeCallback (D:\ember-cli\node_modules\rsvp\dist\commonjs\rsvp\-internal.js:172:17)
at publish (D:\ember-cli\node_modules\rsvp\dist\commonjs\rsvp\-internal.js:150:13)
at flush (D:\ember-cli\node_modules\rsvp\dist\commonjs\rsvp\asap.js:51:9)
at process._tickCallback (node.js:419:13)Livereload server on port 35729

This is actually pretty simple with Ember CLI 0.0.40:
Create folder structure
ember new my-app
Go into the newly created folder
cd my-app
Generate api-stub* (see update)
ember generate api-stub my-server
This latter command creates a server folder with an index.js file and a routes folder with a my-server.js file.
Open my-server.js file and you see:
module.exports = function(app) {
var express = require("express");
var myServerRouter = express.Router();
myServerRouter.get("/", function(req, res) {
res.send({my-server:"something"});
});
app.use("/api", myServerRouter);
};
All you need to do then is to change that file. If the Ember app makes calls to /api/hamsters and /api/project, edit as follows:
module.exports = function(app) {
var express = require("express");
var myServerRouter = express.Router();
myServerRouter.get("/hamsters", function(req, res) {
res.send({ ... });
});
myServerRouter.get("/project", function(req, res) {
res.send({ ... });
});
app.use("/api", myServerRouter);
};
To start the server (from project's root):
ember server
Make sure you have updated node.js to the latest version as well.
Updates
As of Ember CLI 0.0.41 (via this PR) api-stub has been renamed http-mock.

I started playing with ember cli so i'm not sure but i found the following:
https://github.com/dockyard/ember-cli-plus-backend/tree/rails-served-html/frontend/api-stub
Basically you should proxy your express server to the same port as your ember-cli (so then you don't have to deal with jsonp issue)
Set the method to 'proxy' and define the proxyURL to pass all API requests to the proxy URL.
UPDATE:
1.Generate adapter ember generate adapter application
2.Make api namespace - fill the created file with the following code:
export default DS.RESTAdapter.reopen({
namespace: 'api'
});
3.Start the server with ember serve --proxy http://localhost:1337/ (this will proxy all your request to localhost:4200 to 1337
4.Make routes in your express app prefixed by /api
Hope it helps

Related

Nuxtjs - Error 404 with post request in production while working in local

I'm actually trying to use nuxt-mail in a personnal project,
During my development phase, I receive all my testing mails. And from there I did the following adjustments to do the exact same request from my builded site :
//nuxt.config.js
env: {
baseUrl:
process.env.NODE_ENV === 'dev'
? 'http://localhost:3000'
: 'https://my-domain.netlify.app'
},
My code when using the 'send' function :
this.$axios.$post(process.env.baseUrl + "/mail/send", {
config: 'contact',
from: document.getElementById('input-2').value,
subject: document.getElementById('subject').value,
text: "This is a text message",
})
It continues to work well with localhost/3000/mail/send but I have a 404 error once I build my site and using https:/ /my-domain.netlify.app/mail/send :
POST https://my-domain.netlify.app/mail/send [HTTP/2 404 Not Found 186ms]
Uncaught (in promise) Error: Request failed with status code 404
I'm actually struggling to solve this problem, am I missing something ?
Alright, so if your target is static, you can only do yarn generate.
If you do have the default, aka target: server, you can only yarn build.
Then, as talked about it a bit here: Sending mail in Nuxt.js with nuxt-mail
You cannot use a Node.js package in a static environment, so neither yarn generate nor Netlify will help you here. You need to yarn build and host it on something like Heroku.
One last step that you can do, is to try it locally with the following:
target: server
yarn build
yarn start
make your POST call with Postman or alike
If it does not work here, it is a code issue and you can look into the hosting one.
If it does work locally, you can proceed to the hosting issue that you'll face.
Well you just misunderstood the env field in the nuxt.config.js file.
That env field is passed to the $config Object of the Nuxt App and not passed to process.env.
What you want is to set the BaseUrl for the Axios Module
// nuxt.config.js
axios: {
baseURL: process.env.NODE_ENV === 'dev'
? 'http://localhost:3000'
: 'https://my-domain.netlify.app'
},
// or provide a runtime config
// server and clientside
publicRuntimeConfig: {
axios: {
browserBaseURL: process.env.BROWSER_BASE_URL
}
},
// serverside only
privateRuntimeConfig: {
axios: {
baseURL: process.env.BASE_URL
}
},
Edit:
Also when calling axios just do it like that if you implement the above changes
this.$axios.$post("/mail/send", {
// ... the rest of your code

Running flutter web app locally without android studio

I have a flutter app using Firebase's cloud firestore. I've done the web build and running it on Chrome through Android Studio works well. I would like to share my web app progress to my client but don't want to host it (because it's not finished yet). Hence I'd like to find a way to run it locally the same way you can do it with Android Studio but without needing to install Android Studio (and hopefully not requiring to install flutter either), so that I can send the build file to my client and they can run it in their machine (with a script to start the web server locally and run the web app).
I have tried the following script included inside the web build folder (where the index.html is)
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from httplib import HTTPResponse
from os import curdir,sep
#Create a index.html aside the code
#Run: python server.py
#After run, try http://localhost:8080/
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.path = '/index.html'
try:
sendReply = False
if self.path.endswith(".html"):
mimeType = 'text/html'
sendReply = True
if sendReply == True:
f = open(curdir + sep + self.path)
self.send_response(200)
self.send_header('Content-type', mimeType)
self.end_headers()
self.wfile.write(f.read())
f.close()
return
except IOError:
self.send_error(404,'File not found!')
def run():
print('http server is starting...')
#by default http server port is 80
server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, RequestHandler)
try:
print 'http server is running...'
httpd.serve_forever()
except KeyboardInterrupt:
httpd.socket.close()
if __name__ == '__main__':
run()
But when opening http://localhost:8000 on Chrome I get a blanc page and the console shows the errors:
Failed to load resource: net::ERR_EMPTY_RESPONSE main.dart.js:1
Failed to load resource: net::ERR_EMPTY_RESPONSE manifest.json:1
Failed to load resource: net::ERR_EMPTY_RESPONSE :8080/favicon.png:1
I also tried NPM local-web-server by running ws --spa index.html but just getting a ERR_EMPTY_RESPONSE response.
This is what I have in my build/web after running flutter build web:
How can I create a local server where I can host my web app locally and run it locally without hosting it on the internet?
as you mentioned in the comment here you go.
Create a file app.js with the following:
const express = require('express')
const app = express()
const port = 8000
app.get('/', (req, res) => {
console.log('getting request')
res.sendFile('website/y.html',{root:__dirname})
})
app.use(express.static(__dirname + '/website'))
app.use((req, res)=>{
res.redirect('/')
})
app.listen(port, () => {
console.log(`app listening at http://localhost:${port}`)
})
Here my website files exist at website folder and my entry point is y.html.
Set the static file directory (your website page) and then serve the .html for the root request
example project: https://github.com/ondbyte/website
Finally, to run it open terminal and move to the root folder. Then do
npm init
npm install express --no-save
node app.js
Here is the more simpler way. NO NEED to setup server
open your Build/web folder in vscode.
install Live server Plugin in vscode.
hit Golive Button
Here you go your flutter web app would be running locally without android studio.

Is there a way to proxy requests in Parcel as in Webpack?

In Webpack there is an ability to proxy backend requests through proxy setting in the config file. That allows me to develop a front-end part of my app with webpack-dev-server with HMR while webpack-dev-server and my app server run on different ports on my localhost. There is also a development server in Parcel which is run by default command parcel index.html on port 1234. Is there a way to run both Parcel dev server and proxy requests to my app server?
I found a solution that suggests using Express middleware for that. But that doesn't solve the problem completely and cleanly. What if my backend runs Django? How should I use Parcel dev server then?
This is currently not supported directly, see the open pull-request https://github.com/parcel-bundler/parcel/pull/2477
However, https://github.com/parcel-bundler/parcel/issues/55 and lists various solutions involving a simple wrapper, such as:
for http-proxy-middleware >= 1.0.0 (Published 2/2020):
const Bundler = require('parcel-bundler');
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use(createProxyMiddleware('/api', {
target: 'http://localhost:3000'
}));
const bundler = new Bundler('src/index.html');
app.use(bundler.middleware());
app.listen(Number(process.env.PORT || 1234));
For older http-proxy-middleware (versions 0.x):
const Bundler = require('parcel-bundler');
const express = require('express');
const proxy = require('http-proxy-middleware');
const app = express();
app.use('/api', proxy({
target: 'http://localhost:3000/api'
}));
const bundler = new Bundler('src/index.html');
app.use(bundler.middleware());
app.listen(Number(process.env.PORT || 1234));
There is an npm module called parcel-proxy-server that might help. I have tried it myself, and it works quite well for my project.
From the documentation:
Create a file, e.g. server.js
const ParcelProxyServer = require('parcel-proxy-server');
// configure the proxy server
const server = new ParcelProxyServer({
entryPoint: './path/to/my/entry/point',
parcelOptions: {
// provide parcel options here
// these are directly passed into the
// parcel bundler
//
// More info on supported options are documented at
// https://parceljs.org/api
https: true
},
proxies: {
// add proxies here
'/api': {
target: 'https://example.com/api'
}
}
});
// the underlying parcel bundler is exposed on the server
// and can be used if needed
server.bundler.on('buildEnd', () => {
console.log('Build completed!');
});
// start up the server
server.listen(8080, () => {
console.log('Parcel proxy server has started');
});
then call node server.js to run your proxy, and the default parcel command.

Connecting Aurelia with backend API

Context: I'm starting a new project for my company. It's been many years since I've done some web development and decided to build it using the latest platforms (so I'm a still new to all of this).
Current stack:
Aurelia frontend (running on localhost:9000)
Backend REST API using ExpressJS (running on localhost:8000)
PostGreSQL database running on AWS, providing data for the backend
Question: I can't seem to connect my frontend with my backend properly.
Here is my code:
import {inject} from "aurelia-framework";
import {HttpClient} from "aurelia-http-client";
#inject(HttpClient)
export class Login {
constructor(httpClient){
this.http = httpClient;
}
signIn() {
const url = 'http://localhost:8000/api/user/demo/test';
this.http
.get(url)
.then(data => {
console.log("data");
console.log(data);
})
.catch(error => {
console.log('Error getting ' + url);
console.log(error);
});
};
}
This always end up in the catch block, with a "response: ProgressEvent"
If I put the url in the browser I get a proper JSON:
{"status":"success","data":[],"message":"Retrieved ALL users"}
The code above only works for 'local' content, i.e. localhost:9000. As soon as I need content from somewhere else I get this error. What am I missing?
I think that CORS is not allowing you to access localhost:8000 from localhost:9000. To solve this, you should enable your ExpressJS server to accept CORS requests from localhost:9000 (or all hosts using a wildcard "*").
Look into these resources:
https://enable-cors.org/server_expressjs.html
https://github.com/expressjs/cors
Or search Google for 'expressJS cors'.

How to enable CORS in an EmberJS application?

I have an EmberJS application that uses ember-data to access data via a REST API. The REST API is running on the same machine but on a different port (although this probably applies to REST API's that are served from another domain.
When I go to the URL localhost:4200/items I get the following error in the Firefox console:
Content Security Policy: The page's settings blocked the loading of a resource at http://localhost:7654/api/items ("connect-src http://localhost:4200 ws://localhost:35729 ws://0.0.0.0:35729 http://0.0.0.0:4200").
I tried installing ember-cli-cors but nothing changed. I also tried the solution at http://discuss.emberjs.com/t/ember-data-and-cors/3690, but that didn't work either. That discussion was from 2013, so that's not a huge surprise.
The REST API is written in python using Flask and Flask-cors. Using the network tab I can see that the request is being sent, and the data being sent back, but the error is still there. The header Access-Control-Allow-Origin is set to http://localhost:4200 in the response, as expected.
app/router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
export default Router.map(function() {
this.route('items');
});
app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: 'api',
host: 'http://localhost:7654',
});
app/routes/items.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('item');
}
});
app/models/item.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr(),
});
app/templates/items.hbs
{{#each item in items}}
{{ item.name }}<br>
{{else}}
<p>No items</p>
{{/each}}
{{outlet}}
This is a CSP issue not CORS
Inside config/environment.js find the ENV.contentSecurityPolicy and add http://localhost:7654 to your 'connect-src' key
e.g.
ENV.contentSecurityPolicy = {
// ... other stuff here
'connect-src': "'self' http://localhost:7654"
}
You will probably need a different setting for your production environment as well.
For testing environment you can use proxy.
ember s -proxy http://localhost:7654
So all back-end request goes to your server which is running on port 7654.