I've started to learn Dart, but I stuck.
I follow this tutorial but something goes wrong.
Here is the problem: I would like to reach out to an API and fetch data from it. Nice!
I've imported packages for doing requests and converting. API returns the data correctly. HTTP GET is working.
The troubles came when I tried to assign json.decode(response.body) to Map().
It always says: The argument type dynamic cannot be assigned to the parameter type Map<String, dynamic>.
Could someone explain why that it's happening and how to handle it?
I'm using Android Studio. I'm invoking the function in the StatefulWidget:
var trends = fetchData('getAll', params);
where params is a Map().
The code:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<ApiResponse> fetchData(String command, Map params) async {
final String url =
'https://example.com/api/v2/....';
final response = await http.get(url);
if (response.statusCode == 200) {
return ApiResponse.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
}
class ApiResponse{
final String result;
final String error;
final String error_number;
final String response_code;
PopnableResponse(
{this.result, this.error, this.error_number, this.response_code});
factory ApiResponse.fromJson(Map<String, dynamic> json) {
return ApiResponse(
result: json['result'] as String,
error: json['error'] as String,
error_number: json['error_number'] as String,
response_code: json['response_code'] as String,
);
}
}
JSON Example:
{
"error":"",
"error_number":"",
"response_code":200,
"result":[
{
"id":1,
"name":"Great Deal",
"day_aired":"2015-07-05 11:06:09",
"trend":"Noone"
},
{
"id":2,
....
}
]
}
Try to cast it
json.decode(response.body) as Map<String, dynamic>
Related
I have a app where I use youtube api and make a get request using retrofit, now I want to get a list of videos for a specific keyword, but for that I have to use a different get req everytime so how can I change the get request programatically
Code for calling API
private fun getVideosList() {
val videos = RetrofitInstance.youtubeapi.getYoutubeVideos()
videos.enqueue(object : Callback<YoutubeAPIData?> {
override fun onResponse(call: Call<YoutubeAPIData?>, response: Response<YoutubeAPIData?>) {
val videosList = response.body()?.items
if (videosList != null) {
for(video in videosList) {
Log.d("title", video.snippet.title)
}
}
}
override fun onFailure(call: Call<YoutubeAPIData?>, t: Throwable) {
Toast.makeText(applicationContext, "Unable to fetch results!", Toast.LENGTH_SHORT).show()
Log.d("APIError",t.toString())
}
})
}
Retrofit Instance
object RetrofitInstance {
const val BASE_URL = "https://www.googleapis.com/youtube/v3/"
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val youtubeapi: YoutubeListApi by lazy {
retrofit.create(YoutubeListApi::class.java)
}}
Code for API interface
interface YoutubeListApi {
#GET("search?part=snippet&q=eminem&key=*my_key*")
fun getYoutubeVideos(): Call<YoutubeAPIData>}
Now what I want is to change the #GET("search?part=snippet&q=eminem&key=my_key") in the api interface so that if the keyword is eminem it should be search?part=snippet&q=eminem&key=my_key
and if keyword is dog it should be search?part=snippet&q=dogkey=my_key
Why not use #Query from retrofit?
You could redefine your interface to:
interface YoutubeListApi {
#GET("search")
fun getYoutubeVideos(
#Query("part") part: String,
#Query("q") query: String,
#Query("key") key: String,
): Call<YoutubeAPIData>
}
and then you can call it like getYoutubeVideos("snippets", "eminem", "your key") or getYoutubeVideos("snippets", "dog", "your key").
I think you can even hardcode some values in the URL if you want, but honestly I think you can just use kotlin default values:
interface YoutubeListApi {
#GET("search")
fun getYoutubeVideos(
#Query("q") query: String,
#Query("part") part: String = "snippet",
#Query("key") key: String = "your key",
): Call<YoutubeAPIData>
}
and just pass the query getYoutubeVideos("eminem"). I haven't double checked this, but I think it could work.
I'm trying to write a simple Discord bot in TypeScript, using discord.js and clime.
I'm running into an issue where I'm trying to access an object property of a context object that I pass around, but it's always null. When I check the properties using either vscode's debugger or console.log, the object seems to have all of the properties that I would expect, except they're all nested one layer too deep.
export class DiscordCommandContext extends Context {
public message:Message;
public client:Client;
constructor (options:ContextOptions, message:Message, client:Client) {
super(options);
this.message = message;
this.client = client;
}
}
When I try accessing it the message property, it's always falsy (if block is skipped over).
if (context.message.guild) {
var settings = await repo.getRealmSettings(+context.message.guild.id);
if (key) {
embed.fields.push({name:key,value:settings[key]});
} else {
Object.keys(settings).forEach(property => {
embed.fields.push({name:property,value:settings[property]});
});
}
}
But in the console, I see this:
DiscordCommandContext appears to have nested "message" objects, one of the wrong type
I cannot access context.message.message, I get "Property 'message' does not exist on type 'Message'", which is as I would expect.
EDIT 1
My instantiation code looked like this:
var options:ContextOptions = {
commands: argArr,
cwd: ""
};
var context = new DiscordCommandContext(options, this.message, this.client );
Where argArr is a split string passed into the method and both this.message and this.client are populated in the constructor of the calling class (none are null)
I managed to get DiscordCommandContext to function properly by changing it to this:
export class DiscordCommandContext extends Context {
public message:Message;
public client:Client;
public realmSettings: RealmSettings;
constructor (options:ContextOptions, contextExtension:DiscordCommandContextValues) {
super(options);
this.message = contextExtension.message;
this.client = contextExtension.client;
this.realmSettings = contextExtension.realmSettings
}
}
export interface DiscordCommandContextValues {
message:Message;
client:Client;
realmSettings: RealmSettings;
}
And calling it like this:
var context = new DiscordCommandContext(options, {message:this.message, client:this.client, realmSettings: settings} );
I'm not sure if that's the right way or not... but it works.
I am using pipes for request validation. If the request fails, I want to redirect to a page but don't want to throw error. The question is, how can I access the response object in validation?
This is my validation pipe.
#Injectable()
export class ValidationPipe implements PipeTransform<any> {
async transform(value: any, { metatype }: ArgumentMetadata) {
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
// in here i need to response with res.redirect('') function
throw new BadRequestException('Validation failed');
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
Instead of throwing exception i need to access res.redirect() function
The response object is not available from within the context of a pipe. What you could do is A) use an interceptor instead or B) throw an exception and use a filter to catch this specific exception and redirect to the correct location.
Pipes are only used for validation or object transformation and as such immediately return successes (with the possibly transformed object) or throw errors about why the transformation/validation failed.
I'm following this example to create an element and call its method. I'm doing:
class streetViewCard extends Polymer.Element {
static get is() {
return 'street-view-card';
}
...
updateLocation(coordinates) {
//empty for now for testing
}
...
customElements.define(streetViewCard.is, streetViewCard);
And then using this element and giving it and id of streetViewCard, then getting this element by:
this.streetViewCard = document.querySelector("streetViewCard");
console.log(streetViewCard); //this logs the element to the console OK, it's NOT null
streetViewCard.updateLocation(feature.geometry.coordinates);
And this gives an error Uncaught TypeError: streetViewCard.updateLocation is not a function. Any idea why?
UPDATE
As requested in the comments, the update from console.log(streetViewCard) is:
class streetViewCard extends Polymer.Element {
static get is() {
return 'street-view-card';
}
static get properties() {
return {
title: {
type: String,
value: 'Street V…
I am quite new to groovy and getting following error when running the below method. I am trying to pass xml file name and Map
RD.groovy
Given(~'^input currency "([^"]*)"$') { String baseCurr ->
fromCurr = baseCurr
}
When(~'^insert end Currency "([^"]*)"$') { String tragetCurr ->
toCurr = tragetCurr
}
Then(~'^get the expected end currency value "([^"]*)"$') { String result ->
assert result == currCon(fromCurr, toCurr)
}
private currCon(fromCurr, toCurr)
{
def binding = ["fromCurr": fromCurr, "toCurr": toCurr]
response = Consumer.currConvert("request/CurrencyConvert.xml",binding) --> This is line 119
assert 200 == response.status
return response.data.ConversionRateResult.toString()
}
ClassA.groovy
package abc.api.member
import abc.util.Log
import abc.util.TemplateUtil
import groovyx.net.http.ContentType
import abc.api.RestClient
class ClassA extends ClassB{
ClassA(RestClient restClient) {
super(restClient)
}
def currConvert(String xmlFilename, Map binding) {
return currencyConvertRequest(TemplateUtil.xmlFromTemplate(xmlFilename, binding))
}
def currencyConvertRequest(xmlString) {
def params = [path : 'CurrencyConvertor.asmx',
headers: globeHeaders(),
body: xmlString]
return restClient.post(params)
}
Consumer.Groovy
package abc.api.member
import geb.Browser
import org.apache.http.client.utils.URIBuilder
import abc.api.RestClient
import abc.browser.member.Admin
class Consumer {
Browser browser
String token
String userId
#Delegate
private ClassA classA
Consumer(url) {
browser = new Browser()
browser.baseUrl = baseUrl(url)
restClient = new RestClient(url)
classA = new ClassA(restClient)
}
private baseUrl(url) {
URI uri = URI.create(url)
URIBuilder builder = new URIBuilder()
URI result =builder.setHost(uri.host). //
setPath(uri.path). //
setPort(uri.port). //
setScheme(uri.scheme).
setUserInfo("Cons", "pbiCons").build()
return result.toURL().toString()
}
Error:
groovy.lang.MissingMethodException: No signature of method: abc.api.consumer.Consumer.currConvert() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl, java.util.LinkedHashMap) values: [request/globe/CurrencyConvert.xml, [fromCurr:AUD, ...]]
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at RD.currCon(RD.groovy:119)
After searching the issue it turned out its a common issue. Couldn't figure out though. Because all solutions are subjective.
Just curious where I am doing wrong
Thanks
currConvert is an instance method, but it's being called as if it was a static method.
I had a similar problem like this :
class Example {
static void main (String [] args) {
printMessage(obj)
}
def printMessage(obj) {
}
}
I was getting the same exception at printMessage(obj).
It got fixed after changing it to like this :
class Example {
static void main (String [] args) {
new Example().printMessage(obj)
}
def printMessage(obj) {
}
}