---
title: Bitovi Academy - Fetching Data with Services
description: Learn how to write an Angular service that gets data from the server.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React Native ](https://www.bitovi.com/academy/learn-react-native.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us) 
    - [ Why Angular? ](https://www.bitovi.com/academy/learn-angular/why-angular.html?hsLang=en-us)
    - [ Generate an App ](https://www.bitovi.com/academy/learn-angular/building-our-first-app.html?hsLang=en-us)
    - [ Creating Components ](https://www.bitovi.com/academy/learn-angular/creating-components.html?hsLang=en-us)
    - [ Creating Pipes ](https://www.bitovi.com/academy/learn-angular/creating-pipes.html?hsLang=en-us)
    - [ Adding Routing ](https://www.bitovi.com/academy/learn-angular/adding-routing.html?hsLang=en-us)
    - [ Creating Navigation ](https://www.bitovi.com/academy/learn-angular/creating-navigation.html?hsLang=en-us)
    - [ Fetching Data with Services ](https://www.bitovi.com/academy/learn-angular/restaurant-service.html?hsLang=en-us)
    - [ Rendering Data in Components ](https://www.bitovi.com/academy/learn-angular/pull-restaurant-data-into-view.html?hsLang=en-us)
    - [ Reactive Forms Data Binding ](https://www.bitovi.com/academy/learn-angular/state-city-options.html?hsLang=en-us)
    - [ Listening to Form Changes ](https://www.bitovi.com/academy/learn-angular/form-value-changes.html?hsLang=en-us)
    - [ Multi-parameter Services ](https://www.bitovi.com/academy/learn-angular/updating-service-params.html?hsLang=en-us)
    - [ Optional: Declarative State ](https://www.bitovi.com/academy/learn-angular/declarative-state.html?hsLang=en-us)
    - [ Writing Unit Tests ](https://www.bitovi.com/academy/learn-angular/writing-unit-tests.html?hsLang=en-us)
    - [ Creating Nested Routes ](https://www.bitovi.com/academy/learn-angular/nested-routes.html?hsLang=en-us)
    - [ Binding Component Data ](https://www.bitovi.com/academy/learn-angular/building-order-form.html?hsLang=en-us)
    - [ Creating Directives ](https://www.bitovi.com/academy/learn-angular/creating-directive.html?hsLang=en-us)
    - [ Order Service ](https://www.bitovi.com/academy/learn-angular/order-service.html?hsLang=en-us)
    - [ Order History Component ](https://www.bitovi.com/academy/learn-angular/order-history-component.html?hsLang=en-us)
    - [ Item Total Pipe ](https://www.bitovi.com/academy/learn-angular/item-total-pipe.html?hsLang=en-us)
    - [ Real Time Connections ](https://www.bitovi.com/academy/learn-angular/real-time-connection.html?hsLang=en-us)
    - [ Deploy App ](https://www.bitovi.com/academy/learn-angular/deploy-app.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Fetching Data with Services `page`

Learn how to write an Angular service that gets data from the server.

## Overview

In this part, we will:

- Install the `place-my-order` API
- Update `npm start` script
- Create an environment variable for API URL
- Generate a new service via the CLI
- Write a method to make an HTTP request
- Write interfaces to describe response object and restaurant object

## Problem 1: Write a Restaurant Service to Fetch a List of Restaurants

We want to create an Angular service with a method that will get a list of restaurants from our Place My Order API.

## P1: What you need to know

To complete this problem, you’ll need to know:

- The basics of Angular Services.
- How to generate a service.
- How to inject `HttpClientModule` into your app.
- How to use `HttpClient` to make an HTTP request in a service.

## Angular Service Basics

Angular [Services](https://angular.io/guide/architecture-services) are pieces of functionality that may not need to be tied to a view like components. A common example of a service is making an HTTP request to get data. Many components may require functionality to fetch data, and a Service can help abstract that logic into one place to be used across components.

The following example shows a `UsersService` with methods on it that return a list of users and get a user by ID, and shows how the `UsersService` is injected into the `AppComponent` and calls the `getUsers` to get the list of users to display in the template.

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.1/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.js"/></script>
<script src="https://unpkg.com/@angular/core@7.2.0/bundles/core.umd.js"/></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.26/zone.min.js"></script>
<script src="https://unpkg.com/@angular/common@7.2.0/bundles/common.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@7.2.0/bundles/compiler.umd.js"></script>
<script src="https://unpkg.com/@angular/router@7.2.0/bundles/router.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser@7.2.0/bundles/platform-browser.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@7.2.0/bundles/platform-browser-dynamic.umd.js"></script>
<base href="/">
<my-app></my-app>
<script type="typescript">
const { Component, NgModule, VERSION, OnInit, Injectable } = ng.core;
const { BrowserModule } = ng.platformBrowser;
const { CommonModule } = ng.common;
const { Routes, RouterModule } = ng.router;

@Injectable({
  providedIn: 'root'
})
class UsersService {
  private users = [
  {
    name: 'Jennifer',
    id: 1,
    role: 'admin'
  },
  {
    name: 'Steve',
    id: 2,
    role: 'user'
  },
  {
    name: 'Alice',
    id: 3,
    role: 'developer'
  }]

  constructor() { }

  getUsers() {
    return this.users;
  }

  getUser(id: number) {
    return this.users.find(x => x.id === id)
  }
}

@Component({
  selector: 'my-app',
  template: `
    <ul class="nav">
      <li routerLinkActive="active">
        <a routerLink="/about">About</a>
      </li>
    </ul>
    <router-outlet></router-outlet>
  `
})
class AppComponent {
  constructor() {}
}

@Component({
  selector: 'about-component',
  template: `
    <p>An about component!</p>
  `
})
class AboutComponent {
  constructor() {
  }
}

@Component({
  selector: 'home-component',
  template: `
    <p>A home component!</p>
    <ul>
      <li *ngFor="let user of users">
        {{user.name}}
      </li>
    </ul>
  `
})
class HomeComponent implements OnInit{
  private users: any[] = [];

  constructor(private usersService: UsersService) {
  
  }

  ngOnInit() {
    this.users = this.usersService.getUsers();
  }
}
//THIS IS A HACK JUST FOR CODEPEN TO WORK
HomeComponent.parameters = [UsersService];

const routes: Routes = [
  { path: 'about', component: AboutComponent },
  { path: '**', component: HomeComponent }
]
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
class AppRoutingModule { }

                 
@NgModule({
  declarations: [AppComponent, AboutComponent, HomeComponent],
  imports: [
    BrowserModule,
    CommonModule,
    AppRoutingModule,
  ],
  bootstrap: [AppComponent],
  providers: []
})
class AppModule {}

const { platformBrowserDynamic } = ng.platformBrowserDynamic;

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));
</script>

```

## Generating a service

To generate a `UsersService`, you run:

```
ng g service users
```

This will create a `src/app/users.service.ts` file and associated `spec` test file.

> Hint: You can generate a service in a folder `ng g service folder/users`

## Injectable

[`Injectable`](https://angular.io/api/core/Injectable) is an Angular decorator that makes the class it’s decorating available to Angular’s [Injector](https://angular.io/api/core/Injector) for creation. In the case of creating service to get data to use in our application, we want those services to be able to be injected into the app components we need the services in.

Angular uses the injector to create dependencies using providers - which know how to create said dependencies. We can then inject our service into our components constructor to take advantage of Angular’s dependency injection pattern.

## Importing `HttpClientModule` into *app.module.ts*

For making HTTP requests to interact with an API, Angular provides [HttpClient Module](https://angular.io/api/common/http/HttpClientModule). To use it we’ll need to import it in the root module of our app and include it the imports array.

**src/app/app.module.ts**

```
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { RestaurantComponent } from './restaurant/restaurant.component';
import { ImageUrlPipe } from './image-url.pipe';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    RestaurantComponent,
    ImageUrlPipe
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

```

## Using HttpClient to Make a Request

[HttpClient](https://angular.io/api/common/http/HttpClient) is a class with methods for making HTTP requests. Methods will return [RxJS Observables](https://angular.io/guide/observables).

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.1/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.js"/></script>
<script src="https://unpkg.com/@angular/core@7.2.0/bundles/core.umd.js"/></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.26/zone.min.js"></script>
<script src="https://unpkg.com/@angular/common@7.2.0/bundles/common.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@7.2.0/bundles/compiler.umd.js"></script>
<script src="https://unpkg.com/@angular/router@7.2.0/bundles/router.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser@7.2.0/bundles/platform-browser.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@7.2.0/bundles/platform-browser-dynamic.umd.js"></script>
<base href="/">
<my-app></my-app>
<script type="typescript">
const { Component, NgModule, VERSION, OnInit, Injectable } = ng.core;
const { BrowserModule } = ng.platformBrowser;
const { CommonModule, HttpClient } = ng.common;
const { Routes, RouterModule } = ng.router;

@Injectable({
  providedIn: 'root'
})
class UsersService {

  constructor(private httpClient: HttpClient) { }

  getUsers() {
    return this.httpClient.get<any>('/api/users');
  }

  getUser(id: number) {
    return this.httpClient.get<any>('/api/users/' + id);
  }
}

@Component({
  selector: 'my-app',
  template: `
    <ul class="nav">
      <li routerLinkActive="active">
        <a routerLink="/about">About</a>
      </li>
    </ul>
    <router-outlet></router-outlet>
  `
})
class AppComponent {
  constructor() {}

}

@Component({
  selector: 'about-component',
  template: `
    <p>An about component!</p>
  `
})
class AboutComponent {
  constructor() {
  }
}

@Component({
  selector: 'home-component',
  template: `
    <p>A home component!</p>
    <ul>
      <li *ngFor="let user of users">
        {{user.name}}
      </li>
    </ul>
  `
})
class HomeComponent implements OnInit{
  private users: any[] = [];

  constructor(private usersService: UsersService) {}

  ngOnInit() {
    this.users = usersService.getUsers();
  }
}
//THIS IS A HACK JUST FOR CODEPEN TO WORK
HomeComponent.parameters = [UsersService];

const routes: Routes = [
  { path: 'about', component: AboutComponent },
  { path: '**', component: HomeComponent }
]
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
class AppRoutingModule { }

                 
@NgModule({
  declarations: [AppComponent, AboutComponent, HomeComponent],
  imports: [
    BrowserModule,
    CommonModule,
    AppRoutingModule,
  ],
  bootstrap: [AppComponent],
  providers: []
})
class AppModule {}

const { platformBrowserDynamic } = ng.platformBrowserDynamic;

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));
</script>

```

This tutorial won’t cover RxJS in depth, but it’s worth being aware of Angular’s heavy use of it. Check out our [Learn RxJS](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us) tutorial for more information.

## P1: Technical requirements

Write a `RestaurantService` with a method `getRestaurants` that uses `httpClient` to get a list of restaurants from an environment variable + `/restaurants`. For example, we could get restaurants like:

```
const httpClient = new HttpClient();
const restaurantService = new RestaurantService(httpClient);

restaurantService.getRestaurants(); //-> Observable<Array<Object>>
```

Note:

- `getRestaurants` will return an RxJS observable that emits an array of restaurants.
- Typically, services and `HttpClient` are injected into components and not created as shown above.
- We want to create `RestaurantService` in `src/app/restaurant/restaurant.service.ts`.

## P1: Setup

Before we begin making services, we must:

- Install the place-my-order API
- Create an environment variable to point to the API

### Installing the Place My Order API

We’ve done some work to create a Place My Order API for use in this app by creating an npm package that will generate fake restaurant data and serve it from port 7070.

✏️ Run:

```
npm install place-my-order-api@1
```

✏️ Next add an API script to your `package.json`

```
{
  "name": "place-my-order",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "api": "place-my-order-api --port 7070",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^17.1.0",
    "@angular/common": "^17.1.0",
    "@angular/compiler": "^17.1.0",
    "@angular/core": "^17.1.0",
    "@angular/forms": "^17.1.0",
    "@angular/platform-browser": "^17.1.0",
    "@angular/platform-browser-dynamic": "^17.1.0",
    "@angular/router": "^17.1.0",
    "place-my-order-api": "^1.3.0",
    "place-my-order-assets": "^0.2.2",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.14.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^17.1.0",
    "@angular/cli": "^17.1.0",
    "@angular/compiler-cli": "^17.1.0",
    "@types/jasmine": "~5.1.0",
    "jasmine-core": "~5.1.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.3.2"
  }
}

```

✏️ In **new** terminal window, start the API server by running:

```
npm run api
```

Double check the api by navigating to [localhost:7070/restaurants](http://localhost:7070/restaurants). You should see a JSON list of restaurant data. It will be helpful to have a second terminal tab to run the api command from.

### Create an Environment Variable

The way we’re accessing our locally run API during development may be different than how we access it in production. To prepare for this, we’ll set an environment variable to do what we need.

✏️ To generate the environment files, run:

```
ng generate environments
```

> Before v15, Angular used to generate the environment files with `ng new` command.

The command will generate two files, `src/environments/environment.ts` and `src/environments/environment.development.ts`, with the following content:

```
export const environment = {};
```

When developing locally Angular will use the `environment.development.ts` file, but when we create a production build the `environment.ts` file will be used. Update `environment.ts` and `environment.development.ts` files to include a `production` key and an `apiUrl` key with the value of where our API is being served from: `http://localhost:7070`.

✏️ Update `src/environments/environment.ts`:

```
export const environment = {
  production: true,
  apiUrl: 'http://localhost:7070',
};
```

✏️ Update `src/environments/environment.development.ts`:

```
export const environment = {
  production: false,
  apiUrl: 'http://localhost:7070',
};
```

Now generate the restaurant service:

✏️ Run

```
ng g service restaurant/restaurant
```

✏️ Update `src/app/restaurant/restaurant.service.ts`:

```
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class RestaurantService {

  constructor() { }
}

```

### Having issues with your local setup?

You can get through most of this tutorial by using an online code editor. You won’t be able to run our tests to verify your solution, but you will be able to make changes to your app and see them live.

You can use one of these two online editors:

- [StackBlitz](https://stackblitz.com/fork/github/bitovi/academy/tree/main/exercises/angular/6-restaurant-service/problem?file=src/app/image-url.pipe.ts)
- [CodeSandbox](https://codesandbox.io/p/devbox/github/bitovi/academy/tree/main/exercises/angular/6-restaurant-service/problem?file=src/app/image-url.pipe.ts)

## P1: How to verify your solution is correct

✏️ Update the spec file **src/app/restaurant/restaurant.service.spec.ts** to be:

```
import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';

import { RestaurantService } from './restaurant.service';

describe('RestaurantService', () => {
  let httpTestingController: HttpTestingController;
  let service: RestaurantService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [RestaurantService],
    });

    httpTestingController = TestBed.inject(HttpTestingController);
    service = TestBed.inject(RestaurantService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should make a GET request to restaurants', () => {
    const mockRestaurants = {
      data: [
        {
          name: 'Brunch Place',
          slug: 'brunch-place',
          images: {
            thumbnail:
              'node_modules/place-my-order-assets/images/4-thumbnail.jpg',
            owner: 'node_modules/place-my-order-assets/images/2-owner.jpg',
            banner: 'node_modules/place-my-order-assets/images/2-banner.jpg',
          },
          menu: {
            lunch: [
              { name: 'Ricotta Gnocchi', price: 15.99 },
              { name: 'Garlic Fries', price: 15.99 },
              { name: 'Charred Octopus', price: 25.99 },
            ],
            dinner: [
              { name: 'Steamed Mussels', price: 21.99 },
              { name: 'Roasted Salmon', price: 23.99 },
              { name: 'Crab Pancakes with Sorrel Syrup', price: 35.99 },
            ],
          },
          address: {
            street: '2451 W Washburne Ave',
            city: 'Ann Arbor',
            state: 'MI',
            zip: '53295',
          },
          _id: 'xugqxQIX5rPJTLBv',
        },
        {
          name: 'Taco Joint',
          slug: 'taco-joint',
          images: {
            thumbnail:
              'node_modules/place-my-order-assets/images/4-thumbnail.jpg',
            owner: 'node_modules/place-my-order-assets/images/2-owner.jpg',
            banner: 'node_modules/place-my-order-assets/images/2-banner.jpg',
          },
          menu: {
            lunch: [
              { name: 'Beef Tacos', price: 15.99 },
              { name: 'Chicken Tacos', price: 15.99 },
              { name: 'Guacamole', price: 25.99 },
            ],
            dinner: [
              { name: 'Shrimp Tacos', price: 21.99 },
              { name: 'Chicken Enchilada', price: 23.99 },
              { name: 'Elotes', price: 35.99 },
            ],
          },
          address: {
            street: '13 N 21st St',
            city: 'Chicago',
            state: 'IL',
            zip: '53295',
          },
          _id: 'xugqxQIX5dfgdgTLBv',
        },
      ],
    };

    service.getRestaurants().subscribe((restaurants: any) => {
      expect(restaurants).toEqual(mockRestaurants);
    });

    const url = 'http://localhost:7070/restaurants';
    const req = httpTestingController.expectOne(url);

    expect(req.request.method).toEqual('GET');
    req.flush(mockRestaurants);

    httpTestingController.verify();
  });
});

```

✏️ Quit the previous tests running and restart them:

```
npm run test
```

## P1: Solution

If you’ve implemented the solution correctly, the tests will pass when you run `npm run test`!

Click to see the solution ✏️ Update **src/app/app.module.ts** to inject the `HttpClientModule`:

```
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { RestaurantComponent } from './restaurant/restaurant.component';
import { ImageUrlPipe } from './image-url.pipe';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    RestaurantComponent,
    ImageUrlPipe
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

```

✏️ Update **src/app/restaurant/restaurant.service.ts** to make a request to the API server `/restaurants`:

```
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class RestaurantService {

  constructor(private httpClient: HttpClient) {}

  getRestaurants(): Observable<any> {
    return this.httpClient.get<any>(environment.apiUrl + '/restaurants');
  }
}

```

## Problem 2: Write an Interface to Describe the Restaurant Object and Data Response

Currently, from TypeScript’s perspective, `getRestaurants()` can return anything. This means if we use the data from `getRestaurants()`, TypeScript will not be able to notice any mistakes. This undermines the whole point of TypeScript!

## P2: What you need to know

To solve this problem, you’ll need to:

- Understand interfaces in TypeScript
- How to generate an interface with Angular’s CLI.

## Interfaces in TypeScript

Thanks to TypeScript we can write interfaces to describe what we expect objects to look like. Consider the user service below returning an array of users. This interface describes what a user (and array of users) should look like:

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.1/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.js"/></script>
<script src="https://unpkg.com/@angular/core@7.2.0/bundles/core.umd.js"/></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.26/zone.min.js"></script>
<script src="https://unpkg.com/@angular/common@7.2.0/bundles/common.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@7.2.0/bundles/compiler.umd.js"></script>
<script src="https://unpkg.com/@angular/router@7.2.0/bundles/router.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser@7.2.0/bundles/platform-browser.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@7.2.0/bundles/platform-browser-dynamic.umd.js"></script>
<base href="/">
<my-app></my-app>
<script type="typescript">
const { Component, NgModule, VERSION, OnInit, Injectable } = ng.core;
const { BrowserModule } = ng.platformBrowser;
const { CommonModule } = ng.common;
const { Routes, RouterModule } = ng.router;

interface User {
  name: string;
  id: number;
  role: string;
}

@Injectable({
  providedIn: 'root'
})
class UsersService {
  private users: User[] = [
  {
    name: 'Jennifer',
    id: 1,
    role: 'admin'
  },
  {
    name: 'Steve',
    id: 2,
    role: 'user'
  },
  {
    name: 'Alice',
    id: 3,
    role: 'developer'
  }]

  constructor() { }

  getUsers() {
    return this.users;
  }

  getUser(id: number) {
    return this.users.find(x => x.id === id)
  }
}

@Component({
  selector: 'my-app',
  template: `
    <ul class="nav">
      <li routerLinkActive="active">
        <a routerLink="/about">About</a>
      </li>
    </ul>
    <router-outlet></router-outlet>
  `
})
class AppComponent {
  constructor() {}

}

@Component({
  selector: 'about-component',
  template: `
    <p>An about component!</p>
  `
})
class AboutComponent {
  constructor() {
  }
}

@Component({
  selector: 'home-component',
  template: `
    <p>A home component!</p>
    <ul>
      <li *ngFor="let user of users">
        {{user.name}}
      </li>
    </ul>
  `
})
class HomeComponent implements OnInit{
  private users: User[] = [];

  constructor(private usersService: UsersService) {}

  ngOnInit() {
    this.users = this.usersService.getUsers();
  }
}
//THIS IS A HACK JUST FOR CODEPEN TO WORK
HomeComponent.parameters = [UsersService];

const routes: Routes = [
  { path: 'about', component: AboutComponent },
  { path: '**', component: HomeComponent }
]
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
class AppRoutingModule { }

                 
@NgModule({
  declarations: [AppComponent, AboutComponent, HomeComponent],
  imports: [
    BrowserModule,
    CommonModule,
    AppRoutingModule,
  ],
  bootstrap: [AppComponent],
  providers: []
})
class AppModule {}

const { platformBrowserDynamic } = ng.platformBrowserDynamic;

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));
</script>

```

Arrays can also be written as:

```
users: Array<User>
```

To learn more about interfaces in TypeScript, check out our [TypeScript guide](https://www.bitovi.com/academy/learn-typescript/interfaces.html?hsLang=en-us).

## Generate an Interface

Use the following to generate an interface with the CLI:

```
ng g interface user
```

This will generate:

```
export interface User {}
```

## P2: Technical requirements

Write interfaces to tell TypeScript what we expect restaurant and other related objects to look like and use them in our restaurant service. A `Restaurant` interface should represent an object like this:

```
let restaurant = {
  name: '', //string
  slug: '', //string
  images: {
    thumbnail: '', //string
    owner: '', //string
    banner: '', //string
  },
  menu: {
    lunch: [
      {
        name: '', //string
        price: '', //number
      },
    ],
    dinner: [
      {
        name: '', //string
        price: '', //number
      },
    ],
  },
  address: {
    street: '', //string
    city: '', //string
    state: '', //string
    zip: '', //string
  },
  _id: '', //string
};
```

This interface should be written in the **src/app/restaurant/restaurant.ts** file.

## P2: Setup

We’ve already written a `ResponseData` interface that will take an array of restaurants for you. Here’s the code to get you started:

✏️ Generate the restaurant interface:

```
ng g interface restaurant/restaurant
```

✏️ Update **src/app/restaurant/restaurant.ts** with some starter code that includes some scaffolding for some of the sub-interfaces within the `Restaurant` interfaces:

```
interface Item {
  name: string;
}

interface Menu {
  lunch: Item[];
}

interface Address {
  street: string;
}

interface Images {
  thumbnail: string;
}

export interface Restaurant {
  name: string;
}

```

✏️ Update **src/app/restaurant/restaurant.service.ts** to import the `Restaurant` interface, use it within the `ResponseData` interface which is used by `httpClient.get`:

```
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';
import { Restaurant } from './restaurant';

export interface ResponseData {
  data: Restaurant[];
}

@Injectable({
  providedIn: 'root'
})
export class RestaurantService {

  constructor(private httpClient: HttpClient) {}

  getRestaurants(): Observable<ResponseData> {
    return this.httpClient.get<ResponseData>(
      environment.apiUrl + '/restaurants'
    );
  }
}

```

## P2: How to verify your solution is correct

✏️ Update the spec file **src/app/restaurant/restaurant.service.spec.ts** to be:

```
import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { Restaurant } from './restaurant';
import { ResponseData, RestaurantService } from './restaurant.service';

describe('RestaurantService', () => {
  let httpTestingController: HttpTestingController;
  let service: RestaurantService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
    });

    httpTestingController = TestBed.inject(HttpTestingController);
    service = TestBed.inject(RestaurantService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should make a GET request to restaurants', () => {
    const mockRestaurants = {
      data: [
        {
          name: 'Brunch Place',
          slug: 'brunch-place',
          images: {
            thumbnail:
              'node_modules/place-my-order-assets/images/4-thumbnail.jpg',
            owner: 'node_modules/place-my-order-assets/images/2-owner.jpg',
            banner: 'node_modules/place-my-order-assets/images/2-banner.jpg',
          },
          menu: {
            lunch: [
              { name: 'Ricotta Gnocchi', price: 15.99 },
              { name: 'Garlic Fries', price: 15.99 },
              { name: 'Charred Octopus', price: 25.99 },
            ],
            dinner: [
              { name: 'Steamed Mussels', price: 21.99 },
              { name: 'Roasted Salmon', price: 23.99 },
              { name: 'Crab Pancakes with Sorrel Syrup', price: 35.99 },
            ],
          },
          address: {
            street: '2451 W Washburne Ave',
            city: 'Ann Arbor',
            state: 'MI',
            zip: '53295',
          },
          _id: 'xugqxQIX5rPJTLBv',
        },
        {
          name: 'Taco Joint',
          slug: 'taco-joint',
          images: {
            thumbnail:
              'node_modules/place-my-order-assets/images/4-thumbnail.jpg',
            owner: 'node_modules/place-my-order-assets/images/2-owner.jpg',
            banner: 'node_modules/place-my-order-assets/images/2-banner.jpg',
          },
          menu: {
            lunch: [
              { name: 'Beef Tacos', price: 15.99 },
              { name: 'Chicken Tacos', price: 15.99 },
              { name: 'Guacamole', price: 25.99 },
            ],
            dinner: [
              { name: 'Shrimp Tacos', price: 21.99 },
              { name: 'Chicken Enchilada', price: 23.99 },
              { name: 'Elotes', price: 35.99 },
            ],
          },
          address: {
            street: '13 N 21st St',
            city: 'Chicago',
            state: 'IL',
            zip: '53295',
          },
          _id: 'xugqxQIX5dfgdgTLBv',
        },
      ],
    };

    service.getRestaurants().subscribe((restaurants: ResponseData) => {
      expect(restaurants).toEqual(mockRestaurants);
    });

    const url = 'http://localhost:7070/restaurants';
    const req = httpTestingController.expectOne(url);

    expect(req.request.method).toEqual('GET');
    req.flush(mockRestaurants);

    httpTestingController.verify();
  });

  it('can set proper properties on restaurant type', () => {
    const restaurant: Restaurant = {
      name: 'Taco Joint',
      slug: 'taco-joint',
      images: {
        thumbnail: 'node_modules/place-my-order-assets/images/4-thumbnail.jpg',
        owner: 'node_modules/place-my-order-assets/images/2-owner.jpg',
        banner: 'node_modules/place-my-order-assets/images/2-banner.jpg',
      },
      menu: {
        lunch: [
          { name: 'Beef Tacos', price: 15.99 },
          { name: 'Chicken Tacos', price: 15.99 },
          { name: 'Guacamole', price: 25.99 },
        ],
        dinner: [
          { name: 'Shrimp Tacos', price: 21.99 },
          { name: 'Chicken Enchilada', price: 23.99 },
          { name: 'Elotes', price: 35.99 },
        ],
      },
      address: {
        street: '13 N 21st St',
        city: 'Chicago',
        state: 'IL',
        zip: '53295',
      },
      _id: 'xugqxQIX5dfgdgTLBv',
    };
    // will error if interface isn’t implemented correctly
    expect(true).toBe(true);
  });
});

```

If you’ve implemented the solution correctly, the tests will pass when you run `npm run test`! If you haven’t written the interfaces correctly, you’ll see a compile error before the tests runs. You might need to restart the test script to see the compile error.

## P2: Solution

Click to see the solution ✏️ Update **src/app/restaurant/restaurant.ts** to:

```
interface Item {
  name: string;
  price: number;
}

interface Menu {
  lunch: Item[];
  dinner: Item[];
}

interface Address {
  street: string;
  city: string;
  state: string;
  zip: string;
}

interface Images {
  thumbnail: string;
  owner: string;
  banner: string;
}

export interface Restaurant {
  name: string;
  slug: string;
  images: Images;
  menu: Menu;
  address: Address;
  _id: string;
}

```

In the next step we’ll call the `getRestaurants` method in our component to get the list of restaurants.

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-angular/restaurant-service.html",
          "description": "Learn how to write an Angular service that gets data from the server. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```