Ember app does not fetch json file or fails to read data from it

Hi everyone, I’ve recently started to use Ember and for the first point of start, I started Ember official tutorial on their website. At the section of Working with data, when I try to change the model from the hard-coded model with reading the JSON file provided by the website, it fails to fetch data OR can’t parse data because the webpage doesn’t load any model. Do you have any idea what will be the problem?

this is the hard-coded snippet:

import Route from '@ember/routing/route';

export default class IndexRoute extends Route {
  async model() {
    return {
      title: 'Grand Old Mansion',
      owner: 'Veruca Salt',
      city: 'San Francisco',
      location: {
        lat: 37.7749,
        lng: -122.4194,
      },
      category: 'Estate',
      type: 'Standalone',
      bedrooms: 15,
      image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg',
      description: 'This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests.',
    };
  }
}

And this is after trying to read data from json file:

import Route from '@ember/routing/route';

export default class IndexRoute extends Route {
  async model() {

    let response = await fetch('/api/rentals.json');
    let parsed = await response.json();
    return parsed;
  }
}

Hi @satir1313, welcome to ember! Is there a specific error message you’re seeing in the javascript console?

Also did you follow the steps in this section carefully to get your mock API files in the right place? You want to make sure your public directory in your project looks like this:

public
├── api
│   ├── rentals
│   │   ├── downtown-charm.json
│   │   ├── grand-old-mansion.json
│   │   └── urban-living.json
│   └── rentals.json
...

I ask because it’s easy to miss and I’ve seen one or two others with the same issue and it definitely won’t find the data if those files aren’t there.

Oh also did you try following the verification step it mentions in the guides?

You can verify that everything is working correctly by navigating to http://localhost:4200/api/rentals.json

If you visit that URL and your mock API is configured properly you should see the json

Hi dknutsen, thanks for replay. I have followed all steps as it has been mentioned in the tutorial, even confirming that json file can be reached from http://localhost:4200/api/rentals.json link. It is located in the public/api folder but outside the rental directory as the picture explains. But as soon as I remove the hard-coded snippet and add three lines to read from json file, I have a blank page. I just read something about the port that Ember uses to read from the server and the port it uses to deploy the app. I’m not sure if it is applicable to this problem.

Ah ok it’s been a little while since I’ve read through that section, and when you change the route model over you’re doing more than just going from static => “dynamic” JSON, the rentals file you’re fetching is loading an array of data vs the single record that the static JSON represented. So make sure you’ve followed all the way through this step to adapt your template to match using the {{#each}} helper.

If you’ve done that and it’s still breaking could you post anything that’s in your javascript console? It’s harder to debug without that.

I’ve done all the steps in the section and still have the same issue. it builds the project but nothing was displayed in the page. this link is the github repo that you can download the steps I took to end of the section. https://github.com/satir1313/super-rental.

Also, after changing

    return {
      title: 'Grand Old Mansion',
      owner: 'Veruca Salt',
      city: 'San Francisco',
      location: {
        lat: 37.7749,
        lng: -122.4194,
      },
      category: 'Estate',
      type: 'Standalone',
      bedrooms: 15,
      image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg',
      description: 'This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests.',
    };
  }```


to 



```async model() {
    let response = await fetch('/api/rentals.json');
    let parsed = await response.json();
    return parsed;
  }```



this is the JS console message: 

Error while processing route: index Mirage: Your app tried to GET '/api/rentals.json', but there was no route defined to handle this request. Define a route for this endpoint in your routes() config. Did you forget to define a namespace? Mirage: MirageError@webpack://__ember_auto_import__/./node_modules/miragejs/dist/mirage-esm.js?:808:13
assert@webpack://__ember_auto_import__/./node_modules/miragejs/dist/mirage-esm.js?:792:11
createPretender/</this.unhandledRequest@webpack://__ember_auto_import__/./node_modules/miragejs/dist/mirage-esm.js?:7209:9
handleRequest@webpack://__ember_auto_import__/./node_modules/pretender/dist/pretender.es.js?:1551:14
send@webpack://__ember_auto_import__/./node_modules/pretender/dist/pretender.es.js?:1339:21
fetch/<@webpack://__ember_auto_import__/./node_modules/pretender/dist/pretender.es.js?:525:9
fetch@webpack://__ember_auto_import__/./node_modules/pretender/dist/pretender.es.js?:462:10
model@http://localhost:4200/assets/super-rental.js:680:28
deserialize@http://localhost:4200/assets/vendor.js:21126:19
getModel@http://localhost:4200/assets/vendor.js:61856:24
resolve/<@http://localhost:4200/assets/vendor.js:61652:229
invokeCallback@http://localhost:4200/assets/vendor.js:63721:17
publish@http://localhost:4200/assets/vendor.js:63704:9
@http://localhost:4200/assets/vendor.js:58133:53
invoke@http://localhost:4200/assets/vendor.js:56336:16
flush@http://localhost:4200/assets/vendor.js:56227:13
flush@http://localhost:4200/assets/vendor.js:56424:21
_end@http://localhost:4200/assets/vendor.js:56958:34
Backburner/this._boundAutorunEnd@http://localhost:4200/assets/vendor.js:56627:14

Ah I think we found the culprit. It looks like you have mirage installed, which is awesome, and would actually be easier than using the JSON fixture files for more complex APIs and behaviors, but also requires some config.

If you’re not familiar with mirage, it’s a mock API server and it uses a library called Pretender that intercepts all of your ajax requests and handles them on the mirage “server”. What that error is telling you is that mirage has intercepted your request for /api/rentals.json(instead of letting the ember server serve it from the file system) and tried to handle it, but you haven’t configured a mirage handler for that “route”.

The easiest way to fix this would be to uninstall mirage from your tutorial app and follow the tutorial as written before attempting to learn/use mirage. If you didn’t want to uninstall you could use mirage to do this step instead of using the static files as your “api” (but not that you’ll have to translate steps from the tutorial into mirage convention). Mirage will be easier to leverage with Ember Data, which I believe is in the next section of the tutorial, but you could still use it at this point if you wanted.

At a high level that would look like this:

  • add a mirage model for “rental”
  • add the data from rentals.json to your mirage fixtures
  • load the mirage fixtures in your default mirage scenario
  • change the mirage config prefix to api
  • add a shorthand route handler like server.get('/rentals') to your mirage config
  • change the fetch call in your route to await fetch('/api/rentals');

You’d probably want to skim over the mirage docs before jumping in if you haven’t already. And if you decide to go with the mirage thing feel free to ask any questions that come up along the way!

Thanks, dknutsen for the explanation, I rather remove the mirage from the project for two reasons.

1- I added mirage because I wanted to use that as the second server to run the app. As I mentioned in my previous replies I read something about reading and deploying Ember app over one port, and the article was suggesting to use mirage to solve this problem. (Obviously, it wasn’t the case, because the problem still exist)

2- I removed mirage from my system and remove the mirage folder from Ember app but it was not able to build the project anymore and asking for the mirage config file. I tried to disable to Ember-Cli-mirage in the environment config file but wasn’t really successful.

would you guide me on how to remove mirage from the app? cheers

The main thing you’ll want to do is remove ember-cli-mirage from your package.json and reinstall your npm packages with npm install or yarn install (depending on which package manager you’re using, probably npm). That actually uninstalls the addon from your project and it should build again once you do that.

Could you describe this part in a little more detail? We may be able to get that figured out as well…

I added mirage because I wanted to use that as the second server to run the app. As I mentioned in my previous replies I read something about reading and deploying Ember app over one port, and the article was suggesting to use mirage to solve this problem. (Obviously, it wasn’t the case, because the problem still exist)

Unfortunately I can’t find what I’ve read but it was mentioned to use mirage as the back-end server to return response to ajax request because the Ember 4200 webserver cannot response to ajax request. (I’m not really dived into it, so may not be a true statement). I have removed the mirage from the app and install npm again, but still I have the page without any data from the JSON file. Actually, this is the first point of issue that led me to mirage. JS console is empty!

debugging the issue

What about in your network tab in the developer console? Do you see the request for /api/rentals.json being made successfully?

The next step would be to put a breakpoint into the model hook and inspect the parsed var to see if it’s actually fetching the JSON properly and parsing it properly.

If all that looks good I’d next look at my template code and make sure that the structure the template is expecting matches the data that is coming from the model hook.

And if that looks good you could inspect the component that’s rendering each rental to make sure it’s getting the right props passed.

servers and ports

As to your question about servers and ports I’ll try and explain it all at a high level and hopefully that will help, and feel free to ask any follow ups if something isn’t clear…

First off, Ember is a SPA (single page application) framework. This means that the entire ember app is captured in one (very dynamic) HTML document and its attending javascript and css files. When an ember app is deployed in production the app itself is just a few static files that sit on a static file server somewhere. When you “build” an ember app (which is a prerequisite step to running ember s etc) it smashes all your source files together into a few files and places them in dist (by default). If you look there you’ll probably find an index.html file, some javascript and css assets, and a few other goodies. But again these are all static files, meaning any static file server can serve them.

So one common point of confusion is what the ember “server” is for. The ember server is not meant to handle any sort of typical API responsibilities like connecting to a database or serving dynamic HTTP requests, etc. It’s main purpose is just to serve static files from your project directory in development. You wouldn’t want to use the ember server for actual production deployment as it’s probably not robust or secure enough for that sort of thing. So when we refer to the ember server it’s just a little node script that serves your static files for you while you’re developing as a convenience. In the tutorial you’re mocking an “api” by using static files, but that only really works because the fixture files are static.

The vast majority of real world ember apps will also leverage a backend API of some sort. For example at my company we have a full API built in Ruby on Rails among other things. Our Ember app is hosted in Redis and served via Rails too but you could host it in Amazon S3, Apache, literally anything that could serve static files. The ember app itself doesn’t have to be served by the API server. So then a client browser makes the request for your app, downloads the static assets that make up your app, and “boots” it. Then your app (usually) starts to make requests to your API server. Anyway point being the API server is a separate thing entirely.

During development you’ll usually have your API server running on one port, spin up your ember server (port 4200 by default) perhaps proxied to your API server port, and then visit localhost:4200 in your browser. That request is served by your ember server which just gives the browser your static app assets, and then (if you’re using proxy) proxies your apps requests to the API server.

Mirage of course is another option for using a “fake” server. Note that it does not actually exist outside of your Ember app and just intercepts the requests that are made before they “leave” your browser. It’s an incredible tool for both testing and for prototyping apps. However you wouldn’t want to use it in production in most cases because if nothing else there is no persistence (the mirage database is all in your browser memory so if you refresh the page the server is wiped out).

So anyway, that’s a lot of text but the broad strokes are:

  • ember server isn’t meant to serve data unless it’s static file data like in the tutorial, it’s mainly a convenience for development purposes
  • mirage is a great solution if you’re prototyping out an app that doesn’t have a backend yet, or writing tests (where you want isolation from the actual backend) or want to get up and running with fixtures really fast
  • if you want persistent database-backed data layer you’ll need an API server at some point. Ember Data gives you incredible power and flexibility over matching any backend API to a declarative powerful data store on the front-end, and you can also opt out of Ember Data and use other data fetching/caching methods.

I checked the network tab in Firefox browser and it seems there is GET request for JSON file which is rentals.json, but when debug the projects variable parsed is undefined and does not return any data from JSON. I tried to re-download the file and use the fresh new JSON but did not work.

I have that working on Windows 10, but still not working on Linux, so I assume it’s something related to the Unix environment that I need to figure out.