"Type 'void' is not assignable to type 'Todo[]'." How to resolve this? - angular8

in my angular 8 app i have this service :
export class TodoService {
private url:string ="http://192.168.99.100:2403/todos";
sTodos:Subject<Todo[]>= new Subject<Todo[]>();
sTodos$=this.sTodos.asObservable();
constructor(private http:Http) { }
getTodos(){
return this.http.get(this.url).map((r)=>{
let data = r.json();
this.sTodos.next(data);
});
}
in my component i call getTodos function:
export class TodoListComponent implements OnInit {
todos:Todo[]=[];
constructor(private todoService:TodoService) { }
ngOnInit(){
this.todoService.getTodos().subscribe((todos) =>{
this.todos = todos;
});
}
}
i get this error
Type 'void' is not assignable to type 'Todo[]'.

You can add an explicit type to the http call.
EDIT:
If you're using Angular 8, you should also use the new Http Client
constructor(private http:HttpClient) { }
getTodos(){
return this.http.get<Todo[]>(this.url)
.pipe(
tap((data)=>{
this.sTodos.next(data);
});
)
}

Related

How to use gaurds on module level in nest.js?

I want to use the gaurds on module level instead of controller routes and global module.
How can I do that?
I have this gaurd on my code:
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private readonly verifyOptions?: VerifySessionOptions) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const ctx = context.switchToHttp();
let err = undefined;
const resp = ctx.getResponse();
await verifySession(this.verifyOptions)(ctx.getRequest(), resp, (res) => {
err = res;
});
if (resp.headersSent) {
throw new STError({
message: 'RESPONSE_SENT',
type: 'RESPONSE_SENT',
});
}
if (err) {
throw err;
}
return true;
}
}
I have many modules in my app like applications, chat, share etc and I want to protect the routes. For that protected routes I want to use this AuthGaurd.
But I don't want to use the gaurd on each and every controller endpoint like this:
#Post()
UseGaurds(new AuthGaurd())
async createApplication(
#Body() createAppData: CreateApplicationDto,
#Session() session: SessionContainer
) {
try {
const newDoc = await this.applicationService.create(createAppData);
return utils.sendSuccess(SUCCESS.S200.DEFAULT, newDoc);
} catch (error) {
throw new BadRequestException();
}
}
I want to use the gaurd on module level. Not on the global module but the modules like application, chat, share etc.
This is what my applicationModule looks like:
#Module({
imports: [SequelizeModule.forFeature([Application])],
providers: [ApplicationServices, ...applicationProvider, ...shareProvider],
exports: [ApplicationServices],
controllers: [ApplicationController],
})
export class ApplicationModule {}

How can I use type-graphql and RESTDataSource

I wonder how it is possible to use RESTDataSource in type-graphql and thus cache correctly in a redis. I would be grateful for a small example.
At the moment I use the DI container to get a service, which is extended from the RestDataSource class, but this is not the right way.
BookmarkResolver.ts
import { Resolver, FieldResolver, Root, Query, Ctx, Authorized } from 'type-graphql';
import { DealService } from '../service/DealService';
import { AvailableLocale } from '../enum/AvailableLocale';
import { Bookmark } from '../entity/Bookmark';
#Resolver(_of => Bookmark)
export class BookmarkResolver {
constructor(private dealService: DealService) {}
#FieldResolver()
async wordpressDeal(#Root() bookmark: Bookmark) {
return await this.dealService.getDealById(bookmark.item_id, AvailableLocale.STAGING);
}
}
DealService.ts
import { Service } from 'typedi';
import { AbstractService } from './AbstractService';
import { AvailableLocale } from '../enum/AvailableLocale';
#Service()
export class DealService extends AbstractService {
baseURL = process.env.DEAL_SERVICE_URL;
async getDealById(dealId: string | number, locale: AvailableLocale) {
const response = await this.get(
'deals/' + dealId,
{ locale }
);
return this.dealReducer(response);
}
dealReducer(deal: any) {
return {
id: deal.id || 0,
title: deal.title
};
}
}
AbstractService.ts
import { RESTDataSource, HTTPCache } from 'apollo-datasource-rest';
import { Service } from 'typedi';
#Service()
export class AbstractService extends RESTDataSource {
constructor() {
super();
this.httpCache = new HTTPCache();
}
}
Share the RESTDataSource via ApolloServer's context. Use it in the resolver by accessing the context with the #Ctx() decorator.
1. Define a RESTDataSource
Define the data source according to the apollo-datasource-rest example.
export class TodoDataSource extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://jsonplaceholder.typicode.com/todos";
}
async getTodos(): Promise<Todo[]> {
return this.get("/");
}
}
2. Create an instance of the DataSource and put it in the Context
When you start the server, add data sources to the context by defining a function that creates the data sources.
const server = new ApolloServer({
schema,
playground: true,
dataSources: () => ({
todoDataSource: new TodoDataSource(),
}),
});
3. Access the DataSource in the resolver
Use the #Ctx() decorator to access the context in the resolver so you can use the data source.
#Resolver(Todo)
export class TodoResolver {
#Query(() => [Todo])
async todos(#Ctx() context: Context) {
return context.dataSources.todoDataSource.getTodos();
}
}
Full, runnable example at https://github.com/lauriharpf/type-graphql-restdatasource

NestJS pipe Joi.validate() (is not a function)

I try to use Joi validator on NestJS with pipe.
https://docs.nestjs.com/pipes#object-schema-validation
import * as Joi from '#hapi/joi';
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '#nestjs/common';
#Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(
private readonly schema: Joi.ObjectSchema,
) {}
transform(value: any, metadata: ArgumentMetadata) {
const { error } = Joi.validate(value, this.schema);
if (error) {
throw new BadRequestException('Validation failed');
}
return value;
}
}
It doesn't work properly.
TypeError: Joi.validate is not a function
Use schema.validate in place of Joi.validate, for example:
const schema = Joi.object({
name: Joi.string().min(3).required()
});
const result = schema.validate(req.body);
or for more info go to https://hapi.dev/family/joi/?v=16.1.8
I have made an PR to update the https://docs.nestjs.com and it looks like it is already deployed, so you can refer to it.
#hapijs/joi deprecated Joi.validate with version 16 and you have to call .validate directly on schema.

Testing Angular2 with Jasmine. Class property not being set

I am currently writing tests for my Angular2 (with Typescript) application and all has been fine and dandy so far, that is until I have attempted to start testing one of my services.
This service has the Angular2 Http module injected on instantiation as shown below:
import { Injectable, EventEmitter } from 'angular2/core';
import { Http } from 'angular2/http';
import 'rxjs/add/operator/map';
import { ConfigObject } from '../ConfigObject';
import { HTTPHelper } from '../helpers/HTTPHelper';
import { Category } from '../classes/Category';
#Injectable()
export class CategoryService {
public emitter: EventEmitter<Category>;
constructor(private _http: Http) {
this.emitter = new EventEmitter();
}
private APIUrl = ConfigObject.productBox + ConfigObject.apiVersion + 'category';
getCategories(filters) {
return this._http.get(this.APIUrl + HTTPHelper.convertVarsToString(filters))
.map(res => res.json());
}
public emitCat(category): void {
this.emitter.emit(category);
}
}
This is then used to make GET requests to an API box I have created.
Here is my Jasmine test spec file for the service:
import { CategoryService } from '../../services/category.service';
import { Http } from 'angular2/http';
describe('Category service', () => {
let testCategoryService: CategoryService;
let _http: Http;
beforeEach(function() {
testCategoryService = new CategoryService(Http);
});
it('should have emitter name set', () => {
expect(testCategoryService.emitter._isScalar).toBeDefined();
});
it('should return categories', () => {
testCategoryService.getCategories({
order : 'asc',
order_by : 'name',
parent_id : 0,
});
});
});
As you can see, am including the Http object here too and injecting it into the test instantiation of my service class before each test on this line:
beforeEach(function() {
testCategoryService = new CategoryService(Http);
});
When I try and test the 'getCategories' function on my service class I get the following error:
TypeError: this._http.get is not a function
Which is odd as as far as I am concerned I am injecting the Http service into my test instantiation on the line above so this should be set in the class constructor?
Can anyone see why the Http object in my class is not being set?
Thanks

Dynamic path in Angular2 Router

I'm looking for a way to receive the current server path as a string in Angular2, i.e.
http://localhost:3000/my/dynamic/path
How can I get: /my/dynamic/path
This should do it the Angular way
export class AppComponent {
constructor(private location:Location) {}
repoPath: string;
ngOnInit() {
this.repoPath = location.path();
}
}
Found it already:
export class AppComponent {
repoPath: string;
ngOnInit() {
this.repoPath = window.location.pathname;
}
}