problem in making http.get() request in flutter - api

i am learing about api's and http request in flutter and i am facing problem in making a get request as in any tutorial they are directly pasting string url inside get as parameter but when i post it as string it is showing error: The argument type 'String' can't be assigned to the parameter type 'Uri'.
can any one help me in this :
this is my sample code :
import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
void main(List<String> arguments) async {
// This example uses the Google Books API to search for books about http.
// https://developers.google.com/books/docs/overview
var url = 'https://www.googleapis.com/books/v1/volumes?q={http}';
// Await the http get response, then decode the json-formatted response.
var response = await http.get(url); // i am getting error here
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body);
var itemCount = jsonResponse['totalItems'];
print('Number of books about http: $itemCount.');
} else {
print('Request failed with status: ${response.statusCode}.');
}
}
here is image of my code with error
enter image description here

first import http as http
import 'package:http/http.dart' as http;
then parse your link to Uri using
var url = Uri.parse('https://www.googleapis.com/books/v1/volumes?q={http}');
http.Response response = await http.get(url);
try {
if (response.statusCode == 200) {
String data = response.body;
var decodedData = jsonDecode(data);
return decodedData;
} else {
return 'failed';
}
} catch (e) {
return 'failed';
}

If still doesn't work try this:
import 'package:http/http.dart';
var response = get(Uri.parse('https://www.google.com'));

Try this (Add http to pubspec.yaml under dependencies):
import 'package:http/http.dart' as http;
var response = http.get(Uri.parse('https://www.google.com'));

You passing string the error says need an uri so create an uri and use in it.
var uri = new Uri.http("example.org", "/path", { "q" : "{http}" });

First of all, check your pubspec.yaml file and HTTP version. It should be the actual one you can find here: https://pub.dev/packages/http/install
For example, it is:
http: ^0.12.2
at the moment
Here is my code and it works well:
main.dart
import 'package:flutter/material.dart';
import 'package:stackowerflow/my_app.dart';
void main() {
runApp(MyApp());
}
my_app.dart
import 'dart:convert' as convert;
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class MyApp extends StatelessWidget {
Future<void> stackHelp() async {
var url = 'https://www.googleapis.com/books/v1/volumes?q={http}';
// Await the http get response, then decode the json-formatted response.
var response = await http.get(url);
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body);
var itemCount = jsonResponse['totalItems'];
print('Number of books about http: $itemCount.');
} else {
print('Request failed with status: ${response.statusCode}.');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView '),
),
body: Container(
child: TextButton(onPressed: stackHelp, child: Text('Push me')),
),
),
);
}
}
RESULT
flutter: Number of books about http: 485.

Related

How to call an async method in initState in flutter

I need to get some information from an endpoint. I have this method:
List<Widget> cardsList = List();
List<dynamic> cardsId = List();
addToList() async {
var jsonData = await Provider.of<CardData>(context).cardsList;
print(jsonData);
for (var i = 0, len = jsonData.length; i < len; i++) {
if (jsonData[i]['account_type'] == "1") {
cardsList.add(
BankCard(
bankName: jsonData[i]['title'],
colors: [Color(0xFFD00E00), Color(0xFFF44336)],
cardNumber: jsonData[i]['number'],
cardDesc: jsonData[i]['description'],
),
);
cardsId.add(jsonData[i]['id']);
}
}
}
and a class as provider data called CardData:
import 'package:flutter/material.dart';
import '../cards/cards.dart';
class CardData extends ChangeNotifier {
static Cards cards = Cards();
Future<dynamic> cardsList = cards.getCards();
}
and a class called Card to send request and doing all other stuff:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
class Cards {
String _accessToken;
String _refreshToken;
Future<dynamic> getCards() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
_accessToken = sharedPreferences.getString("access");
_refreshToken = sharedPreferences.getString("refresh");
var jsonData;
var response = await sendRequestToGetCards(
url: "http://10.0.2.2:8000/accounts/list/", accessToken: _accessToken);
if (response.statusCode == 200) {
jsonData = json.decode(utf8.decode(response.bodyBytes));
return jsonData;
} else if (response.statusCode == 401) {
_accessToken = await getNewAccessToken(_refreshToken);
response = await sendRequestToGetCards(
url: "http://10.0.2.2:8000/accounts/list/",
accessToken: _accessToken);
if (response.statusCode == 200) {
jsonData = json.decode(utf8.decode(response.bodyBytes));
return jsonData;
}
}
}
getNewAccessToken(String refreshToken) async {
var refreshResponse = await http.post(
"http://10.0.2.2:8000/users/api/token/refresh/",
body: {'refresh': refreshToken});
if (refreshResponse.statusCode == 200) {
var jsonData = json.decode(refreshResponse.body);
return jsonData['access'];
}
}
sendRequestToGetCards({String url, String accessToken}) async {
var response = await http.get(
url,
headers: {"Authorization": "Bearer $accessToken"},
);
return response;
}
}
But when I call addToList method in initState to retrieve data before build method, the main UI disappears.
What's wrong with it?
You can call async function in the initState, but as it itself is not an async function it will not wait for futures to complete before moving on to the build method, which is why your UI disappears because it is building with no data so there are no cards. I would suggest using a FutureBuilder in your build method to build when the async function returns.

Angular 6 Http client custom url and header

I am working in an Angular 6 application and I was wondering what should be the best practice when customizing the url while sending requests to the server.
Here is the scenario:
- In my Angular project I have the environment.ts and environment.prod.ts where I added a "host" which contains the url:port of the http server (project with the controllers).
- I am creating Services to be injected in my components which will be responsible for sending requests (GETs and POSTs) to the server to retrieve data or to send updates.
- I want to use the "host" from the environment.ts as part of the request url. So ALL my requests will have the "host" as the base url and then i can concatenate to the desired path.
I already checked a few solutions and I already implemented one of them, but I am not sure this is the right practice. I will write below what i implemented so far and then i will write some ideas, please help me understand what is the best solution (I am new at angular)
Currently implemented:
-> In my feature services, like LoginService, I inject the angular HttpClient. Then I simply call:
return this.httpService.post("/login/", creds).pipe(
map((data: any) => {
this.manager = data;
return this.manager;
}));
I created an interceptor to make changes to the url: InterceptService implements HttpInterceptor where I create a new instance of the HttpRequest and customize the request.url using environment.host. I also needed the interceptor to add a Header for the authentication (still not fully implemented)
const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
request = Object.assign(request, httpRequest);
const headers = new HttpHeaders({
'Authorization': 'Bearer token 123',
'Content-Type': 'application/json'
});
Questions:
1) This works, all my requests are changed in the interceptor as I
wanted, but it doesn't look like the best practice in my first look. I
don't like to create a new HeepRequest to be able to do this (i did it
to keep it immutable, I guess that's the correct way). Do you think
this looks good?
2) What about the Authentication being added to the Header in the interceptor? Is it ok? Most of the references I checked did this
Other solutions:
1) I saw some examples where a HttpClientService extends Http and each of the methods such as get and post edit the url and headers before calling super methods. But I believe this is not Angular 6 and is probably not preferrable
2) I could also create a service that receives an angular HttpClient (angular 6 HttpClientModule) instance by injection and I could implement the methods like get or post.
Well, as I didn't get any answers I will add my solution. i believe it's the best solution based on my researches.
I used an interceptor for adding information to the header such as the
token bearer authentication.
import { Injectable } from '#angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpResponse,
HttpHeaders,
HttpErrorResponse
} from '#angular/common/http'
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { environment } from "../../../environments/environment";
import { Router } from "#angular/router";
export class HttpClientInterceptor implements HttpInterceptor {
constructor(private router: Router) { }
// intercept request to add information to the headers such as the token
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//I decided to remove this logic from the interceptor to add the host url on the HttpClientService I created
//const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
//request = Object.assign(request, httpRequest);
var token = localStorage.getItem("bearerToken");
if (token) {
const newReq = request.clone(
{
headers: request.headers.set('Authorization',
'Bearer ' + token)
});
return next.handle(newReq).pipe(
tap(event => {
if (event instanceof HttpResponse) {
console.log("Interceptor - HttpResponse = " + event.status); // http response status code
}
}, error => {
// http response status code
if (error instanceof HttpErrorResponse) {
console.log("----response----");
console.error("status code:");
console.error(error.status);
console.error(error.message);
console.log("--- end of response---");
if (error.status === 401 || error.status === 403) //check if the token expired and redirect to login
this.router.navigate(['login']);
}
})
)
}
else {
return next.handle(request);
}
};
For changing the url, I created a service on file
http-client.service.ts and got the host url from environment.ts
import { Injectable } from "#angular/core";
import { HttpClient } from '#angular/common/http';
import { Observable } from "rxjs";
import { environment } from "../../../environments/environment";
#Injectable({ providedIn:'root' })
export class HttpClientService {
constructor(private http: HttpClient) { }
get(url: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.get(url, options);
}
post(url: string, body: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.post(url, body, options);
}
put(url: string, body: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.put(url, body, options);
}
delete(url: string, options?: any): Observable<ArrayBuffer> {
url = this.updateUrl(url);
return this.http.delete(url,options);
}
private updateUrl(req: string) {
return environment.host + req;
}
}
As i said, I believe this is the best approach, but feel free to add information to my question/answer.

How write header with nestjs

how I can write headers using way nest.js?
I'm currently using this:
import { Controller, Body, Get, Post, HttpCode, HttpStatus, Req, Res } from '#nestjs/common';
import { Request, Response } from 'express';
import { AuthService } from './auth.service';
import { Usuario } from '../usuario/usuario.entity';
import { JsonWebTokenError } from 'jsonwebtoken';
import { request } from 'http';
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) { }
#Post('login')
#HttpCode(HttpStatus.OK)
async login(#Body('username') username: string, #Body('password') password: string, #Res() response: Response) {
this.authService
.validateUser(username, password)
.then((token) => {
response.setHeader('Authorization', 'Bearer ' + token);
let respuesta: any = {};
respuesta.success = true;
respuesta.token = token;
return response.send(respuesta);
});
}
}
I do not want to use response.setHeader('Authorization', 'Bearer ' + token); and return response.send(respuesta);
Thanks for your answers!
NestJS is build on top of express, so do it like in express:
async login(#Body('username') username: string, #Body('password') password: string, #Res() res: Response) {
const token = await this.authService.validateUser(username, password);
res.set('Authorization', 'Bearer ' + token);
res.send({
success: true,
token,
})
});
In latest versions you could use the #Header decorator within NestJS Core.
import { Controller, Get, Req, Header, Res } from '#nestjs/common';
import { Request, Response } from 'express';
#Controller('cookies')
export class CookiesController {
#Get('set')
// #Header('Set-Cookie', 'cookieName = 12345') // "Usin header decorator"
setCookie(#Res() response: Response): Response {
/*
* If using express approach, pass #Res as param decorator
*/
response.cookie('rememberme', '1') // Using express res object.
return response.send('Cookie has been set! :)')
}
#Get()
checkCookie(#Req() request: Request ): string {
console.log(Object.keys(request.cookies))
if(Object.keys(request.cookies).length > 0){
console.log('cookies =>', request.cookies)
return 'Cookies are set :)'
} else {
return 'Uh, oh! Cookie hasn\'t been set :\'('
}
}
}

Two API call in single sesrvices

First I'm new new to angular 2. I'm trying to call two difference API in single service. But it wont return any value second API 'getCityById' but the API 'getCities' return the value.
Here my code:
import { Injectable } from '#angular/core';
import { Http, Headers,Response} from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { Cities } from './cities';
#Injectable()
export class CitiesService {
private CityListUrl = "APIurl";
private CityUrl = "APIurl2";
constructor(private http: Http) {}
getCities(): Observable<Cities[]> {
const headers = new Headers();
headers.append('Access-Control-Allow-Headers', 'Content-Type');
headers.append('Access-Control-Allow-Methods', 'GET,PUT,POST,OPTIONS');
headers.append('Access-Control-Allow-Origin', '*');
return this.http.get(this.CityListUrl,{headers: headers})
.map(this.extractData)
.catch(this.handleError);
}
getCityById(CityId:Number): Observable<any> {
const headers = new Headers();
headers.append('Access-Control-Allow-Headers', 'Content-Type');
headers.append('Access-Control-Allow-Methods', 'GET,PUT,POST,OPTIONS');
headers.append('Access-Control-Allow-Origin', '*');
var params = 'cityid='+CityId;
console.log("____________"+this.CityUrl);
console.log(this.http.post(this.CityUrl,params,{headers: headers})
.map(this.extractData));
return this.http.post(this.CityUrl,params,{headers: headers})
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
console.log(res);
let Cities = res.json();
return Cities || { };
}
private handleError(error: Response) {
console.log(error);
return Observable.throw(error.json().error || "500 internal server error");
}
}
I'm not sure what I'm wrong. Please help with this.

Reponse Preflight and Request header not allowed in Angular 2

I am Working on Angular 2 for getting data from WCF service.
I am calling Login method that returns a token.
For fetching Project Data i am using GET method and in that request we need to pass token in header.
But it gives Error:
XMLHttpRequest cannot load http://192.168.0.149/API/Service1.svc/Datalist. Response for preflight is invalid (redirect). Request header field token is not allowed by Access-Control-Allow-Headers in preflight response.
This are my Headers:-
General:
Request URL:http://pct149/ITM_API/Service1.svc/BHL/Projects
Request Method:OPTIONS
Status Code:200 OK
Remote Address:192.168.0.149:80
Here is my Angular Service in which i am calling WCF Service:-
import {Injectable} from "#angular/core"
import { Http, Response, RequestOptions, Headers } from "#angular/http"
import { Observable } from 'rxjs/Rx';
import {HttpClient } from "#service/http-client";
#Injectable()
export class AppService {
Hero = [];
baseUrl = "http://pct149/ITM_API/Service1.svc/BHL/";
constructor(private _http: Http, private httpClient: HttpClient) {
}
Authentication() {
return this._http.get(this.baseUrl + "Login/harshad.bhola#server1.com/1")
.map((response: Response) => {
let dataToken = response.json();
let Token = dataToken.Token;
if (Token != null & dataToken != null) {
return Token;
}
else {
return '';
}
})
.catch(this.handleError);
}
loadProjects(Token) {
return this._http.get(this.baseUrl + "Projects", { headers: { 'token': Token.trim() } })
.map((responseData: Response) => {
let appData = responseData.json();
console.log(appData);
return appData;
});
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
Here is my Component from where i am calling service method:-
import {Component} from "#angular/core";
import { RouterOutlet, RouterLink, RouterModule, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from "#angular/router";
import { HTTP_PROVIDERS, HTTP_BINDINGS } from '#angular/http';
import {AppService } from "#service/app.service";
#Component({
selector: 'app',
templateUrl: 'htmls/app.html',
directives: [ROUTER_DIRECTIVES],
providers: [AppService]
})
export class ProjectListComponent {
Projects = [];
result = '';
constructor(private _appService: AppService) {
this.GetProject();
}
GetProject() {
this._appService.Authentication().subscribe(result => {this._appService.loadProjects(result).subscribe(newProject => this.Projects = newProject); });
}
}
Below Code i put in Global.asax of My WCF Service:-
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.Flush();
}
}
Please Help me if i am Wrong.
You need to add options to your list of supported methods in your CORS enablement. I'm using webapi 2 so I do this:
from webApiConfig.cs:
var cors = new EnableCorsAttribute("*", "*", "GET,PUT,POST,PATCH,DELETE,OPTIONS");
I also had to trap the preflight request and add the required header:
from global.asax.cs:
protected void Application_BeginRequest()
{
var req = HttpContext.Current.Request;
var res = HttpContext.Current.Response;
var val = res.Headers.GetValues("Access-Control-Allow-Origin");
if (val == null)
{
if (!req.Url.ToString().ToLower().Contains("token") || (req.Url.ToString().ToLower().Contains("token") && req.HttpMethod == "OPTIONS"))
{
res.AppendHeader("Access-Control-Allow-Origin", "http://localhost:4200");
}
}
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
res.AppendHeader("Access-Control-Allow-Credentials", "true");
res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
res.StatusCode = 200;
res.End();
}
}
Hope this helps.