UNPKG

@loopback/docs

Version:
173 lines (137 loc) 4.49 kB
--- lang: en title: 'Calling other APIs and web services' keywords: LoopBack 4.0, LoopBack 4 sidebar: lb4_sidebar permalink: /doc/en/lb4/Calling-other-APIs-and-web-services.html --- Your API implementation often needs to interact with REST APIs, SOAP Web Services, gRPC microservices, or other forms of APIs. To facilitate calling other APIs or web services, we introduce `@loopback/service-proxy` module to provide a common set of interfaces for interacting with backend services. ## Installation ``` $ npm install --save @loopback/service-proxy ``` ## Usage ### Define a data source for the service backend ```ts import {juggler} from '@loopback/service-proxy'; const ds: juggler.DataSource = new juggler.DataSource({ name: 'GoogleMapGeoCode', connector: 'rest', options: { headers: { accept: 'application/json', 'content-type': 'application/json', }, }, operations: [ { template: { method: 'GET', url: 'http://maps.googleapis.com/maps/api/geocode/{format=json}', query: { address: '{street},{city},{zipcode}', sensor: '{sensor=false}', }, responsePath: '$.results[0].geometry.location[0]', }, functions: { geocode: ['street', 'city', 'zipcode'], }, }, ], }); ``` Install the REST connector used by the new datasource: ``` $ npm install --save loopback-connector-rest ``` ### Declare the service interface To promote type safety, we recommend you to declare data types and service interfaces in TypeScript and use them to access the service proxy. ```ts interface GeoCode { lat: number; lng: number; } interface GeoService { geocode(street: string, city: string, zipcode: string): Promise<GeoCode>; } ``` Alternately, we also provide a weakly-typed generic service interface as follows: ```ts /** * A generic service interface with any number of methods that return a promise */ export interface GenericService { [methodName: string]: (...args: any[]) => Promise<any>; } ``` To reference the `GenericService`: ```ts import {GenericService} from '@loopback/service-proxy'; ``` **NOTE**: We'll introduce tools in the future to generate TypeScript service interfaces from service specifications such as OpenAPI spec. ### Declare service proxies for your controller If your controller needs to interact with backend services, declare such dependencies using `@serviceProxy` on constructor parameters or instance properties of the controller class. ```ts import {serviceProxy} from '@loopback/service-proxy'; export class MyController { @serviceProxy('geoService') private geoService: GeoService; } ``` ### Get an instance of your controller ```ts context.bind('controllers.MyController').toClass(MyController); const myController = await context.get<MyController>( 'controllers.MyController', ); ``` ### Make service proxies easier to test While `@serviceProxy` decorator makes it easy to use service proxies in controllers, it makes it difficult to write integration tests to verify that service proxies are correctly configured/implemented in respect to the most recent API provided by the backend service implementation. To make service proxies easy to test, we recommend to write a [Provider](./Creating-components.md#providers) class that will allow both controllers and integration tests to access the same service proxy implementation. ```ts import {getService, juggler} from '@loopback/service-proxy'; import {inject, Provider} from '@loopback/core'; import {GeocoderDataSource} from '../datasources/geocoder.datasource'; export class GeoServiceProvider implements Provider<GeoService> { constructor( @inject('datasources.geoService') protected datasource: juggler.DataSource = new GeocoderDataSource(), ) {} value(): Promise<GeocoderService> { return getService(this.datasource); } } ``` In your application, apply [ServiceMixin](http://apidocs.loopback.io/@loopback%2fdocs/service-proxy.html#ServiceMixin) and use `app.serviceProvider` API to create binding for the geo service proxy. ```ts app.serviceProvider(GeoServiceProvider); ``` Finally, modify the controller to receive our new service proxy in the constructor: ```ts export class MyController { @inject('services.GeoService') private geoService: GeoService; } ``` Please refer to [Testing Your Application](./Testing-your-application.md#test-your-services-against-real-backends) for guidelines on integration testing.