GET request to API request give status code of 502. How can I resolve this? - https

I am building an application with nestjs framework. I have created controller and service to fetch data from Http endpoint. Instead of getting the json data I am getting
Error: Request failed with status code 502
at createError (node_modules/axios/lib/core/createError.js:16:15)
at settle (node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (node_modules/axios/lib/adapters/http.js:237:11)
at IncomingMessage.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1145:12)
at process._tickCallback (internal/process/next_tick.js:63:19) in the output. The endpoint is working fine on Google Chrome. I have integrated my application with Swagger UI. What changes should I make in my code so that I can get data from endpoint?
Here is my service.ts
import { Injectable, HttpService } from '#nestjs/common';
import { map } from 'rxjs/operators';
#Injectable()
export class MessageService {
constructor(private readonly httpService: HttpService) {}
configEndPoint: string = 'https://jsonplaceholder.typicode.com/todos/1';
getData(source: string, productCode: string, vehicleType: string) {
return this.httpService
.get(this.configEndPoint)
.pipe(map(response => response.data.json()));
}
}
Here is my controller.ts
import { Controller, Post, Body, Get } from '#nestjs/common';
import {
ApiImplicitHeader,
ApiOperation,
ApiResponse,
ApiUseTags,
} from '#nestjs/swagger';
import { ProductEvent } from '../dto/product-event';
import { MessageService } from '../service/message/message-service';
#Controller('/service/api/message')
export class MessageController {
source: string;
productCode: string;
vehicleType: string;
constructor(private messageService: MessageService) {}
#Post()
#ApiUseTags('processor-dispatcher')
#ApiOperation({ title: 'Generate product message for the SNS topics' })
async generateMessage(#Body() productEvent: ProductEvent) {
return JSON.stringify(
this.messageService.getData(
this.source,
this.productCode,
this.vehicleType,
),
);
}
}

Related

Nestjs / GraphQL - Playground Returns Null Error For Query. My Resolvers?

Playground in my browser shows the Nestjs created schema nicely but queries are returning null. Is there something wrong with my code?
"errors": [
{
"message": "Cannot return null for non-nullable field Query.getUsers.",
"locations": [
{
"line": 2,
"column": 3
}
This means no data found.
schema.graphql:
type UsersGQL {
User_id: ID!
first_name: String!
last_name: String!
main_skill_title: String!
user_name: String!
....
}
type Query {
getUser(user_id: ID!): UsersGQL!
getUsers: [UsersGQL!]!
}
Compiles in Nestjs with GraphQL to graphql.schema.ts
export class UsersGQL {
user_id: string;
first_name: string;
last_name: string;
main_skill_title: string;
user_name: string;
...
}
export abstract class IQuery {
abstract getUser(user_id: string): UsersGQL | Promise<UsersGQL>;
abstract getUsers(): UsersGQL[] | Promise<UsersGQL[]>;
abstract temp__(): boolean | Promise<boolean>;
}
users.resolvers.ts
import { Query, Resolver } from '#nestjs/graphql';
import { UsersService } from './users.service';
import { UsersGQL } from '../graphql.schema';
// import { UsersDTO } from './users.dto';
#Resolver('UsersGQL')
export class UsersResolvers {
constructor(
private readonly userService: UsersService
) {}
#Query()
async getUsers() {
return await this.userService.findAll();
}
}
The service works fine for my Nestjs REST API's. The db is Postgres.
users.service.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository, getManager, getRepository } from 'typeorm';
import { Members } from './members.entity';
#Injectable()
export class UsersService {
private entityManager = getManager();
constructor(
#InjectRepository(Users)
private readonly usersRepository: Repository<Users>
) {}
async findAll(): Promise<Users[]> {
return await this.usersRepository.find();
}
}
Playground query:
{
getUsers {
first_name
last_name
}
}
The error returned in Playground:
{
"errors": [
{
"message": "Cannot return null for non-nullable field Query.getUsers.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getUsers"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
...
],
"data": null
}
Edit - added users.module.ts, app.module.ts and ormconfig.json. This whole module is lazy loaded. REST and GraphQL are side by side in the module. I also separated REST and GQL components.
users.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
// REST
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { Users } from './users.entity';
// GraphQL
import { UsersResolvers } from './users.resolvers';
#Module({
imports: [
TypeOrmModule.forFeature([
Users
]),
],
providers: [
UsersService,
UsersResolvers
],
controllers: [UsersController],
})
export class UsersModule {}
app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { GraphQLModule } from '#nestjs/graphql';
import { join } from 'path';
import { LoggerMiddleware } from './logger.middleware';
import { UsersModule } from './users/users.module';
import { UsersController } from './users/users.controller';
#Module({
imports: [
TypeOrmModule.forRoot(),
GraphQLModule.forRoot({
typePaths: ['./**/*.graphql'],
definitions: {
path: join(process.cwd(), 'src/graphql.schema.ts'),
outputAs: 'class',
},
debug: true,
}),
UsersModule
],
controllers: [
],
exports: [
],
providers: [
]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.with('AppModule')
.forRoutes(
UsersController
)};
}
ormconfig.json
...
"entities": [
"src/**/**.entity{.ts,.js}",
// "src/graphql.schema.ts" This doesn't work. Must use REST entity.
],
...
You probably imported #Query from '#nestjs/common' instead of '#nestjs/graphql'.
Make sure to have:
import { Query } from '#nestjs/graphql';
TL;DR
The fact that your schema is correctly exposed (and available via the playground) doesn't necessarily mean that all the corresponding modules and resolvers are integrated into your running Nest application.
I recently faced the same error and the reason was quite straightforward: I had forgotten to import the module including the resolver into the root module — usually AppModule.
So: are you sure you have all your UserModule module dependencies (and above all the UserResolver) imported and the UsersModule itself imported into your AppModule?
The trick here is that the GraphQL schema exposed by your server is directly generated from your source files. According to your Nest GraphQL configuration, it will compile all the .graphql, .gql files together (schema first approach) ; or the type-graphql module, with Nest v6, will read all your source files looking for its decorators and generate the schema.gql (code first approach). As a consequence, you can expose a correct schema even having no actual module resolving your request.
IMO, it's a buggy behaviour from the framework as it silently fails to resolve your schema without providing any explanation. The simple error message you get (Cannot return null for non-nullable field Query.getUsers.) is quite misleading as it hides the real failure, which is a broken dependency.
For more information, here is the related GitHub issue: https://github.com/nestjs/graphql/issues/198
The "solution" with this TypeORM architecture is to use the TypeORM entity.
users.resolvers.ts
import { Query, Resolver } from '#nestjs/graphql';
import { UsersService } from './users.service';
import { Users } from './users.entity'; // Here
#Resolver('Users')
export class UsersResolvers {
constructor(
private readonly userService: UsersService
) {}
#Query()
async getUsers() {
return await this.userService.findAll();
}
}

How to access websocket from controller or another component/services?

I have a REST API, I want to send event to the client via websocket.
How to inject websocket instance in controller or another component?
Better solution is to create global module. You can then emit events from any other module/controller. A. Afir approach will create multiple instances of Gateway if you try to use it in other modules.
Note: This is just simplest solution
Create socket.module.ts
import { Module, Global } from '#nestjs/common';
import { SocketService } from './socket.service';
#Global()
#Module({
controllers: [],
providers: [SocketService],
exports: [SocketService],
})
export class SocketModule {}
socket.service.ts
import { Injectable } from '#nestjs/common';
import { Server } from 'socket.io';
#Injectable()
export class SocketService {
public socket: Server = null;
}
app.gateway.ts see afterInit function
import { WebSocketGateway, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer } from '#nestjs/websockets';
import { Logger } from '#nestjs/common';
import { Server, Socket } from 'socket.io';
import { SocketService } from './socket/socket.service';
#WebSocketGateway()
export class AppGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
constructor(private socketService: SocketService){
}
#WebSocketServer() public server: Server;
private logger: Logger = new Logger('AppGateway');
afterInit(server: Server) {
this.socketService.socket = server;
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client connected: ${client.id}`);
}
}
Then import SocketModule into AppModule and you can use Socket service everywhere.
class Gateway can be injected in another component, and use the server instance.
#Controller()
export class AppController {
constructor(
private readonly appService: AppService,
private readonly messageGateway: MessageGateway
) {}
#Get()
async getHello() {
this.messageGateway.server.emit('messages', 'Hello from REST API');
return this.appService.getHello();
}
}
I suppose that #Raold missed a fact in the documentation:
Gateways should not use request-scoped providers because they must act as singletons. Each gateway encapsulates a real socket and cannot be instantiated multiple times.
So it means that we can neither instantiate the gateway class multiple times nor do it explicitly using injection scopes features.
So creating just only one gateway for one namespaces will be right and it will produce only one instance of the websocket or socket.io server.

Angular SharedService with BehaviorSubject lost Data on refresh

i created sharedService it works perfectly , i can shared data from one component to another (this both are irrelevant component in different module).
Data Transfer as follows:
AdminDashboard.Component (update value) ===> conference.component (get new updated value)
problem : when i refresh my conference.component i lost the value
EventService.ts
import { Injectable } from '#angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { importExpr } from '#angular/compiler/src/output/output_ast';
import {Events} from '../models/event.model'
#Injectable()
export class EventService {
private dataSource = new BehaviorSubject(null);
sendMessage(data) {
this.dataSource.next(data);
}
getMessage(): Observable<any> {
return this.dataSource.asObservable();
}
}
dashboard.component (url /dashboard)
on Button Click msg() method called , which updated BehaviourSubjectvalue.
import { Component, OnInit} from '#angular/core';
import { NgForm } from '#angular/forms';
import { EventService } from '../../shared/sharedServies/eventService.service';
export class AdminDashboardComponent implements OnInit {
constructor( private testEventService: EventService){ }
msg() {
debugger
this.testEventService.sendMessage('Message from Home Component to App
Component!');
}
}
conference.component (url /conference)
Here , i hold value in message and bind to ui.
import { Component, OnInit } from '#angular/core';
import { EventService } from'../../shared/sharedServies/eventService.service';
import { Subscription } from 'rxjs/Subscription';
export class ViewconferenceComponent implements OnInit {
message: any;
constructor(private EventService: EventService) {
this.subscription = this.EventService.getMessage().subscribe(message => {
console.log(message)
this.message = message;
});
}
}
Question :
when i get data on /conference page , at this when i refresh the
service holded value is lost , i didn't understand what this happens.
also i need to add json to sharedService , how it will achive?
This is expected since when you "switch" components they are destroyed. You could work around this quickly by adding state variables to your service.
Personally, I encourage you to make use of some state library like ngRx https://github.com/ngrx/platform

HttpClient Angular 5 does not send request

I have a problem with HttpClient in Angular 5. HttpClient does not send any request (I don't see any xhr log in console) on two specified components. On the others components everything is fine.
Calling ApiService POST method (custom service which works like a wrapper for HttpClient) from Component A, but when I call this method from Component B
HttpClient seems to be frozen.
There are many components in my app that use ApiService. Everything is injected fine. I have no idea what is wrong.
--- respond
ApiService.ts
#Injectable()
export class ApiService
{
private errorListeners : Map<string, Array<(details ?: any) => any>> =
new Map<string, Array<(details ?: any) => any>>();
public constructor(private http: HttpClient)
{
}
public post<T>(path : string, data : any, urlParams : any = null) : Observable<any>
{
return this.http.post<T>(`${environment.api.path}${path}`, data, {
params: urlParams
}).catch(this.catchErrors()).map(response => {
if (response['Error']){
throw response['Error'];
}
return response;
});
}
}
--
Component
#Component({
selector: 'login-register-component',
templateUrl: './register.component.html',
styleUrls: [
'./../../assets/main/css/pages/login.css'
]
})
export class RegisterComponent implements OnInit, OnDestroy
{
public constructor(private route: ActivatedRoute,
private router: Router,
private userService : UserService,
private apiService: ApiService
)
{
this.apiService.post('/some-endpoint', null, {}).subscribe(res => {
console.log(res);
});
}
HttpClient does not work even if i directly inject HttpClient into Component
-- Other component in the same module
example call: (it works)
public loginTraditionalMethod(emailAddress : string, plainPassword : string)
{
this.apiService.post('/auth/email', {
email: emailAddress,
password: plainPassword
}, {}).subscribe(res => {
console.log(res);
})
}
I was having the same problem, no xhr request after subscribing to a http.get(). This was a request for a forgotten password function, I was therefore not connected to the app.
The request was being intercepted by an http token interceptor that was returning an empty Observable if no session was detected.
Never know, this might help someone...

'object%20Object' Being Appended instead of parameters.

I am attempting to make a call to the server using promises. When trying to add my parameters, it comes out as 'object%20Object'
Here is the call
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
import { User } from '../models/user';
#Injectable()
export class UserService {
private baseUserUrl = 'api/User/'
constructor(private http: Http) { }
getUsers(currentPage: number): Promise<User[]> {
return this.http.get(this.baseUserUrl + 'GetUsers?currentPage=' + currentPage)
.map(resp => resp.json() as User[])
.toPromise()
}
}
I was accidentally passing an object into the method, so I wasn't accessing the property, I was accessing the object. I fixed that and removed the object and passed a property.

Resources