How to send dynamic data in Retrofit API calls in flutter? - flutter

I want to add dynamic data in my api calls so using retrofit I am trying this:
#RestApi(baseUrl: Constants.baseUrl)
abstract class AppServiceClient {
factory AppServiceClient(Dio dio, {String baseUrl}) = _AppServiceClient;
#GET("/get-all-country")
Future<AllCountryResponse> getCountries();
#GET("/get-state/{input}")
Future<AllCountryResponse> getStates(#Path("input") instance<StateId>().fetchCountryId);
}
This is my statId class:
class StateId {
StateId();
String countryId = "";
String get fetchCountryId => countryId;
setCountryId(String value) {
countryId = value;
}
}
I want to pass a dynamic data in the get-state api. How can I do this?

I found the solution to this, it was adding field to the parameter
#GET("/get-state/{id}")
Future<AllCountryResponse> getStates(#Path("id") String id);

Related

How to serialize private fields in json-serializable?

Minimal reproducible code:
#JsonSerializable()
class A {
final int _x;
A(int x) : _x = x;
factory A.fromJson(Map<String, dynamic> json) => _$AFromJson(json);
}
Note:
I don't want to make my private field _x public or define a public x getter.
This PR addresses what you want:
https://github.com/google/json_serializable.dart/pull/1256/files#diff-0acaf4c472e452d1e5d215a15fcd2266ccd02ab6abdfac0080c2fca845eb9096
You will be able to explicitly set includeFromJson and includeToJson on the private fields you want to include.
Example:
class X {
#JsonKey(includeFromJson: true, includeToJson: true)
int _includeMeToTheJsonParsing;
}
It was merged November 30th. Latest package version is v6.5.4, released at October 25th. So you will need to wait a little bit if you want the official release. Otherwise, you can point directly to the latest commit if you need it ASAP.
If you don't want to make your private field public or define a public getter, you can still use a serialization library like json_serializable or built_value to serialize and deserialize the class, but you will need to define a custom toJson method that manually serializes the private field. Here's an example of using json_serializable with a custom toJson method:
import 'package:json_annotation/json_annotation.dart';
part 'my_class.g.dart';
#JsonSerializable()
class MyClass {
final int _x;
MyClass(this._x);
Map<String, dynamic> toJson() => {
'x': _x,
};
factory MyClass.fromJson(Map<String, dynamic> json) => MyClass(json['x'] as int);
}
You can then use the fromJson and toJson methods to serialize and deserialize your class:
import 'dart:convert';
void main() {
// Serialize to JSON
MyClass obj = MyClass(42);
String json = jsonEncode(obj);
// Deserialize from JSON
MyClass obj2 = MyClass.fromJson(jsonDecode(json));
}

A value of type 'xxx?' can't be returned from a function with return type 'xxx' because 'xxx?' is nullable and 'xxx' isn't

I am learning factory method in dart. However I encounter a problem, which says
A value of type 'Person?' can't be returned from a function with return type 'Person' because 'Person?' is nullable and 'Person' isn't.
3-1.dart:13
Here is my code:
void main(List<String> args) {
Person a = new Person("zarkli");
a.say("hello");
}
class Person{
final name;
static final Map<String, Person> _cache = new Map<String,Person>();
factory Person(String name){
if (_cache.containsKey(name)){
return _cache[name]; // error
} else {
final person = new Person.newPerson(name);
_cache[name] = person;
return person;
}
}
Person.newPerson(this.name);
void say(String content){
print("$name: $content");
}
}
Some maps allow null as a value. For those maps, a lookup using this operator cannot distinguish between a key not being in the map, and the key being there with a null value.
This is from the get operator documentation for map. When you use containsKey it could be the case that the key exists but its value is null.
You can use a local variable to store _cache[name] and check if it's null or not. Dart then can promote that local variable and not give you any errors. So your factory will look like this:
factory Person(String name) {
final cached = _cache[name];
if (cached != null) {
return cached;
} else {
final person = Person.newPerson(name);
_cache[name] = person;
return person;
}
}

Flutter Dart | How to return different object from class Constructor

In Dart, is it possible for a constructor to cancel object creation and return a different object instead?
Use case:
Users contains a static map that maps ids to User objects.
When a User is initialized, I want the User constructor to check if User with id is already created, if so: return existing User object, else create a new User object
Example (of-course not working):
class Users {
static const Map<String, User> users = {};
}
class User {
final String id;
final String firstName;
User({required id, required firstName}) {
// If user with id already exists, return that object
if (Users.users.containsKey(id) {
return Users.users[id];
}
// Else, initialize object and save it in Users.users
this.id = id;
this.firstName = firstName;
Users.users[id] = this;
}
}
Question: IS there any way to get the above pseudo code to work?
As mentioned by jamesdlin you should use a factory constructor. Here's what is mentioned in the documentation:
Use the factory keyword when implementing a constructor that doesn’t
always create a new instance of its class.
And in your case this is exactly what you want. Now here's a code sample that does what you want:
Code sample
class Users {
// Also your Map cannot be const if you want to edit it.
static Map<String, User> users = {};
}
class User {
final String id;
final String firstName;
/// Base private constructor required to create the User object.
User._({required this.id, required this.firstName});
/// Factory used to create a new User if the id is available otherwise return the User
/// associated with the id.
factory User({required String id, required String firstName}) {
// If user with id already exists, return that object
if (Users.users.containsKey(id)) {
// Force casting as non nullable as we already checked that the key exists
return Users.users[id]!;
}
// Else, initialize object and save it in Users.users
final newUser = User._(id: id, firstName: firstName);
Users.users[id] = newUser;
return newUser;
}
}
Try the full code on DartPad
You can create a function in class to handle things you want. Here's what you can implement.
class Player {
final String name;
final String color;
Player(this.name, this.color);
Player.fromPlayer(Player another) :
color = another.color,
name = another.name;
}
If this is for caching purposes or you are not creating multiple instances of the Users class, I would suggest using a pattern where static is responsible for a list of class instances. Sometimes this helps to significantly reduce the amount of code:
class User {
static final Map<String, User> users = {};
final String id, firstName;
User._({required this.id, required this.firstName});
factory User({required String id, required String firstName}) => users[id] ??= User._(id: id, firstName: firstName);
}

Flutter: Shuffle BuiltList in Package built_value

I've developed an app that receives questions from an API.
The client uses built_value for checking.
Is there a way to shuffle the objects in
BuiltList<Aufgabe>fragen ?
This is what the client should do.
abstract class Aufgabenbundle
implements Built<Aufgabenbundle, AufgabenbundleBuilder> {
String get nameDerUebung;
String get dateiNameDerPdf;
BuiltList<Aufgabe> get fragen; //These objects should be mixed
Aufgabenbundle._();
factory Aufgabenbundle([updates(AufgabenbundleBuilder b)]) = _$Aufgabenbundle;
String toJson() {
return json
.encode(serializers.serializeWith(Aufgabenbundle.serializer, this));
}
static Aufgabenbundle fromJson(String jsonString) {
return serializers.deserializeWith(
Aufgabenbundle.serializer, json.decode(jsonString));
}
static Serializer<Aufgabenbundle> get serializer => _$aufgabenbundleSerializer;
}
abstract class Aufgabe
implements Built<Aufgabe, AufgabeBuilder> {
String get title;
String get frage;
int get schwierigkeit;
int get antwortZeit;
BuiltList<String> get vorgegebeneAntworten;
int get richtigeAntwort;
#nullable
int get angehakteWert;
Aufgabe._();
factory Aufgabe([updates(AufgabeBuilder b)]) = _$Aufgabe;
static Serializer<Aufgabe> get serializer => _$aufgabeSerializer;
}
The BuiltList is immutable, so you can't shuffle it directly. As with other mutating operations, you need to rebuild it instead.
When you do that, you get a ListBuilder which implements the List interface, including the shuffle method.
So:
var fragen = aufgabenbundle.fragen;
var gemischteFragen = fragen.rebuild((b) => b.shuffle());

How can I return only several Json fields of an inner object with Jackson

I'm using Jackson + spring RestControlles
Lets say I have 3 classes
class Card {
String id;
String pan;
String holder;
String expiry;
}
class CardProfile {
String id;
Card card;
...
}
class Recipient {
String name;
Card card;
...
}
So when I serialize a CardProfile object I want all fields of object card to be percent in result json.
But in case Recipient object , Json has to have only part of object card(For example : pan, holder) .
Is there a way to present Card object in json with different set of fields?
Use of annotations like #JsonIgnore will remove fields from both cases.
Thanks.
Thinking again - is this approach scalable? What if you need something similar again?
Why not rely on inheritance and create a base class and multiple subclasses with attributes you are interested in?
class Card{
// bare min attribute
.....
}
class SubCard1 extends Card{
//add more attribute
.....
}
class SubCard2 extends Card{
//add more attribute
.....
}
Use SubCard1 or SubCard2 based on what you need? Same can be used for other classes. If this is more dynamic - look at design patterns.
when you serialize the object you can keep only the parameter that are interest for you.
I post a simple java code to resolve this stuff you can convert the code in the lenguage that you need.
the following code is prt of the Recipient class which contains two field: String name and Card card
To write the json object:
#Override
public final void toJSON(final OutputStream out) throws IOException {
final JsonGenerator jg = JSON_FACTORY.createGenerator(out);
jg.writeStartObject();
jg.writeFieldName("Recipient");
jg.writeStartObject();
jg.writeNumberField("id",card.getID());
jg.writeStringField("name", name);
jg.writeStringField("pan", card.getPan());
jg.writeStringField("holder", card.getHolder());
jg.writeEndObject();
jg.writeEndObject();
jg.flush();
}
to get the the object from the json:
public static Recipient fromJSON(final InputStream in) throws IOException {
int jId = -1;
String jName = null;
String jHolder = null;
String jPan = null;
//Obtain a new JsonParser to parse Recipient from JSON
final JsonParser jp = JSON_FACTORY.createParser(in);
while (jp.getCurrentToken() != JsonToken.FIELD_NAME || "Recipient".equals(jp.getCurrentName()) == false) {
// there are no more events
if (jp.nextToken() == null) {
throw new IOException("Unable to parse JSON: no employee object found.");
}
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
if (jp.getCurrentToken() == JsonToken.FIELD_NAME) {
switch (jp.getCurrentName()) {
case "id":
jp.nextToken();
jId = jp.getIntValue();
break;
case "name":
jp.nextToken();
jName = jp.getText();
break;
case "pan":
jp.nextToken();
jPan = jp.getText();
break;
case "holder":
jp.nextToken();
jHolder = jp.getText();
break; }
} }
//create new card object, the values not present in the json will set to null
Card card = new Card(jId,null,jPan,jHolder,null);
return new Recipient(jName, card);
}
}
I tried to adapt the code for you but it is just to give you an idea,I hope this will be usefull for you.