Flutter : How to delete Rest Api Using Http.Client? - api

I develope App for CRUD Operation rest api using Http Client. GET and POST work perfectly, but problem come after DELETE Operation.
Console Message show me response code Bad Request 400 **, I Check code rest Api (in my codeigniter) **Bad Request 400 it's means the ID is null or not passing the ID on URL Rest Api.
It's Console Message Image
But I try on POSTMAN and **DELETE* is perfectly work , i dont know why in flutter http.delete not working.
It's Result POSTMAN Working
My Api Url for Delete
http://192.168.43.159/wpu-rest-server/apii/mahasiswa/delete/
It's My API.dart :
Future<bool> checkPost(Map<String, dynamic> id) async {
final client = http.Client();
try {
final response = await client.send(http.Request(
"DELETE", Uri.parse("${Urls.BASE_API_URL}mahasiswa/delete/"))
..headers['Content-type']= 'application/x-www-form-urlencoded'
..body = jsonEncode(id));
print(response.reasonPhrase);
print(response.statusCode.toString());
print(response.request.toString());
return response.statusCode == 204;
} finally {}
}
It's My list.dart :
void _checkPost() async{
final post = {"id":widget.id};
bool result = await api.checkPost(post);
if (result) {
_showSnackBar(
context, 'Success ');
} else {
_showSnackBar(context, 'Failed');
return null;
}
}
If you need Rest Api Code :
Controller
public function delete_delete()
{
$id = $this->delete('id');
$msgDelete = ['id' => $id, 'message' => 'Deleted the resource'];
$msgEmpty = ['status' => false, 'message' => 'ID Not Found'];
$msgBadRequest = ['status' => false, 'message' => 'Provide an ID'];
if ($id === null) {
$this->set_response($msgBadRequest, 400);
} else {
if ($this->mahasiswa->deleteMahasiswa($id) > 0) {
$this->set_response($msgDelete, 204);
} else {
$this->set_response($msgEmpty, 404);
}
}
}
Model
public function deleteMahasiswa($id = null)
{
if ($id === null) {
return false;
} else {
$this->db->delete('mahasiswa', ['id' => $id]);
return $this->db->affected_rows();
}
}
I'm mistake something ?
I ever heard httpclient.delete can't add body , but in POSTMAN need add body for deleting data, how to handle this ?

Related

Make a parameter in minimal api as an optional in .NET Core

I have this API as you can see:
app.MapGet("/api/fund/{fundCode}", ([FromServices] IMediator mediator,string fundCode)
=> mediator.Send(new GetFundsQuery(fundCode)));
I want to set fundcode as an optional parameter to my API, so I changed it to
app.MapGet("/api/fund/{fundCode?}", ([FromServices] IMediator mediator,string fundCode)
=> mediator.Send(new GetFundsQuery(fundCode)));
But it didn't work, and when I call this address
https://localhost:7147/api/fund
I get an http 404 error. Why?
When I used code below, I'll get "null" as a response when I call localhost:port/hello. But when I use string id as the parameter, I got 400 bad request...
app.MapGet("/hello/{id?}", (string? id) =>
{
if (id == null)
{
return "null";
}
else {
return id;
}
});
I also tried to use code below and when I call localhost:port/hello, I get "empty" as the response.
app.MapGet("/hello/{id?}", (string? id) =>
{
if (id == null)
{
return "null";
}
else {
return id;
}
});
app.MapGet("/hello", () =>
{
return "empty";
});
You can try the query parameter. For example:
app.MapGet("/api/fund", GetFundsAsync).Produces<IList<Fund>>();
private async Task<IList> GetFundsAsync(IMediator mediator,string fundCode = null)
{
return await mediator.Send(new GetFundsQuery(fundCode));
}
This way https://localhost:7147/api/fund will return results
And https://localhost:7147/api/fund?fundCode=ABC will work too

NetCore3 API not returning/serializing my data

I have the following controller:
[HttpGet("idfull/{id}")]
public async Task<IActionResult> GetAccountByIdFull(int id)
{
try
{
var response = await _accountFacade.GetAccountByIdAsync(id, full: true).ConfigureAwait(false);
if (response == null)
return NoContent();
return Ok(response);
}
catch (KeyNotFoundException kEx)
{
return NotFound();
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
}
The Facade layer:
public async Task<AccountViewModel> GetAccountByIdAsync(int accountId, bool full = false)
{
try
{
var unmappedResponse = await _accountService.GetAccountByIdAsync(accountId, full);
var mappedResponse = _mapper.Map<AccountViewModel>(unmappedResponse);
return mappedResponse;
}
catch
{
throw;
}
}
The service layer:
public async Task<Account> GetAccountByIdAsync(int accountId, bool full = false)
{
try
{
Account account;
if (full)
{
account = await _repo.GetOneAsync<Account>(x => x.AccountId == accountId);
account.Company = await _repo.GetOneAsync<Company>(filter: x => x.CompanyId == account.CompanyId,
includes: source => source
.Include(c => c.CompanyTransferType)
.ThenInclude(ctt => ctt.PartnerCompanyAccountType)
.Include(c => c.CompanyTransferType).ThenInclude(ctt => ctt.TransferType)
.Include(c => c.CompanyEquipment).ThenInclude(ce => ce.Equipment)
.Include(c => c.CompanyAccountGroup)
.Include(c => c.CompanyAccountType));
account.AccountContact = await _repo.GetAsync<AccountContact>(filter: x => x.AccountId == accountId);
account.AccountEquipment = await _repo.GetAsync<AccountEquipment>(filter: x => x.AccountId == accountId,
includes: source => source
.Include(ae => ae.AccountEquipmentFee).Include(ae => ae.CompanyEquipment).ThenInclude(ce => ce.Equipment));
account.AccountPickVolumeDefaultAccount = await _repo.GetAsync<AccountPickVolumeDefault>(filter: x => x.AccountId == accountId,
includes: source => source
.Include(a => a.Equipment).Include(a => a.PartnerAccount));
}
else
{
account = await _repo.GetByIdAsync<Account>(accountId);
}
if (account == null)
throw new KeyNotFoundException($"Could not find Account with ID: {accountId}");
return account;
}
catch
{
throw;
}
}
What I do not understand is, the controller returns OK status and all of my fields are populated. However, the API hangs and does not return my data, in other words, the Swagger API (including front-end application) does not receive the response and keeps on showing the loading button.
I have a funny feeling it has something to do with Serialization, but not sure how to fix it.
I have made sure to turn off SelfRefenceLooping, as can be seen here:
services.AddControllers().AddNewtonsoftJson(setup =>
{
setup.SerializerSettings.ContractResolver = new DefaultContractResolver();
setup.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
Why is the API not returning the JSON object?
Can you try without the .ConfigureAwait(false)?
Except for that, you code seems ok and the API should work fine.
If you don't have it, I would recommend adding Swagger to your API, it's just a matter of 5-10 lines and it helps a lot in the development phase (and also avoid manual mistakes while testing). Here is the official documentation: ASP.NET Core web API help pages with Swagger / OpenAPI
You can also try to add a very dumb action in your controller, to try to identify where the issue comes from (Controller layer? Service layer? Facade layer?)

Yii2-How to access a variable from model to a controller?

I am working on yii2. I have came across a point in which I have to send an email to a person when a meter is installed and it's images are uploaded to the server. Fro this I have already configured the swift mailer.
There is a model named Installations which have a function which saves all the installation data.
public static function saveAll($inputs){
$coutner = 0;
$arr_status = [];
foreach ($inputs as $input) {
$s = new Installations;
foreach ((array)$input as $key => $value) {
if($key != 'image_names') {
if ($s->hasAttribute($key)) {
$s->$key = $value;
}
}
}
$user = Yii::$app->user;
if (isset($input->auth_key) && Users::find()->where(['auth_key' => $input->auth_key])->exists()) {
$user = Users::find()->where(['auth_key' => $input->auth_key])->one();
}
$s->created_by = $user->id;
if (Installations::find()->where(['ref_no' => $input->ref_no])->exists()) {
$arr_status[] = ['install_id' => $input->install_id, 'status' => 2, 'messages' => "Ref # Already exists"];
continue;
}
$s->sync_date = date('Y-m-d H:i:sā€Šā€Š');
if($s->save()){
if ($s->istallation_status == 'Installed') {
Meters::change_status_byinstall($s->meter_msn, Meters::$status_titles[4]);
}
else if ($s->istallation_status != 'Installed' && $s->comm_status =='Failed')
{
Meters::change_status_byinstall($s->meter_msn, Meters::$status_titles[5]);
}
$arr_status[] = ['install_id' => $input->install_id, 'status' => 1];
$coutner++;
if (isset($input->doc_images_name)) {
foreach ($input->doc_images_name as $img) {
$image = new InstallationImages;
$image->image_name = $img->image_name;
$image->installation_id = $s->id;
$image->save();
}
}
if (isset($input->site_images_name)) {
foreach ($input->site_images_name as $img2) {
$image2 = new InstallationImagesSite;
$image2->image_name = $img2->image_name;
$image2->installation_id = $s->id;
$image2->save();
}
}
}else{
$arr_status[] = ['install_id' => $input->install_id, 'status' => 0, 'messages' => $s->errors];
}
$status = $s->istallation_status;
$msn = $s->meter_msn;
$com = $s->comm_status;
// want to pass these variables to the controller function
}
return ['status' => 'OK', 'details' => $arr_status, 'records_saved' => $coutner];
}
Now There Is a Controller name InstallationController. This controller contains all the APIs for my mobile application. Below are two main functions in it
public function actionAddnew()
{
$fp = fopen('debugeeeeeee.txt', 'w+');
fwrite($fp, file_get_contents('php://input'));
fclose($fp);
$inputs = json_decode(file_get_contents('php://input'));
return Installations::saveAll($inputs);
}
public function actionSavephoto()
{
try {
$count = 0;
foreach ($_FILES as $f) {
$dd = pathinfo($f['name']);
if (!isset($dd['extension']) || !in_array($dd['extension'], array('jpg', 'png', 'gif'))) {
return ['status' => 'ERROR', 'uploaded_files' => $count, 'message' => 'Invalid File'];
break;
}
if (move_uploaded_file($f['tmp_name'], Installations::UPLOAD_FOLDER . $f['name'])) {
$count++;
return ['status' => 'OK', 'uploaded_files' => $count];
break;
} else {
return ['status' => 'ERROR', 'uploaded_files' => $count];
break;
}
}
} catch (Exception $x) {
return ['status' => 'ERROR', 'message' => $x->getMessage()];
}
}
The mobile application will call the Addnew() api and after that it will call the savephoto. Now I want to pass $msn,$status and $com values from the Model to the controller function Savephoto.
For this I have tried to use session variables but still I am unable to get by desired result(s).
I have also checked the question Yii, how to pass variables to model from controller?
but it didn't worked for me.
How can I achieve it?
Any help would be highly appreciated.
The only way to get those values out of saveAll() is to return them. Presently, they are defined on an object in $s that is overwritten each loop. The best way to do that seems to be creating an array outside of your foreach ($inputs... loop and appending each created Installations object.
Return that at the end, and pass it (or just the relevant element from it) into actionSavephoto() as a parameter. Then, those values will be accessible of properties of that passed object. This handling will occur in the code that is not pictured which calls actionAddNew() and then actionSavephoto()

Linkedin API: Exchange JSAPI Token for REST API OAuth Token

I'm having some difficulty exchanging my JSAPI token for a REST API token. I'm using this for reference:
https://developer-programs.linkedin.com/documents/exchange-jsapi-tokens-rest-api-oauth-tokens
I've: set up a self signed SSL cert locally, so Linkedin's secure cookie works properly; given my app r_basicprofile and r_emailaddress permissions.
Here's my front end code:
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: **MY_CLIENT_ID**
authorize: true
credentials_cookie: true
</script>
...
$('.linkedin-signin').click(function(e) {
IN.User.authorize( function () {
IN.API.Raw("/people/~").result(function(data) {
$.post(location.origin+'/api/account/create/linkedin', { 'lId': data.id } ).done(function(result) {
console.log(result);
});
});
});
return false;
});
And here is my PHP code, which is almost exactly as in their docs:
$consumer_key = '**MY_CLIENT_ID**';
$consumer_secret = '**MY_CLIENT_SECRET**';
$cookie_name = "linkedin_oauth_${consumer_key}";
$credentials_json = $_COOKIE[$cookie_name];
$credentials = json_decode($credentials_json);
$access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
$oauth = new OAuth($consumer_key, $consumer_secret);
$access_token = $credentials->access_token;
// swap 2.0 token for 1.0a token and secret
$oauth->fetch($access_token_url, array('xoauth_oauth2_access_token' => $access_token), OAUTH_HTTP_METHOD_POST);
Everything looks good, but on $oauth->fetch, I get the error:
OAuthException(code: 401): Invalid auth/bad request (got a 401, expected HTTP/1.1 20X or a redirect)
Which leads me to believe that the token is invalid... but it's taken directly from the cookie, so how could it be invalid? Any ideas?
Today we got the weird 401 error too, apperently linkedin was broken, because after an hour it worked again without any changes on our side.
I found this site though and eventhough it's a really old post, i tought i'd share how we fixed it, which works.
JS Front-end
var AppConfig = {
linkedin : {
onLoad : "linkedinLibInit",
api_key : 'YOUR_API_KEY',
authorize : false,
credentials_cookie: true
}
};
window.linkedinLibInit = function ( response ) {
// post init magic
// cleanup window callback function
delete window.linkedinLibInit;
}
$.getScript( "//platform.linkedin.com/in.js?async=true", function success() {
IN.init( AppConfig.linkedin );
} );
function connectToLinkedIn() {
if ( IN.User.isAuthorized() ) {
_linkedinAuthorized();
}
else {
IN.User.authorize( _linkedinAuthorized );
}
}
function _linkedinAuthorized() {
IN.API.Profile( "me" )
.fields( 'id', 'first-name', 'last-name', 'location', 'industry', 'headline', 'picture-urls::(original)', 'email-address' )
.result( function ( response ) {
var accessToken = JSON.parse( $.cookie( 'linkedin_oauth_' + AppConfig.linkedin.api_key ) );
// performApi Call to backend
} )
.error( function ( err ) {
// render error
} );
}
PHP Backend using PECL oAuth
function offlineAuthLinkedIn($accessToken, $linkedinConfig) {
$oAuth = new \OAuth( $linkedinConfig['app_id'], $linkedinConfig['app_secret'] );
$oAuth->fetch(
'https://api.linkedin.com/uas/oauth/accessToken',
array('xoauth_oauth2_access_token' => $accessToken),
OAUTH_HTTP_METHOD_POST
);
$response = null;
parse_str($oAuth->getLastResponse(), $response);
$oAuth->setToken($response['oauth_token'], $response['oauth_token_secret']);
$oAuth->fetch(
'http://api.linkedin.com/v1/people/~:(id,first-name,last-name,formatted-name,headline,location,picture-url,picture-urls::(original),public-profile-url)',
array(),
OAUTH_HTTP_METHOD_GET,
array('x-li-format' => 'json')
);
$profile = json_decode($oAuth->getLastResponse(), true);
$profile['user_id'] = $profile['id'];
if (true == isset($profile['pictureUrl']))
{
$profile['profile_image'] = $profile['pictureUrl'];
unset($profile['pictureUrl']);
}
return $profile;
}

Yii::app()->user->isGuest always returns true even though login was successful

I started to make some differences between those users which have authenticated and those that not. For this, i am using
Yii::app()->user->id;
However, in a determined view i put the following code:
<?php
if(Yii::app()->user->isGuest) {
print("Welcome back Guest!");
print("Your id is ".Yii::app()->user->id);
} else {
print("Welcome back ".Yii::app()->user->name);
print("Your id is ".Yii::app()->user->id);
}?>
And i always get the "welcome back guest!", whether i have logged in (successfully) or not. And if i have logged in, then it displays the welcome message together with the user's id!
EDIT
#briiC.lv
Hey.. sorry for the late reply, I hope you are still following this! I am not extending the given UserIdentity class. Is this mandatory? Since i still dont get very well the whole authorization issue, i thought it would be best to give a try with the class they provide, and then extend with my own functionality.. Anyway, next i post my UserIdentity class with its small tweaks.. maybe the problem lies here??
<?php class UserIdentity extends CUserIdentity{
private $_id;
public function authenticate()
{
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0]))
{
return false;
}
else
{
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
}
public function getId()
{
return $this->_id;
}
}
Here is the output i got when i started to log as you suggested; i got this output immediately after successfully logging in.
[05:23:21.833][trace][vardump] CWebUser#1 (
[allowAutoLogin] => true
[guestName] => 'Guest'
[loginUrl] => array ( '0' => '/site/login' )
[identityCookie] => null
[authTimeout] => null
[autoRenewCookie] => false
[autoUpdateFlash] => true
[CWebUser:_keyPrefix] => '0f4431ceed8f17883650835e575b504b'
[CWebUser:_access] => array()
[behaviors] => array()
[CApplicationComponent:_initialized] => true
[CComponent:_e] => null
[CComponent:_m] => null
)
Any help is much appreciated!
Maybe you can try to debug harder:
change messages to something like this:
if(Yii::app()->user->isGuest) {
print("Not logged");
} else {
print_r(Yii::app()->user);
print("Welcome ".Yii::app()->user->name);
print("Your id is ".Yii::app()->user->id);
}
And check session variable in your config/main.php file
...
'session' => array(
'autoStart'=>true,
),
...
The error is in the following line
$this->setState('id', $user[0]->id);
As seen in the official yii documentation regarding auth & auth, setState should be used for anything but the id field. In order to implement the key Yii will use to identify your user, return a unique value per user in the Identity getId() function.
In your case, this means you simply have to change the above line into the following:
$this->_id = $user[0]->id;
Regarding the actual inner working of the login procedure, I'd recommend a look at the CWebUser class, and especially at its login function, which is responsible for the actual storage of the Identity getId() return value.
when you call authenticate function login user as
$userIdentity = new UserIdentity($username, $password);
$userIdentity->authenticate();
if ($userIdentity->errorCode===UserIdentity::ERROR_NONE) {
Yii::app()->user->login($userIdentity,0);
}
and fetch id as
echo 'id='.Yii::app()->user->getId();
apply this code and check
I have faced same problem and found that only one line in UserIdentity Component will resolve this issue.
This is your code:
else
{
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
Update this code by this one
else
{
$this->_id = $user[0]->id;
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
First of all, you need to know condition that sets guest and logged-in user apart.
Based on Yii master's branch CWebUser::getIsGuest():
public function getIsGuest()
{
return $this->getState('__id')===null;
}
Compared to your code:
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0])) {
// false
} else {
$this->setState('id', $user[0]->id); // this is for persistent state sakes
...
}
}
In short: you did supply 'id' to Identity persistent state but Yii CWebUser expecting '__id' based on UserIdentity::getId().
Solution is pretty dead simple. You just need to set $this->_id
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0])) {
// false
} else {
$this->setState('id', $user[0]->id); // this is for persistent state sakes
$this->_id = $user[0]->id; // this is UserIdentity's ID that'll be fetch by CWebUser
...
}
}
This routine explains how CWebUser get UserIdentity's ID: https://github.com/yiisoft/yii/blob/master/framework/web/auth/CWebUser.php#L221
Please do test it out.
Please try following code. Its working well
//config/main.php
return array (
'component' => array(
'session' => array(
'savePath' => INSTANCE_ROOT.DS.'runtime'.DS.'session',
'autoStart' => true,
),
)
);
// LoginController
class LoginController extends CController {
public function actionLogin () {
if(isset($_POST['LoginForm']))
{
$form = new LoginForm;
$form->setAttributes($_POST['LoginForm']);
if ($form->validate()) {
$user = Users::model()->find('upper(username) = :username', array(
':username' => strtoupper($form->username)));
if($user)
return $this->authenticate($user, $form);
else {
Yii::log( 'som.....', 'error');
$form->addError('password', Yii::t('Username or Password is incorrect'));
}
return false;
}
}
}
protected function authenticate($user, $form) {
$identity = new UserIdentity($user->username, $form->password);
$identity->authenticate();
switch($identity->errorCode) {
case UserIdentity::ERROR_NONE:
$duration = $form->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->user->login($identity,$duration);
return $user;
break;
case UserIdentity::ERROR_EMAIL_INVALID:
$form->addError("password",Yii::t('Username or Password is incorrect'));
break;
case UserIdentity::ERROR_STATUS_INACTIVE:
$form->addError("status",Yii::t('This account is not activated.'));
break;
case UserIdentity::ERROR_STATUS_BANNED:
$form->addError("status",Yii::t('This account is blocked.'));
break;
case UserIdentity::ERROR_STATUS_REMOVED:
$form->addError('status', Yii::t('Your account has been deleted.'));
break;
case UserIdentity::ERROR_PASSWORD_INVALID:
Yii::log( Yii::t(
'Password invalid for user {username} (Ip-Address: {ip})', array(
'{ip}' => Yii::app()->request->getUserHostAddress(),
'{username}' => $form->username)), 'error');
if(!$form->hasErrors())
$form->addError("password",Yii::t('Username or Password is incorrect'));
break;
return false;
}
}
}
class UserIdentity extends CUserIdentity {
const ERROR_EMAIL_INVALID=3;
const ERROR_STATUS_INACTIVE=4;
const ERROR_STATUS_BANNED=5;
const ERROR_STATUS_REMOVED=6;
const ERROR_STATUS_USER_DOES_NOT_EXIST=7;
public function authenticate()
{
$user = Users::model()->find('username = :username', array(
':username' => $this->username));
if(!$user)
return self::ERROR_STATUS_USER_DOES_NOT_EXIST;
if(Users::encrypt($this->password)!==$user->password)
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else if($user->status == YumUser::STATUS_INACTIVE)
$this->errorCode=self::ERROR_STATUS_INACTIVE;
else if($user->status == YumUser::STATUS_BANNED)
$this->errorCode=self::ERROR_STATUS_BANNED;
else if($user->status == YumUser::STATUS_REMOVED)
$this->errorCode=self::ERROR_STATUS_REMOVED;
return !$this->errorCode;
}
}
class Users extends CActiveModel
{
const STATUS_INACTIVE = 0;
const STATUS_ACTIVE = 1;
const STATUS_BANNED = -1;
const STATUS_REMOVED = -2;
// some ..........
public static function encrypt($string = "")
{
$salt = 'salt';
$string = sprintf("%s%s%s", $salt, $string, $salt);
return md5($string);
}
}
check your security configuration for cookies and sessions.
disable session.use_only_cookies & session.cookie_httponly in php.ini
file.
in PHP.INI => session.use_only_cookies = 0