So I have this route to switch on and off a light:
#a.route("/dome/light")
##a.param('state', 'The lamp state')
class DomeLightApi(Resource):
'''Switches on or off the dome illumination'''
def get(self):
#return {"state": devices.light.state}
return devices.light.state
#a.expect(bool, validate=True)
#api.response(200, 'Success')
#api.response(400, 'Validation Error', bool)
##a.marshal_with(switch, code=201)
def put(self):
state = request.get_json(force=True)
print(state)
devices.light.state = state
return devices.light.state
How can I apply a model where the expected value is just a boolean, and not a {"state": fields.Boolean()} JSON?
And how can I validate that the PUT payload is bool?
Related
I have wrote the following code on server.
server code:
import 'dart:convert';
import 'package:mongo_dart/mongo_dart.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_web_socket/shelf_web_socket.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
class PostsSocketApi {
PostsSocketApi(this.store);
final List<WebSocketChannel> _sockets = [];
final DbCollection store;
Handler get router {
return webSocketHandler((WebSocketChannel socket) {
socket.stream.listen((message) async {
final data = json.decode(message);
print(data);
if (data['action'] == 'LOGIN') {
final user = await store.findOne(
where.eq('name', data['name']).eq('password', data['password']));
if (user != null) {
for (final ws in _sockets) {
ws.sink.add(json.encode('name'));
// probably there must be .toString() ^^^
}
}
if (user == null) {
for (final ws in _sockets) {
ws.sink.addError('NOSUCHUSER');
}
}
}
});
_sockets.add(socket);
});
}
}
And now I want to get the 'name' field into my variable tmp_name to compare it with name on login field, like that:
login code:
void loginUser() async {
final name = emailController.text;
final password = passwordController.text;
widget.api.send(
json.encode({'action': 'LOGIN', 'name': name, 'password': password}));
String tmp_name = widget.api.getName;
// method from API ^^^^^^^
if (tmp_name == name) {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
prefs.setString('name', name);
});
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) => Home()));
} else {
print('error: no such user');
}
}
API code in App:
class PostsSocketApi {
PostsSocketApi()
: _api = WebSocketChannel.connect(
Uri.parse('ws://localhost:8082/posts-ws/'));
final WebSocketChannel _api;
Stream<List<Post>> get stream => _api.stream.map<List<Post>>((data) {
final decoded = json.decode(data);
return (decoded as List)
.map<Post>(
(json) => Post.fromJson(json),
)
.toList();
});
ValueChanged<String> get send => _api.sink.add;
get getName => _api.stream.map((data) {
final decoded = json.decode(data['name']);
return (decoded as List).map<Post>(
(json) => Post.fromJson(json),
);
});
}
However, I got the following error in APP code and don't know how to solve it.
Error: Expected a value of type 'String', but got one of type '_MapStream<dynamic, Iterable<Post>>'
Server code works fine (compare data and print if it's wrong user)
Server response on register:
{action: ADDUSER, name: 6, password: 6, id: 6}
Server response on login as existing user:
{action: LOGIN, name: 6, password: 6}
Server response on login as NOT-existing user:
{action: LOGIN, name: fqfqfq, password: qfqfqfq}
NOSUCHUSER
ERROR - 2022-03-21 11:55:27.183011
Asynchronous error
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
PostsSocketApi.router.<fn>.<fn>
package:io/api/socket_api.dart:79
For Ruchit:
userID type is String. If I write like that, the same error thrown.
get getName => _api.stream.map((data) {
final decoded = json.decode(data['name']);
return (decoded as List)
.map<String>((json) => Post.fromJson(json).userID);
});
But, if I write like that, I get the type error:
error: The return type 'String' isn't a 'Post', as required by the closure's context.
Code:
get getName => _api.stream.map((data) {
final decoded = json.decode(data['name']);
return (decoded as List)
.map<Post>((json) => Post.fromJson(json).userID );
});
Any ideas? (Even about refactoring other code)
I'm tried to find some explanations in documentation, but... Write if u need some more code or explanations. Or if you can give me advice about how to make login by another way - tell me.
Please help me if you can <3
Here you are returning whole post object and you are getting as String which mismatches thus it is showing error.
get getName => _api.stream.map((data) {
final decoded = json.decode(data['name']);
return (decoded as List).map<Post>(
(json) => Post.fromJson(json).field, //here field is the field you want from Post object and you are getting string so this field should have type string.
//eg. Post.fromJson(json).name
);
});
I'm getting The below ERROR,I believe it's because of null safety, this means that no data has been received or getSignedInUser() method is incorrect or class BuiltValueConverter is the cause.
(I tested the token with Postman and retrieved the data)
E/flutter (21792): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)]
Unhandled Exception: Unhandled error Null check operator used on a
null value occurred in Instance of 'AuthBloc'. E/flutter (21792): #0
BuiltValueConverter._deserialize
package:todo_list_app/…/auth/built_value_converter.dart:51 E/flutter
(21792): #1 BuiltValueConverter._convertToCustomObject
package:todo_list_app/…/auth/built_value_converter.dart:36 E/flutter
(21792): #2 BuiltValueConverter.convertResponse
package:todo_list_app/…/auth/built_value_converter.dart:25
I'm using chopper with built_value Pubs. i'm trying to convert the coming json to object.
Example:
{
"userName": "Jack",
"email": "jack2066#gmail.com",
"userRole": "USER",
"created_at": "2021-07-03T16:49:56.774Z",
"updated_at": "2021-07-03T16:49:56.774Z" }
the below code where the error start also explained in this Tutorial Converters & Built Value Integration
import 'package:built_collection/built_collection.dart';
import 'package:chopper/chopper.dart';
import 'package:todo_list_app/infrastructure/remote/auth/models/serializers.dart';
class BuiltValueConverter extends JsonConverter {
#override
Request convertRequest(Request request) {
return super.convertRequest(
request.copyWith(
body: serializers.serializeWith(
serializers.serializerForType(request.body.runtimeType)!,
request.body,
),
),
);
}
#override
Response<BodyType> convertResponse<BodyType, SingleItemType>(
Response response,
) {
final Response dynamicResponse = super.convertResponse(response);
final BodyType customBody =
_convertToCustomObject<SingleItemType>(dynamicResponse.body);//
return dynamicResponse.copyWith<BodyType>(body: customBody);
}
dynamic _convertToCustomObject<SingleItemType>(dynamic element) {
if (element is SingleItemType) return element;
if (element is List)
return _deserializeListOf<SingleItemType>(element);
else
return _deserialize<SingleItemType>(element);
}
BuiltList<SingleItemType> _deserializeListOf<SingleItemType>(
List dynamicList,
) {
// Make a BuiltList holding individual custom objects
return BuiltList<SingleItemType>(
dynamicList.map((element) => _deserialize<SingleItemType>(element)),
);
}
SingleItemType _deserialize<SingleItemType>(Map<String, dynamic> value,) {
// We have a type parameter for the BuiltValue type, which should be returned after deserialization.
return serializers.deserializeWith(
serializers.serializerForType(SingleItemType)!, // Error Start
value,
);
}
}
Here is my Chopper service code, getSignedInUser throw the error.
I don't know if the implementation of the getSignedInUser method is correct or not.
import 'package:chopper/chopper.dart';
import 'package:injectable/injectable.dart';
import 'package:todo_list_app/infrastructure/remote/auth/built_value_converter.dart';
import 'package:todo_list_app/infrastructure/remote/auth/models/auth_built_model.dart';
import 'package:todo_list_app/infrastructure/remote/core/constants.dart';
part 'auth_service.chopper.dart';
#singleton
#ChopperApi()
abstract class AuthService extends ChopperService {
#factoryMethod
static AuthService create() {
final client = ChopperClient(
baseUrl: AUTH_BASE_URL_External,
services: [
_$AuthService(),
],
converter: BuiltValueConverter(),
errorConverter: JsonConverter(),
interceptors: [
HttpLoggingInterceptor()
],
);
return _$AuthService(client);
}
#Post(path: '/signup')
Future<Response> signUp(#Body() RegisterRequestModel body);
#Post(path: '/signin')
Future<Response<LoginResponseModel>> singIn(#Body() LoginRequestModel body);
//headers: {AUTH_HEADER:BEARER+'authValue'}
#Get(path: '/auth', )//authValue='Bearer Token'
Future<Response<UserResponseModel>> getSignedInUser(#Header("Authorization") String authValue);//error Unhandled error Null check operator used on a null value
}
Any idea how to solve this Error?
also Is there a good documentation for Chopper or alternative pub with a good documentation?
Thanks
I think you are missing values in your "serielizers.dart" file it should be as followed :
#SerializersFor(const[RegisterRequestModel,LoginRequestModel,UserResponseModel])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
Yeah, as you said it's because of null safety. Your _deserialize returns a non-null value whereas the serializers.deserializeWith can return a null value. Either you can change the return type to be nullable, or handle the null case for serializers.deserializeWith. If you want you can use the below BuiltValueConverter. It is from the example which they have given which is generic, with minor changes.
import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:chopper/chopper.dart';
import 'package:graphical_representation/app/serializers.dart';
class BuiltValueConverter extends JsonConverter {
T? _deserialize<T>(dynamic value) => serializers.deserializeWith<T>(
(serializers.serializerForType(T) as Serializer<T>),
value,
);
BuiltList<T> _deserializeListOf<T>(Iterable value) => BuiltList(
value.map((value) => _deserialize<T>(value)).toList(growable: false),
);
dynamic _decode<T>(entity) {
/// handle case when we want to access to Map<String, dynamic> directly
/// getResource or getMapResource
/// Avoid dynamic or unconverted value, this could lead to several issues
if (entity is T) return entity;
try {
if (entity is List) return _deserializeListOf<T>(entity);
return _deserialize<T>(entity);
} catch (e) {
print(e);
return null;
}
}
#override
Response<ResultType> convertResponse<ResultType, Item>(Response response) {
// use [JsonConverter] to decode json
final jsonRes = super.convertResponse(response);
final body = _decode<Item>(jsonRes.body);
return jsonRes.copyWith<ResultType>(body: body);
}
#override
Request convertRequest(Request request) => super.convertRequest(
request.copyWith(
body: serializers.serialize(request.body),
),
);
}
I need some help with the following situation. I have a JSON API with a registration request. The request takes 4 parameters: Standard phone, password, email, and a person parameter where a customer chooses a type. Based on the chosen type, they have to specify one more parameter: Name or age.
When I get an HTTP request, I need to decode it into my request object. Doing it with the code below results in a compilation error of type:
type mismatch;
found : Unit
required: io.circe.Decoder[RegistrationReq]
Any ideas why that can be the case and how to fix it? Thanks in advance!
import cats.effect.Sync
import cats.syntax.either._
import circe.jsonOf
import io.circe.{Decoder, DecodingFailure, HCursor}
import io.circe.generic.semiauto._
import io.circe.refined._
import io.circe.Decoder.Result
import org.http4s.EntityDecoder
trait RegJsonCodec {
import JsonCodec._ //all common encoders and decoders come from there
implicit val RegistrationReqDecoder: Decoder[RegistrationReq] = {
def apply(c: HCursor): Result[RegistrationReq] =
for {
phone <- getPhone(c)
password <- c.downField("password").as[Password]
email <- c.downField("email").as[Email] //Password and Email are refined Strings
person <- getPerson(c)
} yield RegistrationReq(phone, password, email, person)
}
private def getPhone(c: HCursor): Either[DecodingFailure, Long] =
c.downField("phone").as[Long].orElse {
c.downField("phone").as[String].flatMap {
str =>
Either.catchNonFatal(str.toLong)
.leftMap(e => DecodingFailure(e.getMessage, c.history))
}
}.flatMap(phone => Either.right(phone))
private def getPerson(c: HCursor): Either[DecodingFailure, Person] = {
c.downField("person").downField("type").as[String].flatMap { type =>
c.downField("person").downField("name").as[String]
.orElse(c.downField("person").downField("age").as[String]).flatMap { extra =>
Either.catchNonFatal(Person.fromPair(type, extra))
.leftMap(e => DecodingFailure(e.getMessage, c.history))
.flatMap(person => Either.right(person))
}
}
}
implicit def requestEntityDecoder[F[_] : Sync]: EntityDecoder[F, RegistrationReq] = jsonOf[F, RegistrationReq]
}
object RegJsonCodec extends RegJsonCodec
I would like to know that how can I return json response data from Play(2.2.x) Scala controller class to display on my view page ? I have json objects in Postgresql database(table name: "test" and having: id and name). Please provide me any solutions for it.
I have tried the following cases(a and b), but I am not sure why I am not getting the response(like: names) on my controller, so I can show them on my view page ? since I am very new to Play/Scala and Postgresql.
case a. If I give like:
model:
def getTestValuesFromTable() = {
DB.withConnection { implicit connection =>
val selectJson =SQL("select name from test").on().apply().collect {
case Row(id:Long, Some(name:String)) =>
new TestContent(name)
}
//.head
//JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)
}
}
controller:
def getTest = Action {
val response = TestContent.getTestValuesFromTable()
Ok("Done")
//Ok(response)
}
Output is: Done(application is executing fine without any exceptions, of course json data is not coming since I am returning: Done only, so getting output: "Done")
case b. If I do like this: getting error: not enough arguments for method apply: (n: Int)models.Testname in trait LinearSeqOptimized. Unspecified value parameter n. I really not sure how can I get my response for it ?
controller:
def getTest = Action {
val response = TestContent.getTestValuesFromTable()
// Ok("Done")
Ok(response)
}
model:
def getTestValuesFromTable(): JsValue = {
DB.withConnection { implicit connection =>
val selectJson = SQL("select * from test")
JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)
// val selectJson =SQL("select name from test").on().apply().collect {
// case Row(id:Long, Some(name:String)) =>
// new TestContent(name)
// }
//.head
JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)//not enough arguments for method apply: (n: Int)models.Testname in trait LinearSeqOptimized. Unspecified value parameter n.
}
}
Please let me know how to get my response ?
getJsonValuesFromTable method return nothing (Unit). To fix it change definition of this method to
def getJsonValuesFromTable(testContent: TestContent) = {
or explicitly setting type:
def getJsonValuesFromTable(testContent: TestContent): Unit = {
Also as a next step to let client know that you are returning json, you should set content type:
Ok(Json.obj(response)).as("application/json")
I am working on implementation of library system using play framework and angularjs.
suppose to search for a book in the library the user enters the keyword value in the input field, this value is received by the controller from the GET request. I need to search the MySQL database for the list of the books, convert them to json request and display them back in the search page which is implemented using angularjs.
I don't understand how to use json and send the result back to the web page.
GET /books/all/search/:by/:value controllers.Books.listBooks(by: String, value: String)
case class Book (
bookId: String,
title: String,
author: String,
category:String,
price: Int,
location: String,
status: String
)
object Book{
val bookParse = {
get[String]("book.bookId") ~
get[String]("book.title") ~
get[String]("book.author") ~
get[String]("book.category") ~
get[Int]("book.price") ~
get[String]("book.location") ~
get[String]("book.status")map {
case bookId~title~author~category~price~location~status => Book(bookId,title, author, category, price, location, status)
}
}
def searchByBookId(bookId: String) : List[Book]= {
DB.withConnection {implicit connection =>
SQL("select * from book where bookId = {bookId}").as(Book.bookParse *)
}
}
object Books extends Controller {
def listBooks(by: String, value:String): List[Book] =
{
if (by == "byBookId" ) Book.searchByBookId(value)
else if(by == "byTitle")Book.searchByTitle(value)
else Book.searchByAuthor(value)
}
}
Now i need to send the List[Book] result to the web page
import play.api.libs.json._
implicit val bookFormat = Json.format[Book]
def listBooks(by: String, value: String) = Action {
val books = if (by == "byBookId" ) Book.searchByBookId(value)
else if(by == "byTitle")Book.searchByTitle(value)
else Book.searchByAuthor(value)
Ok(Json.toJson(books))
}
The implicit val bookFormat needs to be either on the Book companion object, or in scope when Json.toJson is called.
More documentation on JSON:
http://www.playframework.com/documentation/2.2.x/ScalaJson