How to read and write Data in Airtable with Flutter? - flutter

dependencies:
airtable: ^0.0.2
import 'package:airtable/airtable.dart'; ??
import 'package:dart_airtable/dart_airtable.dart'; ??
void main() async {
final apiKey = 'my-airtable-api-key'
final projectBase = 'my-airtable-project-base';
final recordName = 'Tasks';
var airtable = Airtable(apiKey: apiKey, projectBase: projectBase);
var records = await airtable.getAllRecords(recordName);
print(records);
}
If anyone knows how to solve it, I will be very grateful.

First of all, it seems like you mix two things together. Currently there are two packages that provide a library for the communication with airtable: airtable 0.0.2 and dart_airtable 0.1.1.
In your example code you use the import statement for the first package but the code from the second one. As the first one doesn't provide a valid link to a repository I'll have a look at the second one.
To retrieve records for a project from the API you can use this code:
var records = await airtable.getAllRecords(recordName);
Unfortunately the package has some bugs. As I wanted to create a record I used the method createRecord like this:
var test = await airtable.createRecord(
recordName,
AirtableRecord(
fields: [
AirtableRecordField(
fieldName: 'Short Description',
value: 'Test Description',
),
],
),
);
print(test);
But the only response I got was null. So I cloned the project and debugged the method. The result was this:
{"error":{"type":"INVALID_REQUEST_UNKNOWN","message":"Invalid request: parameter validation failed. Check your request data."}}
After a little bit of searching I found out that the package sends wrong data to the airtable API. In a toJson method of the AirtableRecord model, the author added the unnecessary fields id and createdTime. After deleting them, the method works.
Response:
AirtableRecord(id: rec9bqN78Le1dbC1g, createdTime: 2020-10-20 19:10:21.000Z, fields: {Short Description: Test Description})
I didn't look for the remaining methods, but my advice is to write your own connection to the airtime API or use the existing package and change the things that aren't working. Hopefully this helps you.
Edit:
I'll checked the repository again, and it seems that the author is inactive. As it only contains a few methods and models to work with the airtable API, I'll guess it's not a bad idea to just wrote your own implementation.
Here an simple example of how to do this (with Dio for the network connection):
try {
final response = await Dio().post(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
data: {
'records': [
{
'fields': {
'Short Description': 'Cactus',
'Total': 11.5,
}
},
],
},
);
// TODO: Whatever you want to do with the response. A good practice is to transform it into models and than work with them
print(response);
} on DioError catch (e) {
// TODO: Error handling
if (e.response != null) {
print(e.response.data);
} else {
print(e.request);
print(e.message);
}
}
Response:
{"records":[{"id":"recrvxH93gJgAGo7j","fields":{"Short Description":"Cactus","Total":11.5},"createdTime":"2020-10-21T20:41:19.000Z"}]}
You could now extend this, maybe as a service with the GetIt package and add your required funtions. I definetly recommend to also use models for your response (have a look at this).
I used one of their example workspaces. The projectBase was an ID. You can just look at their API documentation to see how to build the requests.
Edit 2:
Read could be simple done by this:
final response = await Dio().get(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);
Update:
final response = await Dio().patch(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
data: {
'records': [
{
'id': 'rechYkD0pDW1NjFAF',
'fields': {
'Short Description': 'Cactus II',
'Total': 11.5,
}
},
],
},
);
And delete:
final response = await Dio().delete(
'https://api.airtable.com/v0/$projectBase/$recordName/rec0bMv507juqS7pv',
options: Options(
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);
These are only examples, I advice you to also read the API documentation to get a overview of what is possible. And your own implementation with proper error handling.
Edit 3:
You can use the filterByFormula parameter to retrieve all the data that matches your condition (Reference).
E.g.:
final response = await Dio().get(
'https://api.airtable.com/v0/$projectBase/$recordName',
queryParameters: {
'filterByFormula': 'SEARCH("Cactus",{Short Description})' // Searches the value 'Cactus' in the 'Short description' field.
},
options: Options(
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);

Related

Flutter http with authorisation: ClientException (Failed to parse header value)

I have an API that expects a JWT token.
I tested the API with https://hoppscotch.io, here is the query that returns the expected results (no error)
import axios from "axios";
const options = {
method: 'POST',
url: 'https://my_authority/text-message',
headers: {
Authorization: 'Bearer my_token',
'content-type': 'application/json'
},
data: {message: ''}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
And here is the code in Dart that fires the error ClientException (Failed to parse header value):
await http.post(
Uri.parse('$_httpEndpoint/$path'),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.authorizationHeader: 'Bearer my_token',
},
body: jsonEncode(body));
Both queries have the same parameters. I have no clue about the root causes.
Here is requests.headers in locals for IOClient.send when the error fires:
_CompactLinkedCustomHashMap ({content-type: application/json; charset=utf-8, authorization: Bearer my_token})
I don't know why http adds charset=utf-8, and I didn't manage to remove it.
I looked over the internet and didn't find an answer. Most of the similar questions are related to an error in the backend, it is not the case here.

Integrating BankID (Swedish authentication service) into Flutter (Android and Ios)

I'm trying to impletment Swedish bankid on one of my project. But the resources that are available on the internet is too little. Can anybody help me how to implement BankId authentication on flutter app.
Not sure on how much experience you have whit BankId, so maybe you already know some of the stuffs, but this is how I solved it.
The service has three main endpoints for performing verification:
/auth/start: This endpoint is used to initiate the verification process and generates a unique key, called a bankIdToken, which is returned in the form of a GUID.
/auth/status: This endpoint is used to check the status of a verification process that has been initiated with the /auth/start endpoint. The status can be "waiting" or "completed".
/auth/verify: This endpoint is used to verify the identity of a user who has completed the verification process and returns a JSON object containing information about the user.
To perform a verification, the steps are as follows:
Send a request to /auth/start to initiate the process and receive the bankIdToken.
Pass the bankIdToken to /auth/verify to trigger the verification on the user's device (mobile, pc) , the status will be waiting.
After the user completes the process on their device, check the status by sending a request to /auth/status that will change the status to completed.
Send a request to /auth/verify to verify the user, this will return a JSON object containing user information.
You can also get testing bankid at https://demo.bankid.com/ and fake Swedish person numbers in skatteverket or https://fejka.nu/ ( GDPR Approved)
This is my flutter code whit hardcoded values
class AuthDataSource {
Future<AuthVerifyModel> authFlow() async {
final authStartResponse = await http.post(
Uri.https(BASEURL, '/auth/start'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdNumber': '198806192392',
}),
);
if (authStartResponse.statusCode != 200) {
throw ServerException();
}
final authStartModel =
AuthStartModel.fromJson(jsonDecode(authStartResponse.body));
final authStatusResponse = await http.post(
Uri.https(BASEURL, '/auth/status'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdToken': authStartModel.bankIdToken.toString(),
}),
);
if (authStatusResponse.statusCode != 200) {
throw ServerException();
}
final authVerifyResponse = await http.post(
Uri.https(BASEURL, '/auth/verify'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdToken': authStartModel.bankIdToken.toString()
}),
);
if (authVerifyResponse.statusCode != 200) {
throw ServerException();
}
return AuthVerifyModel.fromJson(jsonDecode(authVerifyResponse.body));
}
}

Post Files to ASPNetCore API IFormFile Type

I want to send data with files to AspNetCore api that receive files type IFormFile I tried this
Dio dioFile = Dio(
BaseOptions(
baseUrl: baseUrl,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ${APIVariables.token}',
},
),
);
dioFile.post(
url,
data: {
"id": complaint.id,
"title": complaint.title,
"files": complaint.files
.map((file) => base64Encode(file.readAsBytesSync()))
.toList(),
};
);
but it shows dio error: DioError [DioErrorType.response]: Http status error [400].
How can I solve that and is there another better method to do that?
And if I want to send files using MultipartFile how can I do that and what api specialist should do to handle my post?
If you want to send the image file then,
It should look like this.
String fileName = imageFile.path.split('/').last;
FormData formData = FormData.fromMap({
"image-param-name": await MultipartFile.fromFile(
imageFile.path,
filename: fileName,
contentType: new MediaType("image", "jpeg"), //important
),
});
If without this line.
contentType: new MediaType("image", "jpeg")
Maybe it will cause an error: DioError [DioErrorType.RESPONSE]: Http status error [400] Exception
You must confirm the correct contentType to work it as expected
And get MediaType in this package: http_parser

DioErrorType.response: Http status error [415] when Sending FormData via Dio Flutter

I am trying to send dio form data with files to an api but this error comes up.
Dio dio = Dio(
BaseOptions(
baseUrl: baseUrl,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ${APIVariables.token}',
},
),
);
FormData formData = FormData.fromMap({
"id": complaint.id,
"title": complaint.title,
"description": complaint.description,
"complainedPosition": complaint.complainedPosition,
"deptId": complaint.departmentId,
"typeId": complaint.typeId,
"priortyId": complaint.priorityId,
"files": complaint.files
.map((file) async => await MultipartFile.fromFile(file.path,
filename: basename(file.path)))
.toList(),
});
Response response = await dio.post(
'Complaint',
data: formData,
),
how can I send files with options by correct way and show progress that has uploading percentage, and get response after completion?
First import http parser:
import 'package:http_parser/http_parser.dart';
You need add the content type also for your files like this:
"files": complaint.files
.map((file) async => await MultipartFile.fromFile(file.path,
filename: basename(file.path),contentType: MediaType('image', 'jpeg')))
I don't know what is your files type, change MediaType('image', 'jpeg') if your files media type is different

Dio Error : Http Status Error Code [ 405 ] Flutter

I am getting HTTP status error code 405 on sending post requests from the real devices but it's working inside the postman.
The URL is: https://amapp.adtestbed.com/api/post-survey
The following is the form data I am using
FormData formData = FormData.fromMap({
'user_id': id,
'is_collection':
jobDetailsResponseModel.jobData.jobStatus == '8' ? 1 : 0,
'job_id': jobDetailsResponseModel.jobData.id,
'job_no': bookingIdController.text.toString(),
'sender_name': senderNameController.text.toString(),
'reciever_name': recieverNameController.text.toString(),
'sender_phone': senderPhoneController.text.toString(),
'reciever_phone': recieverPhoneController.text.toString(),
'sender_address': senderAddressController.text.toString(),
'reciever_address': recieverAddressController.text.toString(),
'sender_signature_data':
"data:image/jpeg;base64," + base64Imagesendersign,
'receiver_signature_data':
"data:image/jpeg;base64," + base64Imagerecieversign,
'location': currentLocation,
'images[]': uploadimages,
'maked[]': makedlist,
'model[]': modallist,
'rego[]': regolist,
'speedo[]': speedolist,
'is_drivable[]': isdrivablelist,
'goods_inside[]': goodsinsidelist,
'external_condition[]': externalconditionlist,
'interior_condition[]': internalconditionlist,
'survey_image[]': surveyimagelist,
'comments[]': commentlist
});
Here images field is a multipart form list.
And doing requests as follows
final response = await Dio().request(
'https://amapp.adtestbed.com/api/post-survey',
data: formData,
options: Options(
headers: {
"Accept": "application/json",
},
method: 'POST',
),
);
also used the following code to check but still not working
final response = await Dio().post(
'https://amapp.adtestbed.com/api/post-survey',
data: formData,
options: Options(
// headers: {
// // "Accept": "application/json",
// // 'Content-Type': 'application/x-www-form-urlencoded'
// },
method: 'POST',
),
);
When I am sending the form without an images field then it's submitting perfectly and giving 200 status but when I am sending it's with an images field that contains a multipart form list then it's returning 405 status code. End giving the error like the get method not supported only support post method. I also checked the backend code but no error from that's side because it's giving an error before sending the request. I also checked if there were some null data that created errors but not a single field is null.
But when I am doing both cases in postman then it's working fine.
This is the postman link:
https://drive.google.com/file/d/1hTmDC2aQ7vTMxSnzwaeRqd9gv7UbPWhR/view?usp=sharing
These are some images of the postman
https://stackoverflow.com/a/64235806/11623001
Check this out I had a similar issue too before, and I also noticed that you are not adding your authorization token to your header which may explain why you are getting 405 which would mean you can't have access.
I tried to recreate your issue on my end but the authorization token is expired, I'm getting a 401, but here is the code:
void postSome() async {
String base64 =
//This base64 is shortened "data:image/png;base64,...+WZm/et53efvWO6Tuc6rH7kUXy1lxs+/61t7dMg6VAvURAAAAQHMQogDAbE6dlLXtft/F3cuvkJNbetbn7VWrpUUX+mvEtqdHvgAAAABoOf8P3x1uDPELl4UAAAAASUVORK5CYII=";
FormData formData = FormData.fromMap({
'user_id': 139,
'is_collection': "1" == '8' ? 1 : 0,
'job_id': "248",
'job_no': "60036JL#1",
'sender_name': "test",
'reciever_name': "test",
'sender_phone': "1234567890",
'reciever_phone': "1234567890",
'sender_address': "test",
'reciever_address': "test",
'sender_signature_data':
base64,
'receiver_signature_data': base64,
'location': "32, Gopal Nagar, Om Nagar, Gopal Nagar Society, Parvat Patiya, Surat, Gujarat 395010, India\n",
'images[]': "/D:/App/Logicwind/GitLAb/whiteboard-digitization/test_images/w11.jpg",
'maked[]': "test",
'model[]': "test",
'rego[]': "test",
'speedo[]': "123",
'is_drivable[]': "1",
'goods_inside[]': "1",
'external_condition[]': "3",
'interior_condition[]': "3",
'survey_image[]': base64,
'comments[]': "test"
});
final response = await Dio().request(
'https://amapp.adtestbed.com/api/post-survey',
data: formData,
options: Options(
headers: {
'Accept': "application/json",
'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIzIiwianRpIjoiNTlkNzNlZjE4YzcxNGJjMWM1ZjE0ZGQxOWE1OWZmNmQ1YjVhNDViNDIwNzlkODY4ZmJkOGRmNjJlOGM4MDQzNmVjYmIxZjc4MjM5MmZiOGIiLCJpYXQiOjE2MjgxNzY5NTAsIm5iZiI6MTYyODE3Njk1MCwiZXhwIjoxNjU5NzEyOTUwLCJzdWIiOiI0NiIsInNjb3BlcyI6W119.lfnzUvq_LwYtBUQ-t6S_mKXEoM6er6ZzCuTUoHnqz9wwrdLOcu6x9CEixqMRvI-RWtSoiMO5KCYZsgagayGW5slYk6zAAa0V5fCjkRipqqus6mXe6nowtcXs_2V9ucjVoH4Evkb9lFBlE1rlpxKgcGXTcx4UgQs8kjJ5Wm4A8omedza_hUQPN9KUAfhhBDeL9hq-DkC7QbLu_YxnG5g-AETKhbJu8T4HWKqkh9NKGbNlvs1oi_nD81F1w8uSteY-UOgDJyUoGJxzoD6xmEv3J4mkrdr1ZbG88EzTyk3zngwBp9eWcLHhMS2psxArOnOnWusweJJ5uZiWiu2VIL7fWmV5b6G4OCvvkba5eXmw8iAvACACuCGQtOcGdN_euUgyfM9z9a8QbK8M2I-ux4GGY0ejCamFEJZCTwyBCxmLIrP4XjQoeL71WT1YBOgSZwDjA6qrAfL_fLwbEYQYbLIF8fLUmDOWRKBIaJLSVNG2x0Gl5LLXTiTZAzRRtJlSxZ4-Vid4hQJX39lohp-47XPAxvHnNTxiLw_aAG3SruFZ_rtdX4xnNbV3hSI825CD5dBeQC5iE-hiLXDWDXelM_q2fSD1rez62XQZGp1KfvlwowxAWgIghTfSH_E52h6mdoHEo9q73UJNYDz_F9Sj8EOfY3VWtmN6HMmcs4HZht36qX4',
},
method: 'POST',
),
);
print(response.statusCode);
}
It looks like below two fields are files not a form data.
'sender_signature_data': "data:image/jpeg;base64," + base64Imagesendersign
'receiver_signature_data': "data:image/jpeg;base64," + base64Imagerecieversign
You should add those as file fields like this
"sender_signature_data": await MultipartFile.fromFile(sender_signature_path,
filename: fileName, contentType: MediaType(mimee, type))
}),
"receiver_signature_data":await MultipartFile.fromFile(reciever_signature_path,
filename: fileName, contentType: MediaType(mimee, type))
})