我最近开始学习 NestJS,因为它似乎是一个很棒的框架,可以帮助构建我的项目后端。我需要学习但找不到的是一种从 3rd-party API 获取数据的方法。根据文档,它包装了 Axios,这很棒,因为我非常了解 Axios。我不明白的是如何让它发挥作用。
出于学习目的,我正在尝试从 OpenWeatherMap.org 获取天气数据。当我搭建应用程序时,我使用了
nest new weather-app
并按顺序生成了天气模块、服务和控制器,以确保所有内容都与 nest g <<<type of file>>> weather
正确集成。您可以放心地假设我的 app.module.ts
正确导入了我的 weather.module.ts
。另外,我的 OpenWeatherMap API 密钥会直接复制到我的 .env
中。
这是我的
weather.module.ts
:
require('dotenv').config();
import { Module, HttpModule } from '@nestjs/common';
import { WeatherService } from './weather.service';
import { WeatherController } from './weather.controller';
@Module({
imports: [
HttpModule.register({
baseURL: 'api.openweathermap.org/data/2.5/weather',
params: {
appid: process.env.OPEN_WEATHER_KEY,
},
}),
],
providers: [WeatherService],
controllers: [WeatherController],
})
export class WeatherModule {}
这是我的
weather.service.ts
:
import { Injectable, HttpService } from '@nestjs/common';
import { AxiosResponse } from 'axios';
import { Observable } from 'rxjs';
@Injectable()
export class WeatherService {
constructor(private readonly httpService: HttpService) {}
forCity(city: string): Observable<AxiosResponse<object>> {
return this.httpService.get(`?q=${city}`);
}
}
这是我的
weather.controller.ts
:
import { Controller, Get, Param } from '@nestjs/common';
import { WeatherService } from './weather.service';
@Controller('weather')
export class WeatherController {
constructor(private readonly weatherService: WeatherService) {}
@Get(':city')
getWeather(@Param('city') city: string): object {
return this.weatherService.forCity(city);
}
}
当我运行这个项目时,Nest 成功构建了所有内容,没有错误。然而,当我去 Postman 并尝试到达终点时,我得到了这个:
我认为我已经相当仔细地遵循了 NestJS 文档,并利用了我自己使用 Axios 的经验,但我无法弄清楚我在这里做得不正确。我有一个更大的项目,我想在其中使用 Nest,但我需要使用第 3 方 API 才能使该项目正常工作。
有什么想法吗?
提前致谢!
更新: 使用 Observable 的
pipe
方法和 catchError
后,我得到了 401
状态。起初,我认为这意味着我的 api 密钥没有正确传递,但我将其注销,它与我帐户中的天气 api 相匹配。
第二次更新:几天后(包括一个晚上的休息),我仍然没有取得任何成功。如果我将 url 和 API 密钥移至
weather.services.ts
,我会得到循环引用。我已经彻底阅读了 Nest 和 Axios 的文档,但感觉我仍然无法让它工作。
我还尝试访问 Nest 通过
axiosRef()
公开的 HttpService
,但最终收到 Typescript 编译错误,将我的 Observable
类型转换为 Promise
。所做的只是给了我另一个循环引用。
HttpModule 和 HttpService(来自“@nestjs/common”包)已被弃用,并将在下一个主要版本中删除。请改用“@nestjs/axios”包。
app.module.ts
import { HttpModule } from '@nestjs/axios';
@Module({
imports: [
HttpModule,
],
})
export class AppModule {}
app.controller.ts
@Get()
getWeatherForecasts() {
return this.appService.getWeatherForecasts();
}
app.service.ts
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
async getWeatherForecasts() {
const url = 'http://www.7timer.info/bin/api.pl?lon=113.17&lat=23.09&product=astro&output=json';
const { data } = await firstValueFrom(this.httpService.get(url));
return data;
}
在您的服务中,当您返回输出时,NestJS 会尝试“字符串化”Observable
尝试这个
weather.service.ts
:
import { Injectable, HttpService } from '@nestjs/common';
import { AxiosResponse } from 'axios';
import { Observable } from 'rxjs';
@Injectable()
export class WeatherService {
constructor(private readonly httpService: HttpService) {}
forCity(city: string): Observable<AxiosResponse<object>> {
return this.httpService
.get(`?q=${city}`)
.pipe(
map((axiosResponse: AxiosResponse) => {
return axiosResponse.data;
}),
);
}
}