I created a login page and I need to add these things to my password. How do I do it with validation alert message?
Minimum 1 Upper case
Minimum 1 lowercase
Minimum 1 Numeric Number
Minimum 1 Special Character
Common Allow Character ( ! # # $ & * ~ )
Your regular expression should look like:
r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$
Here is an explanation:
r'^
(?=.*[A-Z]) // should contain at least one upper case
(?=.*[a-z]) // should contain at least one lower case
(?=.*?[0-9]) // should contain at least one digit
(?=.*?[!##\$&*~]) // should contain at least one Special character
.{8,} // Must be at least 8 characters in length
$
Match above expression with your password string. Using this method-
String? validatePassword(String value) {
RegExp regex =
RegExp(r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$');
if (value.isEmpty) {
return 'Please enter password';
} else {
if (!regex.hasMatch(value)) {
return 'Enter valid password';
} else {
return null;
}
}
}
You need to use Regular Expression to validate the structure.
bool validateStructure(String value){
String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$';
RegExp regExp = new RegExp(pattern);
return regExp.hasMatch(value);
}
output:
Vignesh123! : true
vignesh123 : false
VIGNESH123! : false
vignesh# : false
12345678? : false
This function will validate the passed value is having the structure or not.
var _usernameController = TextEditingController();
String _usernameError;
...
#override
Widget build(BuildContext context) {
return
...
TextFormField(
controller: _usernameController,
decoration: InputDecoration(
hintText: "Username", errorText: _usernameError),
style: TextStyle(fontSize: 18.0),
),
Container(
width: double.infinity,
height: 50.0,
child: RaisedButton(
onPressed: validate,
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
color: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
),
),
...
}
...
validate(){
if(!validateStructure(_usernameController.text)){
setState(() {
_usernameError = emailError;
_passwordError = passwordError;
});
// show dialog/snackbar to get user attention.
return;
}
// Continue
}
You have to use TextFormField widget with validator property.
TextFormField(
validator: (value) {
// add your custom validation here.
if (value.isEmpty) {
return 'Please enter some text';
}
if (value.length < 3) {
return 'Must be more than 2 charater';
}
},
),
Take a look on official docs: https://flutter.dev/docs/cookbook/forms/validation
You can achieve this using below flutter plugin.
wc_form_validators
You can use it something like this:
TextFormField(
decoration: InputDecoration(
labelText: 'Password',
),
validator: Validators.compose([
Validators.required('Password is required'),
Validators.patternString(r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$', 'Invalid Password')
]),
),
Its documentation is really good. You can read it for more util functions like this.
By using extension in dart
extension PasswordValidator on String {
bool isValidPassword() {
return RegExp(
r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$')
.hasMatch(this);
}
}
You can apply this in your textfield like
TextFormField(
autovalidate: true,
validator: (input) => input. isValidPassword() ? null : "Check your password...",
)
here is the complete answer
Write a Dart program to check whether a string is a valid password. a. A password must have at least ten characters. b. A password
consists of only letters and digits. c. A password must contain at
least two digits.
import 'dart:io';
main() {
var password;
stdout.write("Enter You'r Password: ");
password=stdin.readLineSync();
if(password.length>=10 && !password.contains(RegExp(r'\W')) && RegExp(r'\d+\w*\d+').hasMatch(password))
{
print(" \n\t$password is Valid Password");
}
else
{
print("\n\t$password is Invalid Password");
}
Flutter Login Validation
///creating Username and Password Controller.
TextEditingController username=TextEditingController();
TextEditingController password=TextEditingController();
Form(
child: Builder(
builder: (context) {
return Column(
children: [
TextFormField(
controller: username,
validator: (CurrentValue){
var nonNullValue=CurrentValue??'';
if(nonNullValue.isEmpty){
return ("username is required");
}
if(!nonNullValue.contains("#")){
return ("username should contains #");
}
return null;
},
),
TextFormField(
controller: password,
validator: (PassCurrentValue){
RegExp regex=RegExp(r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$');
var passNonNullValue=PassCurrentValue??"";
if(passNonNullValue.isEmpty){
return ("Password is required");
}
else if(passNonNullValue.length<6){
return ("Password Must be more than 5 characters");
}
else if(!regex.hasMatch(passNonNullValue)){
return ("Password should contain upper,lower,digit and Special character ");
}
return null;
},
),
ElevatedButton(onPressed: (){
if(Form.of(context)?.validate()?? false){
Navigator.of(context).push(MaterialPageRoute(builder: (_)=>loginpage()));
}
}, child: Text("Login"))
],
);
}
),
)
in this picture you can see when you Enter inValid username and password it will not Navigate to another page.
when you Enter Valid Username and Password it will Navigate to another Page.
this is the best regx
bool passValid = RegExp("^(?=.{8,32}\$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!##\$%^&*(),.?:{}|<>]).*").hasMatch(value);
if (value.isEmpty ||!passValid)
{
return 'error';
}
Related
I have a reactive login form following the BLOC pattern. I'm trying to programmatically clear all the values in it. In my Bloc, my submit function passes empty strings to my stream sinks:
class Bloc with Validators {
final _email = BehaviorSubject<String>();
final _password = BehaviorSubject<String>();
Stream<String> get email => _email.stream.transform(validateEmail);
Stream<String> get password => _password.stream.transform(validatePassword);
Stream<bool> get submitValid => Observable.combineLatest2(email, password, (String e, String p) {
var valid = (e != null && e.isNotEmpty)
&& (p != null && p.isNotEmpty);
print('$e && $p = $valid');
return valid;
});
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
submit() {
final validEmail = _email.value;
final validPassword = _email.value;
print('final values: $validEmail && $validPassword');
changeEmail('');
changePassword('');
}
dispose() {
_email.close();
_password.close();
}
}
When I press the submit button that calls this submit() function, I get the error messages for both of the text fields, because the values of email and password have changed behind the scenes, but they are not visually updated in the TextFields. Here are my StreamBuilders for my TextFields and Submit button:
Widget emailField(Bloc bloc) {
return StreamBuilder(
stream: bloc.email,
builder: (context, snapshot) { // re-runs build function every time the stream emits a new value
return TextField(
onChanged: bloc.changeEmail,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
icon: Icon(Icons.email),
hintText: 'email address (you#example.com)',
labelText: 'Email',
errorText: snapshot.error
)
);
}
);
}
Widget passwordField(Bloc bloc) {
return StreamBuilder(
stream: bloc.password,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextField(
onChanged: bloc.changePassword,
autocorrect: false,
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.security),
hintText: 'must be greater than 6 characters',
labelText: 'Password',
errorText: snapshot.error
)
);
}
);
}
Widget submitButton(Bloc bloc) {
return StreamBuilder(
stream: bloc.submitValid,
builder: (context, snapshot) {
return RaisedButton(
child: Text('Logins'),
color: Colors.blue,
onPressed: !snapshot.hasData || snapshot.hasError || snapshot.data == false
? null
: bloc.submit
);
}
);
}'
And here is the code I'm using for my validators in my Bloc:
class Validators {
final validateEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (email, sink) {
RegExp exp = new RegExp(r"^[a-zA-Z0-9.]+#[a-zA-Z0-9]+\.[a-zA-Z]+");
var valid = exp.hasMatch(email);
if (valid) {
sink.add(email);
} else {
sink.add('');
sink.addError('Invalid email address!');
}
}
);
final validatePassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
var valid = password.length >= 6;
if (valid) {
sink.add(password);
} else {
sink.add('');
sink.addError('Password must be at least 6 characters long!');
}
}
);
}
In my validators, I emit an empty string whenever there is an error. This makes it so the submitValid getter works when the user invalidates something that used to be valid.
I know it's been a long time, but that's my way for solving it.
First, I've created a TextEditingController for my TextField. Then I've created two methods on my BLoC: updateTextOnChanged and updateTextElsewhere. On the fisrt one I just retrieved the value (because I need it to use later). On the second one I added a sink to update the controller on TextField.
Widget:
return StreamBuilder<String>(
stream: bloc.streamText,
builder: (context, snapshot) {
_controller.text = snapshot.data;
return Expanded(
child: TextField(
controller: _controller,
onChanged: (value) => {bloc.updateTextOnChanged(value)},
),
);
}
);
Bloc:
Stream<String> get streamText => _controllerTxt.stream;
String _myText;
void updateTextElsewhere(String value) {
_controllerTxt.sink.add(value);
}
void updateTextOnChanged(String value) {
_myText = value;
}
Then you just need to call updateTextElsewhere() whenever you need to update it outside onChanged.
In you're case just add an empty string like: updateTextElsewhere("");
In submit(), you seem like reseting username and password
changeEmail('');
changePassword('');
And as you commented , 're-runs build function every time the stream emits a new value'. It re-builds UI since the value updated to empty. Maybe does it cause the problem?
Instead of write separate validate method of each TextFormField is there any way to be managed by single method like below.
String _isValidatedField(String strInputText) {
String pEmailChk =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
if (_conFirstName.text.isEmpty) {
return 'Please enter first name';
} else if (_conLastName.text.isEmpty) {
return 'Please enter last name';
} else if (_conUserName.text.isEmpty) {
return 'Please enter username';
} else if (_conEmailName.text.isEmpty) {
return 'Please enter email address';
} else if (RegExp(pEmailChk).hasMatch(_conEmailName.text) == false) {
return 'Please enter valid email addres';
}
else if (_conEmailName.text.length != 10) {
return 'Please enter valid phone number';
}
return null;
}
Problem is When any validation will fail then error will be occurred for each TextFormField rather than error should be display on particular TextFormField that was fail.
TextformField has a validator parameter through which you can validate particular text form field
TextFormField(
key: new Key('email'),
decoration: new InputDecoration(labelText: 'Email'),
autocorrect: false,
validator: (val) => val.isEmpty ? 'Email can\'t be empty.' : null,
onSaved: (val) => _email = val,
)
I'm trying to implement same layout in flutter how can i achieve it, i have already tried using wrap widget but Textfield getting full width and changing textfield width dynamically based on content is not possible
I don't know if this is too late. But this library is exactly what you need. You have all steps on the website.
It's a library called Flutter Chips. There are the steps and I'll put the link from the library too.
https://pub.dev/packages/flutter_chips_input
First of all install the library:
dependencies:
flutter_chips_input: ^1.9.4
Here is the code part:
ChipsInput(
initialValue: [
AppProfile('John Doe', 'jdoe#flutter.io', 'https://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX4057996.jpg')
],
decoration: InputDecoration(
labelText: "Select People",
),
maxChips: 3,
findSuggestions: (String query) {
if (query.length != 0) {
var lowercaseQuery = query.toLowerCase();
return mockResults.where((profile) {
return profile.name.toLowerCase().contains(query.toLowerCase()) || profile.email.toLowerCase().contains(query.toLowerCase());
}).toList(growable: false)
..sort((a, b) => a.name
.toLowerCase()
.indexOf(lowercaseQuery)
.compareTo(b.name.toLowerCase().indexOf(lowercaseQuery)));
} else {
return const <AppProfile>[];
}
},
onChanged: (data) {
print(data);
},
chipBuilder: (context, state, profile) {
return InputChip(
key: ObjectKey(profile),
label: Text(profile.name),
avatar: CircleAvatar(
backgroundImage: NetworkImage(profile.imageUrl),
),
onDeleted: () => state.deleteChip(profile),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
);
},
suggestionBuilder: (context, state, profile) {
return ListTile(
key: ObjectKey(profile),
leading: CircleAvatar(
backgroundImage: NetworkImage(profile.imageUrl),
),
title: Text(profile.name),
subtitle: Text(profile.email),
onTap: () => state.selectSuggestion(profile),
);
},
)
I'm familiar with form validation using a TextFormField in Flutter, but is it possible to integrate a DropdownButton into a Form and require one of its value be selected before submission?
Basically, integrate DropdownButton validation into this basic Flutter validation example:
https://flutter.io/cookbook/forms/validation/
Dart Package have already the widget DropdownButtonFormField for this. Here is an example of how to use it:
List<String> typeNeg = [
"One",
"Two",
"Three",];
String dropdownValue = "One";
DropdownButtonFormField<String>(
value: dropdownValue,
hint: Text("Type of business"),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
validator: (String value) {
if (value?.isEmpty ?? true) {
return 'Please enter a valid type of business';
}
},
items: typeNeg
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onSaved: (val) => setState(() => _user.typeNeg = val),
),
The user model is as follows:
class User {
int id;
String name;
String email;
String typeNeg;
User({this.id, this.name, this.email, this.typeNeg});
factory User.fromJson(Map<String, dynamic> parsedJson) {
return User(
id: parsedJson["id"],
name: parsedJson["name"] as String,
email: parsedJson["email"] as String,
typeNeg: parsedJson["typeNeg"] as String,
);
}
save(){
print("User saved");
}
}
To try the validator option change String dropdownValue = "One"; to String dropdownValue = null;
From text_form_field.dart file in Flutter's source code you can see that TextFormField is no more than a FormField emitting a TextField widget in its builder callback. You can write your own DropdownFormField using a similar pattern. Here's mine:
import 'package:flutter/material.dart';
class DropdownFormField<T> extends FormField<T> {
DropdownFormField({
Key key,
InputDecoration decoration,
T initialValue,
List<DropdownMenuItem<T>> items,
bool autovalidate = false,
FormFieldSetter<T> onSaved,
FormFieldValidator<T> validator,
}) : super(
key: key,
onSaved: onSaved,
validator: validator,
autovalidate: autovalidate,
initialValue: items.contains(initialValue) ? initialValue : null,
builder: (FormFieldState<T> field) {
final InputDecoration effectiveDecoration = (decoration ?? const InputDecoration())
.applyDefaults(Theme.of(field.context).inputDecorationTheme);
return InputDecorator(
decoration:
effectiveDecoration.copyWith(errorText: field.hasError ? field.errorText : null),
isEmpty: field.value == '' || field.value == null,
child: DropdownButtonHideUnderline(
child: DropdownButton<T>(
value: field.value,
isDense: true,
onChanged: field.didChange,
items: items.toList(),
),
),
);
},
);
}
The key is to bind DropdownButton's onChanged to field.didChange. Usage is pretty straightforward:
DropdownFormField<String>(
validator: (value) {
if (value == null) {
return 'Required';
}
},
onSaved: (value) {
// ...
},
decoration: InputDecoration(
border: UnderlineInputBorder(),
filled: true,
labelText: 'Demo',
),
initialValue: null,
items: [
DropdownMenuItem<String>(
value: '1',
child: Text('1'),
),
DropdownMenuItem<String>(
value: '2',
child: Text('2'),
)
],
),
I got the idea from this site. The difference is that my version of DropdownFormField is closer to Flutter's native implementation (which extends TextFormField instead of wrapping it inside a StatefulWidget).
I am new to Flutter/Dart, Go and mobile development in general. I am currently coding a login authentication page in flutter that connects to a backend written in go. To check if everything worked I wanted to print out the cookie that my backend sends back in the console. Unfortunately I am getting errors not sure what to do.
EDIT: I have been able to read the cookie, should I save the cookie in this format "session=UUID" or just the "UUID"? I want to send this cookie back in the header for future get requests. My Go code will check for the cookie name "session",but I'm not sure if sending it back in that format is correct.
Flutter code (I read on another stackoverflow post to use 10.0.2.2 as localhost when using an android emulator):
EDIT: After playing around with the code I was able to read the cookie in the header but it has the name as well not just the UUID.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Login extends StatefulWidget {
#override
State<StatefulWidget> createState(){
return new LoginState();
}
}
class LoginState extends State <Login> {
final formKey = GlobalKey<FormState>();
String _email, _password;
String cookie;
void loginApi(){
var form = formKey.currentState;
var url = "http://10.0.2.2:8080";
if (form.validate()) {
form.save();
var body = { "Email":_email, "Pass":_password};
http.post(url,body:json.encode(body)).then((response){
print(response.headers['set-cookie']);
});
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Login"),
backgroundColor: Colors.white,
),
body: new Container(
alignment: Alignment.center,
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
autocorrect: false,
decoration: InputDecoration(
labelText: "Email:",
),
validator: (str) =>
!str.contains('#') ? "Not a Valid Email!" : null,
onSaved: (str) => _email = str,
),
TextFormField(
autocorrect: false,
decoration: InputDecoration(
labelText: "Password:",
),
validator: (str) =>
str.length <= 7 ? "Not a Valid Password!" : null,
onSaved: (str) => _password = str,
obscureText: false,
),
RaisedButton(
child: Text("Submit"),
onPressed:loginApi,
),
],
)
),
),
);
}
}
Golang code (EDIT: Inserted a missing curly bracket after the panic error and deleted the curly bracket at the end of the code):
package main
import (
"encoding/json"
"html/template"
"net/http"
uuid "github.com/satori/go.uuid"
"golang.org/x/crypto/bcrypt"
)
type user struct {
UserName string //Same as email
Password []byte
}
type logindata struct {
Email string
Pass string
}
var tpl *template.Template
var dbUsers = map[string]user{}
var dbSess = map[string]string{}
func init() {
bs, _ := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.MinCost)
dbUsers["test#test.com"] = user{"test#test.com", bs}
}
func main() {
http.HandleFunc("/", login)
http.Handle("/favicon.ico", http.NotFoundHandler()) //Don't have favicon
http.ListenAndServe(":8080", nil)
}
func login(w http.ResponseWriter, req *http.Request) {
var data logindata
decoder := json.NewDecoder(req.Body)
err_decode := decoder.Decode(&data)
if err_decode != nil {
panic(err_decode)
}
u, ok := dbUsers[data.Email]
if !ok {
http.Error(w, "Username and/or password do not match", http.StatusForbidden)
return
}
err_compare := bcrypt.CompareHashAndPassword(u.Password, []byte(data.Pass))
if err_compare != nil {
http.Error(w, "Username and/or password do not match", http.StatusForbidden)
return
}
// create session
sID, _ := uuid.NewV4()
c := &http.Cookie{
Name: "session",
Value: sID.String(),
}
http.SetCookie(w, c)
dbSess[c.Value] = data.Email
return
}
Output from console for flutter code (after I put in username and password and click submit, username is "test#test.com" password is "password"):
Performing hot reload...
Reloaded 0 of 489 libraries in 544ms.
I/flutter ( 3778): session=db3690d6-db6e-4658-8b5b-5f2d3f908a65
I also went to localhost:8080 on my browser expecting to show a blank page but it displayed "page not working" and my terminal outputted the following error I guess because I was accessing it with a browser and I wasn't sending in JSON data, not sure:
2018/05/24 23:29:38 http: panic serving [::1]:40010: EOF
goroutine 6 [running]:
net/http.(*conn).serve.func1(0xc82001a280)
/usr/lib/go-1.6/src/net/http/server.go:1389 +0xc1
panic(0x76c6c0, 0xc82000a160)
/usr/lib/go-1.6/src/runtime/panic.go:443 +0x4e9
main.login(0x7f96c9a848b8, 0xc82012c000, 0xc8201121c0)
/home/daniel/Desktop/Workspace/Genesis/main.go:43 +0x176
net/http.HandlerFunc.ServeHTTP(0x8a8688, 0x7f96c9a848b8, 0xc82012c000, 0xc8201121c0)
/usr/lib/go-1.6/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820013020, 0x7f96c9a848b8, 0xc82012c000, 0xc8201121c0)
/usr/lib/go-1.6/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc82001a100, 0x7f96c9a848b8, 0xc82012c000, 0xc8201121c0)
/usr/lib/go-1.6/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc82001a280)
/usr/lib/go-1.6/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/lib/go-1.6/src/net/http/server.go:2137 +0x44e
2018/05/24 23:29:38 http: panic serving [::1]:40012: EOF
goroutine 18 [running]:
net/http.(*conn).serve.func1(0xc82011c080)
/usr/lib/go-1.6/src/net/http/server.go:1389 +0xc1
panic(0x76c6c0, 0xc82000a160)
/usr/lib/go-1.6/src/runtime/panic.go:443 +0x4e9
main.login(0x7f96c9a848b8, 0xc8201161a0, 0xc820154000)
/home/daniel/Desktop/Workspace/Genesis/main.go:43 +0x176
net/http.HandlerFunc.ServeHTTP(0x8a8688, 0x7f96c9a848b8, 0xc8201161a0, 0xc820154000)
/usr/lib/go-1.6/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820013020, 0x7f96c9a848b8, 0xc8201161a0, 0xc820154000)
/usr/lib/go-1.6/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc82001a100, 0x7f96c9a848b8, 0xc8201161a0, 0xc820154000)
/usr/lib/go-1.6/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc82011c080)
/usr/lib/go-1.6/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/lib/go-1.6/src/net/http/server.go:2137 +0x44e
2018/05/24 23:29:43 http: panic serving [::1]:40016: EOF
goroutine 7 [running]:
net/http.(*conn).serve.func1(0xc82001a380)
/usr/lib/go-1.6/src/net/http/server.go:1389 +0xc1
panic(0x76c6c0, 0xc82000a160)
/usr/lib/go-1.6/src/runtime/panic.go:443 +0x4e9
main.login(0x7f96c9a848b8, 0xc82012c1a0, 0xc8201122a0)
/home/daniel/Desktop/Workspace/Genesis/main.go:43 +0x176
net/http.HandlerFunc.ServeHTTP(0x8a8688, 0x7f96c9a848b8, 0xc82012c1a0, 0xc8201122a0)
/usr/lib/go-1.6/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820013020, 0x7f96c9a848b8, 0xc82012c1a0, 0xc8201122a0)
/usr/lib/go-1.6/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc82001a100, 0x7f96c9a848b8, 0xc82012c1a0, 0xc8201122a0)
/usr/lib/go-1.6/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc82001a380)
/usr/lib/go-1.6/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/lib/go-1.6/src/net/http/server.go:2137 +0x44e
In your code
http.post(url,body:json.encode(body)).then((http.Response response){
cookie = response.headers['session'];
});
debugPrint(cookie);
the line
debugPrint(cookie);
is executed before
cookie = response.headers['session'];
so it is expected that cookie is null when you print it. For some weird reason debugPrint(null) throws an exception about "slit on null"
Try instead
http.post(url,body:json.encode(body)).then((http.Response response){
cookie = response.headers['session'];
debugPrint(cookie);
});