I'm working on the test driven angular app. (Don't ask why, That is how client wants)
Below is the spec which I can't modify or edit.
it('should get results', fakeAsync(
inject(
[XHRBackend, NewsService ],
(mockBackend: MockBackend, newsService: NewsService) => {
const expectedUrl = 'https://api.nytimes.com/svc/topstories/v2/home.json?api-key=315a5a51483b469a918246dc2753b339';
mockBackend.connections.subscribe((connection : MockConnection) => {
expect(connection.request.method).toBe(RequestMethod.Get);
expect(connection.request.url).toBe(expectedUrl);
connection.mockRespond(new Response(
new ResponseOptions({ body: mockResponse })
));
});
newsService.getSectionNews('home')
.subscribe( (res: any) => {
expect(res).toEqual(mockResponse);
});
})
));
So based on the spec, I need to write my front end code.
So this is what I've written,
import { Http } from '#angular/http';
constructor(private http: Http) {}
getSectionNews(sectionName: string): any {
// fetch news of that sectionName
// return this.mockResponse;
const expectedUrl = 'https://api.nytimes.com/svc/topstories/v2/home.json?api-key=315a5a51483b469a918246dc2753b339';
return this.http.get(expectedUrl).subscribe(res => res);
}
But while running the test case, I'm getting this error:
TypeError: newsService.getSectionNews(...).subscribe is not a function
please tell me what I'm doing wrong here.
I wanted to pass the test case.
UPDATE
After updating my service spec.
getSectionNews(sectionName: string): Observable<any> {
const expectedUrl = `https://api.nytimes.com/svc/topstories/v2/${sectionName}.json?api-key=315a5a51483b469a918246dc2753b339`;
return this.http.get(expectedUrl);
}
Now I'm getting this below error,
Expected Response with status: null null for URL: null to equal
Objectt({ status: 'OK', copyright: 'C ...
Related
I'm having a problem with a firebase function, using admin api to read then write to firestore.
See the code below:
I've commented by 2 console logs, which takes between 2-5 minutes to execute. The dataset in firestore is small (only a few records). Any advise on what I'm clearly doing wrong please?
Thanks
(edited as requested with rest of code. This is taken direct from Stripe's github examples)
const processTheOrderApp = express();
processTheOrderApp.post(
'/',
bodyParser.raw({ type: 'application/json' }),
(
request: { headers: { [x: string]: any }; rawBody: any },
response: {
status: (
arg0: number
) => { (): any; new (): any; send: { (arg0: string): any; new (): any } };
json: (arg0: { received: boolean }) => void;
}
) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
} catch (err) {
console.log(err);
return response.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
addPaymentDataToOrder(session); // Here we can proccess the order data after successfull payment
// (e.g. change payment status in Firebase Database and call another function)
}
// Return a response to acknowledge receipt of the event
response.json({ received: true });
}
);
// Exporting our http function
exports.processTheOrder = functions.https.onRequest(processTheOrderApp);
function addPaymentDataToOrder(session: any) {
console.log('adding payment'); ////between this console log
admin
.firestore()
.collection('orders')
.where('paymentSessionId', '==', session.id)
.limit(1)
.get() // getting the order which matches the session id, should be only one so limited to one result
.then((query: any) => {
console.log('found item'); ////and this console log
const thing = query.docs[0];
var orderDoc = thing.data();
thing.ref.update({
checkedOut: true,
payment: session,
});
});
}
It's slow because if a function in the firebase cloud functions is not called/invoked in 2 minutes, it goes into a cold start. Check out this reference.
https://medium.com/#siriwatknp/cold-start-workaround-in-firebase-cloud-functions-8e9db1426bd3
*** - Hi guys, I've been having a problem for days. I am trying to populate
an object with the result of a query to a JSON API. I need to fill in
a model because through it I need to nail a key to make another query
in another api and return the data on the screen. But so far all I
can get is undefined
To better understand I need to fill the generation Object so that through it I can fill the data of another object and get a url to query another endpoint api and return other data from the screen.
export class PokeApp implements OnInit {
gen1: Generation[];
gen2: Generation[];
generation : Generation;
constructor(private http: HttpClient, private gService:GenerationService) {
}
ngOnInit(){
this.getGeneration1();
this.getGeneration2();
// Only for test, this is not the data ho i need - but this object generation returns null, i do not now how.
this.gService.getPokemon_Species(this.generation.name);
}
// this request return a gen1 object to my screen, but a need this object in JS code
// to do another query.
getGeneration1(): void{
this.gService.getGeneration1().subscribe(gen =>{
this.gen1 = gen
this.generation = gen[0];
});
}
getGeneration2(): void{
this.gService.getGeneration2().subscribe(gen => this.gen2 = gen);
console.log("Still Returned Undefined___>>>>" + this.generation);
}
// this do the request to a Poke API
export class GenerationService {
private GetGenerationURL1 = "https://pokeapi.co/api/v2/generation/1";
private GetGenerationURL2 = "https://pokeapi.co/api/v2/generation/2";
httpOptions = { headers: new HttpHeaders({ "Content-Type": "application/json" }) };
constructor(private http: HttpClient) { }
getGeneration1(): Observable<Generation[]> {
return this.http.get<Generation[]>(this.GetGenerationURL1)
.pipe(
tap(_ => console.log('fetched generations')),
catchError(this.handleError<Generation[]>('getGeneration1', []))
);
// Subscribe to begin listening for async result
}
getGeneration2(): Observable<Generation[]> {
return this.http.get<Generation[]>(this.GetGenerationURL2)
.pipe(
tap(_ => console.log('fetched generations')),
catchError(this.handleError<Generation[]>('getGeneration2', []))
);
}
getPokemon_Species(url: string): Observable<Pokemon[]> {
console.log("___>>>>${generation}" + url);
return this.http.get<Pokemon[]>(url)
.pipe(
tap(_ => console.log('fetched Species')),
catchError(this.handleError<Pokemon[]>('getPokemon_Species', []))
);
}
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
console.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
}
Update
So the issue actually is with the typings. You don't need to add the [] after the the Generation anywhere. As there isn't any place that the API will respond with an Array of Generations.
So remove the [] from the returning type of getGeneration1 and in the typed response of the HTTP in the service.
Please note that the typings in Typescript are only for compiling time, it doesn't affect anything in the runtime, just to make sure you are using the right references and detect errors before runtime.
I'm adding the getGeneration functions here:
getGeneration1(): Observable<Generation> {
return this.http.get<Generation>(this.GetGenerationURL1)
.pipe(
tap(_ => console.log('fetched generations')),
catchError(this.handleError<Generation>('getGeneration1', []))
);
}
getGeneration2(): Observable<Generation> {
return this.http.get<Generation>(this.GetGenerationURL2)
.pipe(
tap(_ => console.log('fetched generations')),
catchError(this.handleError<Generation>('getGeneration2', []))
);
}
In the component, you will need to refactor it like this:
export class PokeApp implements OnInit {
gen1: Generation;
gen2: Generation;
generation : Generation;
constructor(private http: HttpClient, private gService:GenerationService) {
}
ngOnInit(){
this.getGeneration1();
this.getGeneration2();
this.gService.getPokemon_Species(this.generation.name);
}
getGeneration1(): void{
this.gService.getGeneration1().subscribe(gen =>{
this.gen1 = gen
this.generation = gen;
});
}
getGeneration2(): void{
this.gService.getGeneration2().subscribe(gen => this.gen2 = gen);
}
This is in case you still need your code in the component to work without chaining the responses as I provided in the old answer, but I suggest to refactor your code same as this:
getGenerations() {
this.gService.getGeneration1()
.pipe(mergeMap(gen => {
this.generation = gen;
return this.gService.getGeneration2();
}))
.pipe(mergeMap(gen => {
return this.gService.getPokemon_Species(this.generation.name);
}))
.subscribe(response => console.log(response));
}
Old Answer
You well need to use mergeMap. It should be something like this:
getGenerations() {
this.gService.getGeneration1()
.pipe(mergeMap(gen => {
this.gen1 = gen;
this.generation = gen[0];
return this.gService.getGeneration2();
}))
.pipe(mergeMap(gen => {
this.gen2 = gen;
return this.gService.getPokemon_Species(this.generation.name);
}))
.subscribe(response => console.log(response));
}
I am trying to implement a logging interceptor in nestjs such that, it captures all the requests and responses and logs it.
Hence I implemented a LoggingInterceptor like this
import { logger } from './../utils/logger';
import { ExecutionContext, Injectable, NestInterceptor } from '#nestjs/common';
import { Observable, BehaviorSubject, from } from 'rxjs';
import { map, tap, refCount, publish, publishLast } from 'rxjs/operators';
#Injectable()
export class LoggingInterceptorInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> {
const reqHeaders = context.switchToHttp().getRequest().headers;
const reqBody = context.switchToHttp().getRequest().body;
logger.info('Logging the incoming request:',reqHeaders);
logger.info('Logging the incoming req body:', reqBody);
const now = Date.now();
logger.info('Time of request call is', now);
const serviceBehaviorSubj = new BehaviorSubject<any>(null);
// response will be available only in the call$ observable stream
// so use tap to get a clone of the observable and print the data sent
// this pipe call transforms the response object to start with something called data
// so a default response like "Done", "test" looks now as a json string
// {data : Done} {data: test}
// const anotherrespObs: Observable<any> = call$.pipe(publishLast(), refCount());
// anotherrespObs.pipe(publishLast(), refCount()).subscribe(data => {
// logger.info('Logging the outgoing response', data);
// });
return call$.pipe(map(data => {
console.log('data here is', data);
return ({ dottted: data });
}));
//oo.then(return new Pro)
// return call$.pipe(tap(() => {
// logger.info(`Time of completion is ${Date.now() -now}`);
// }), map(data => {
// console.log('ccccccc', data);
// return data;
// }));
}
}
I understand that call$ operator behaves like an Observable and that will be subscribed internally by nestjs to send the response to client, but I wanted to log the information before being sent and possibly transform the response
So I make use of the map() operator of rxjs. This functions properly if the response set is of type other than 'application/json'. If the Content-Type
is of 'plain/text', the map operation gets applied and gets transformed to the desired json object and sent to the client but not in the case if the response is already of type application/json, i.e a json object. I am unable to apply the transform object. On logging the value sent to map(), I see it gets logged as undefined for json objects. So how do I get the response (even if it a json object) and possibly log it and transform it before sending it to the client in the interceptor
Note: I am wary that the response might contain sensitive information, but I probably would use log masking to just mask the response data, but this is currently for testing purposes
Here is the sample controller for which I am able to log the response in the interceptor
#ApiOperation({ title: 'Get - With Params', description: 'Test Method with parms' })
#Get('/getTest/:id1/:id2')
#ApiOkResponse({ description: 'Sample string is emitted' })
#ApiResponse({ status: 404, description: 'The endpoint is unavailable' })
#ApiResponse({ status: 503, description: 'The endpoint cannot be processed' })
// #Header('sampleHeaderKey', 'sampleHeaderValue')
// NOte if you send params in the URL and do not use #param then the URL will
// result in NO such end point
public getConfigDataInResponse(#Param('id1') id1: number, #Param('id2') id2: number, #Req() req) {
logger.info('request headers', req.headers);
logger.info('reqiest params', req.params);
logger.info('reqiest query params', req.query);
logger.info('reqiest body ', req.body);
return 'TEST';
}
And here is the method for which the response cannot be logged, it comes as "undefined" in the interceptor
public getConfigDataInResponse(#Param('id1') id1: number, #Param('id2') id2: number, #Req() req, #Res() res) {
logger.info('request headers', req.headers);
logger.info('reqiest params', req.params);
logger.info('reqiest query params', req.query);
logger.info('reqiest body ', req.body);
res.set('SampeHeader', 'saomevaluie');
res.status(HttpStatus.OK).send('some data');
}
When you inject #Res() in your controller method, a lot of the features that make nest so great like interceptors won't work.
In most cases, you do not need to inject #Res() because instead you can use dedicated decorators. In your example that would be:
// Sets the http response code (default for POST is 201, for anything else 200)
#HttpCode(204)
// Sets a custom header
#Header('SampleHeader', 'somevalue')
#Get('/getTest/:id1/:id2')
public getConfigDataInResponse(#Param('id1') id1: number, #Param('id2') id2: number) {
return 'some data';
}
I am using ionic 3 native HTTP to do a POST request to my backend server which returns JSON data but when I try to access the object from the variable I get an error:
[ts] Property 'InRepair' does not exist on type '{}'.
any
Not sure what I am doing wrong.
I made my POST request function a provider and here is the code for that
HttpProvider.ts
import { HTTP } from '#ionic-native/http';
#Injectable()
export class TekItapiProvider {
apiURL = 'myAPISeverURL';
constructor(private http: HTTP) {
}
doPost(url, data) {
var endpointURL = this.apiURL + url;
return new Promise((resolve, reject) => {
this.http.post(endpointURL, data, this.headers)
.then(data => {
resolve(data.data);
})
.catch(error => {
console.log(error.status);
reject(error);
})
})
}
}
This is where it is being called and where I try to access the object. In status I can access .completed because it gives me the error: [ts] Property 'InRepair' does not exist on type '{}'.
any
request.ts
this.httpProvider.doPost(myURL, '')
.then((status) => {
if (status.completed == 'Yes') {
}
},(err) => {
})
Do you guys know what I am doing wrong here?
I am running app on localhost://3000 with npm server
Services file:
import {Injectable} from "#angular/core";
import {Jsonp} from "#angular/http";
import 'rxjs/add/operator/map';
#Injectable()
export class futScoreService{
constructor(private _jsonp:Jsonp){}
getCompetitions(){
let queryString ='?callback=JSONP_CALLBACK';
return this._jsonp.get('http://api.football-data.org/v1/competitions/' + queryString,{method: 'Get'})
.map((res) => res.json());
}
}
Component file:
ngOnInit(){
this._futScoreService.getCompetitions().subscribe(
(comp)=>{
console.log(comp);
},
(err)=>{
console.log(err);
}
);
}
And I'm getting this error in console console-error
and on network tab I get object from API network-tab
Ok solution was making get request with http module and providing header with get request. Header part was main reason why it was failing.
let headers = new Headers({'X-Mashape-Key':'Ns0SkjyRRomshq3PgEnGoz2Zkc71p1CYnWajsnphGctvrGt46W'});
headers.append( 'Accept', 'application/json');
return this._http.get("http://api.football-data.org/v1/competitions/",{
headers: headers
})
.map((res) => res.json());
Angular is replacing JSONP_CALLBACK with
__ng_jsonp____req0_finished
but it should be
__ng_jsonp__.__req0.finished
Inspect your Network response. If you see __ng_jsonp____req0_finished({...json object...}) this is the problem.
Also, some services have different requirements for the callback query string parameter, which proves to be nasty because the error is exactly the same. I was using &callback=__ng_jsonp__.__req0.finished with MailChimp which produced the same error but the response had only a json object and no callback function. This is because MailChimp's spec is to use &c= instead of &callback=
When hardcoding the Jsonp callback (re: JSONP_CALLBACK issue) you need to account for the number of calls made, as Angular persists the state of each call. An example of what I'm doing for Mailchimp:
addEmailToList(email: string, listId: string, jsonpCalls: number, callback: any) {
const cbJsonp = '__ng_jsonp__.__req' + jsonpCalls + '.finished';
let url = [
'http://',
host,
'/subscribe',
'/post-json',
].join('');
let queryParams: URLSearchParams = new URLSearchParams();
queryParams.set('u', Config.MAILCHIMP_API_KEY);
queryParams.set('id', listId);
queryParams.set('EMAIL', email);
queryParams.set('c', cbJsonp); // non-standard; varies by service; usually 'callback'
...
}
this._InstUrl = "your url";
let params1 = new URLSearchParams();
//params.set('search', term); // the user's search value
//params.set('action', 'opensearch');
params1.set('format', 'json');
//params1.set('callback', "ng_jsonp.__req0.finished");
params1.set('callback', "JSONP_CALLBACK");
return this._jsonp
.get(this._InstUrl, { search: params1 })
.map(response => { debugger; this.Result = response.json().data })
.subscribe(
(data) => {
debugger
console.log(this.Result);
},
(error) => {
debugger
console.log(error);
});