Wrapping the NodeJS client for Google Maps Services in a NestJS app
A common doubt that comes to mind when building a NestJS application is the proper way to implement some functionality respecting the framework architecture to take full advantage of the scalability it provides.
This article's main goal is to propose a way of wrapping the NodeJS client for Google Maps Services in a NestJS module and use dependency injection to make it easy to reuse across the application. Although this article uses specifically the @googlemaps/google-maps-service-js
npm package, it may be used as inspiration for other client based external services.
NestJS framework
NestJS is a framework for creating scalable and loosely coupled server-side NodeJS applications. One of its main characteristics is the implemented architecture and directory structure, which reinforces the modularized nature of the application. On top of that, NestJS fully supports TypeScript and also works with Express and Fastify under the hood, which makes it an up-to-date and viable alternative framework for building a reliable web server with well-known tooling.
The framework architecture
As stated in the NestJS documentation, its architecture is heavily inspired by Angular's architecture. The folder structure is basically organized in modules that represent some entity that binds a specific context of the application. Each module is commonly composed by the files app.module.ts
, app.controller.ts
, and app.service.ts
. The common folder structure for a module looks like this:
google-maps
| - google-maps.controller.ts
| - google-maps.module.ts
| - google-maps.service.ts
Node.js Client for Google Maps Services
The client for google maps service is a library created to interact with the Web API provided by Google directly from a given project's programming language, in this case, TypeScript with NodeJS.
Given that the @googlemaps/google-maps-service-js
npm package provides many recurrently used methods and classes, one way to use dependency injection with this service is to wrap the google maps service client inside a getter method in a module class along with the most used methods to better serve the application.
Wrapping the library in a module
The google-maps
module folder is composed simply by a module.ts
file and a service.ts
file, which contains a client getter and other most used methods. The service would then look like this:
The above code is composed by the following functionalities, using an OOP approach:
- The
GoogleMapsService
class extends the defaultClient
class and calls the super() method to instantiate it in order to use all its methods and properties; - A private propertie is declared to store the access Key that is required to access the google api service;
- The accessKey is retrieved from an environment variable for security reasons, using the built-in NestJS service
ConfigService
; - In this example, an async method called
getCoordinates
is defined to get latitude and longitude values from a given address using the .geocode method which communicates with its web service API relative; - Given that the application is using TypeScript, the package also provides custom types for the library so it is possible to define the type of the returned value for the method created as LatLngLiteral.
The whole structure of the service above is well described in its dedicated section in the NestJS documentation.
Since the application described in this article does not provide any external route to interact with the service presented above, there is no controller.ts file to handle external requests.
As for the module file, it is responsible for binding all files related to a given context and also to be injected in other modules. More on this section can be found in the NestJS documentation. The google-maps.module.ts looks something like the following:
The above code defines the service created as a provider and exports it so that it can be reused in other modules.
Dependency injection
Lastly, it is required that the google-maps module created is declared inside the module that uses the google-maps service and then uses dependency injection on the class that uses the google-maps service methods. Other modules would look like this:
And then, for the DI at service level:
The above code uses the NestJS dependency injection format to use the google-maps service created and also the google-maps types to define the returned value of the getAddressCoords
method.
Conclusion
As discussed before, it is interesting to write code in a modularized way in scalable applications with multiple entity scopes.
Considering the described scenario, the application presented in this article shows a way of modularizing external services, making the code more reusable, and concentrating context-related methods and values in the same module.
Credits
- Cover image by Ilya Pavlov on Unsplash
Top comments (0)