How to get response of a nested api call using RxSwift and alamofire? - alamofire

How to get response of a nested api call using RxSwift and alamofire? Here i get a response from an alamofire api cal and with that result i need to call another api call. I want to get the second api call response. Can anyone suggest me a solution to solve this. please.
func origin() -> Observable<String> {
return Alamofire.request("httpbin.org/get").rx.responseJSON()
}
func otherApiCall(with origin: String) -> Observable<YourType> {
// Other api call using origin
return Alamofire...........
}
then
origin()
.flatMap{ origin in
otherApiCall(with: origin)
}
.subscribe(onNext: { response in
})
.disposed(by: disposeBag)

Your code is not explaining much but as per my understanding if you want to call api using other api's response than below code should work.
func firstRequest() -> Observable<firstRequestResponseType> {
return firstRequest
}
firstRequest
.flatMap { (firstRequestResponseType) -> Observable<secondRequestResponseType>
return secondRequest
}
.map { (secondRequestResponseType)
//you can user second request’s response here
}
.subscribe()

Related

Nestjs early return in interceptor sends [ERR_HTTP_HEADERS_SENT]

I am using interceptor on a controller to feed mock data if user is tagged as a demo user in the jwt
It works fine, mock data are fed to client and request doesn't reach my controller, but I still get following error in console :
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This is my interceptor :
#Injectable()
export class UserPageStatsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// Let controller handle request
if (!isDemo(context)) {
return next.handle();
}
// Feed mock datas
const res = context.switchToHttp().getResponse();
res.status(200).send('Demo data');
}
}
And here is my controller :
#Get('statistics')
#UseInterceptors(UserPageStatsInterceptor)
getUsersGlobalStatistics(
#Headers() headers: CustomHeaders,
#Query() filters: BasicFiltersDTO,
#Req() req,
): Promise<UserStatisticsDTO> {
return 'Real data';
}
I suspect that after my UserPageStatsInterceptor the request continues somewhere in the internal of nestjs framework but I haven't been able to find out where.
I have tried adding a returnor res.end() at the end but it doesn't change anything.
Note that this only happens when making queries on my frontend client and doesn't happen in postman
Thank you in advance guys !!
Instead of calling res.send() inside of your interceptor, why not just return an observable that has the data you want to return?
#Injectable()
export class UserPageStatsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// Let controller handle request
if (!isDemo(context)) {
return next.handle();
}
return of('Demo data');
}
}
This will let Nest still handle the response, and not get in the way of actually running your service code.

SPFx Graph API Response Handling

My SPFx webpart is working well until I try to return the result of an Graph API call. The below code is trying to get the users that have permissions to the root file library for the site the webpart is installed.
The console.log("Reached the Graph") shows up in the inspector console so I'm guessing it has something to do with the .push() I'm using to append each returned record to the response declared at the beginning of the method.
I also tried the more documented .forEach() below without success. Any Ideas?
private _loadUser(): MicrosoftGraph.Permission[] {
let response: MicrosoftGraph.Permission[];
this.props.context.msGraphClientFactory
.getClient()
.then((client: MSGraphClient): void => {
let apiUrl: string = '/groups/'+this.props.group+'/drive/items/root/permissions';
client
.api(apiUrl)
.version("v1.0")
.get((error?, result?: MicrosoftGraph.Permission[], rawResponse?: any) => {
// handle the response
if(error){
console.error(error);
}
if (result) {
console.log("Reached the Graph");
for (let res of result){
response.push(res);
}
}
}
);
});
return response;
}
result.forEach(element => {
response.push(element);
console.log(element.grantedTo.user.displayName);
});

i18n-backend with oauth2 authorization in spartacus

We want to use a backend for i18n in spartacus. Unfortunately this backend needs an oauth2 authentication but spartacus does not send a bearer token when trying to access this webservice endpoint and we get a 401 error. Is there anything we can do?
Right now we try to solve this problem in this way:
What we need to have is implemented in ClientTokenInterceptor, so we adapted this interceptor, changed the if-clause a little bit so it fits to the backend-url for this webservices and provide the interceptor via app.module.ts which works so far. Unfortunately calling this.authService.getClientToken() in our Interceptor returns no token.
constructor(
private authService: AuthService,
private occEndpoints: OccEndpointsService
) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return this.getClientToken(request).pipe(
take(1),
switchMap((token: ClientToken) => {
if (
token &&
request.url.includes("i18n")
) {
request = request.clone({
setHeaders: {
Authorization: `${token.token_type} ${token.access_token}`,
},
});
}
return next.handle(request);
})
);
}
private getClientToken(request: HttpRequest<any>): Observable<ClientToken> {
if (
InterceptorUtil.getInterceptorParam(USE_CLIENT_TOKEN, request.headers)
) {
return this.authService.getClientToken();
}
return of(null);
}
What do we miss?
Actually there are couple of things not needed in your solution.
I pasted below what I did instead and tested that it is working correctly (and you can see authorization data in the translation files requests).
First issue:
InterceptorUtil.getInterceptorParam(USE_CLIENT_TOKEN, request.headers) you don't need to check that. If you always need the auth data for translation requests just use return this.authService.getClientToken();
Second issue:
In intercept method you didn't cover cases for any other request than translation. Because of that the request for the client token would hang here, because it would wait for token and so on. If you add option for any other case than i18n it starts working as you intend.
Working solution:
#Injectable({ providedIn: 'root' })
export class TranslationsInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request?.url?.includes('i18n')) {
return this.getClientToken().pipe(
take(1),
switchMap((token: ClientToken) => {
if (token) {
request = request.clone({
setHeaders: {
Authorization: `${token.token_type} ${token.access_token}`,
},
});
}
return next.handle(request);
})
);
} else {
return next.handle(request);
}
}
private getClientToken(): Observable<ClientToken> {
return this.authService.getClientToken();
}
}

Forward fetch response headers to Apollo graphql response

I have an apollo-datasource-rest data source setup on an Apollo/Graphql
Expressjs server. I'd like to forward a few headers from the fetch response to the /graphql response.
Here is the flow:
POST /graphql
Graphql makes fetch request using this.get('http://example.com/api')
Response from this fetch contains the header "cache-status"
Response from /graphql
I'd like to include the "cache-status" header from the example.com/api response here in the /graphql response
I see the header in the didReceiveResponse() method of the rest datasource class. I'm not sure this is the right place to access and store it. How do I include the "cache-status" header in the POST /graphql response?
Assuming you're RESTDataSource from apollo-datasource-rest, you can override the didReceiveResponse to intercept the response and return a custom return value.
Here's a code snippet in Typescript, it can be easily converted to Javascript if need be by removing the parameter/return types and access modifiers.
class MyRestDataSource extends RESTDataSource {
public constructor(baseUrl: string) {
super();
this.baseURL = baseUrl;
}
public async getSomething(): Promise<any & { headers?: { [key: string]: string } }> {
// make the get request
return this.get('path/to/something');
}
// intercept response after receiving it
protected async didReceiveResponse(response: Response, _request: Request) {
// get the value that is returned by default, by calling didReceiveResponse from the base class
const defaultReturnValue = await super.didReceiveResponse(response, _request);
// check if it makes sense to replace return value for this type of request
if (_request.url.endsWith('path/to/something')) {
// if yes get the headers from response headers and add it to the returned value
return {
...defaultReturnValue,
headers: { headerValue: response.headers.get('header_name') },
};
}
return defaultReturnValue;
}
}
I think you can utilize formatResponse of ApolloServerLambda()
And respond with proper headers. I have not tried it myself. But looking at the document I feel it should be helpful
formatResponse?: (
response: GraphQLResponse,
requestContext: GraphQLRequestContext<TContext>,
) => GraphQLResponse | null;

How to call Http post and get request in angular 6

I am updating my application from MEANAngular4 to MEANAngular6 but still don't know how to do http post/get requests. Thats how I did it in Angular 4
registerUser(user) {
return this.http.post(this.domain + 'authentication/register', user).map(res =>
res.json());
}
First you'd notice that you don't need map part because, when the response comes it will already be unwrapped for you.
And also return observable from the api wrapper function and using it will be as simple as I have shown you with the one line below the function.
registerUser(user: any) : Observable<any> {
return this.http
.post(this.domain + 'authentication/register', user);
}
let result = await registerUser(user).toPromise();
import { map } from "rxjs/operators";
registerUser(user: any) {
return this.http.post(this.domain + 'authentication/register', user).pipe(map(res =>
res.json()));
}