Angular - parse json string created by json dumps - javascript

I couldn't find a helpful solution.
I work in python 3.6 (django rest-framwork) server side and angular 5 client side.
At the server:
class TypesView(APIView):
def get(self,request):
a = ['Cat','Dog']
j = json.dumps(a)
return Response(data=j, status=status.HTTP_200_OK)
I am trying to parse this at the client:
public getAnimalRaces(): Observable<string[]>{
const path = environment.apiEndpoint + "animals/races/"
return this._http_client.get<string[]>(path)
}
but I keep getting:
Error trying to diff '["Cat", "Dog"]'. Only arrays and iterables are allowed
This is what Being returned to the client:
"[\"Cat\", \"Dog\"]"
any ideas?

You are trying to iterate on a string.
You need to parse the response as JSON which will turn the response into an array which you can then use with *ngFor in the template for example.
this._http_client.get<string[]>(path)
.map((res) => JSON.parse(res));

Your response is stringified. In order to make it work, you have to send it as plain JSON on server side, or treat it as string and use JSON.parse() on client side.

Related

How to send FormData attribute with an array of strings from React Client to Django + Django Rest Framework API

How can I send JSON.stringify(array) data within form-data and decode the JSON with my Django api?
I'm trying to add the functionality to upload an array of date-strings within a form
originally we sent the post data using JSON and sending arrays of data worked, however, when we switched to using form-data in order to make uploading an image easier we started having problems with array types.
since form data has to be sent using a string type I converted the date-string array using JSON.stringify()
const myForm = new FormData();
myForm.set("date_strings", JSON.stringify(dateStrings));
when I post myForm to my Django + DRF API it responds with
{
"date_strings": [
"Datetime has wrong format. Use one of these formats instead: YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]."
],
"status_code": 400
}
In Postman I verified that sending a single date-string works, but when I send a string-array I get the same error.
I believe my Django API tests if the request.data is valid, sees that date_strings are a JSON string, then responds with a 400 Error.
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
Attempted Solutions:
converting the JSON string to an array in the PostViewset create method
I can't change request.data['publish_dates'] because it is not mutable and I've seen some advice that you should not attempt to copy or change request data in the viewset because it isn't safe.
convert the JSON string to an array in the serializer
neither MySerializer's create nor validate methods run (I logged to test).
date_strings are formated and created as a separate PublishDate model in the create method,
class MySerializer(MyChildSerializer):
date_strings = serializers.ListField(child=serializers.DateTimeField(), min_length=1, max_length=100, write_only=True)
How can I send/accept form-data to my Django + DRF API when one attribute is an array of date-time strings?
I realized the problem and found a solution. Because MySerializer had set date_strings to be a ListField it was coming in as a string and being rejected as a bad request.
by changing the model of date_strings to a CharField, MySerializer runs the validate and create methods. I now have to find a way to convert the JSON date_strings back into an array in the serializer create method, but I solved the API's 400 issue.
MySerializer now looks like:
class CreatePostSerializer(SocialVeilModelSerializer):
publish_dates = serializers.CharField(max_length=2000)

API Connect - 500 error when including basic Javascript

I'm trying some basic API Connect tutorials on IBM's platform (running locally using loopback) and have got completely stuck at an early point.
I've built a basic API service with some in-memory data and setter / getter functions. I've then built a separate API which takes two GET parameters and uses one of my getter functions to perform a search based on two criteria. When I run it, I successfully get a response with the following JSON object:
[{"itemId":1,"charge":9,"itemSize":2,"id":2}]
I've then tried to add a piece of server logic that modifies the response data - at this point, I'm just trying to add an extra field. I've added a Javascript component in the Assemble view and included the following code (taken from a tutorial), which I thought should modify the message body returned by the API while still passing it through:
//APIC: get the payload
var json = apim.getvariable('message.body');
//console.error("json %s", JSON.stringify(json));
//same: code to inject new attribute
json.platform = 'Powered by IBM API Connect';
//APIC: set the payload
//message.body = json;
apim.setvariable('message.body', json);
Instead of getting an extra JSON parameter ("platform"), all I get is a 500 error when I call the service. I'm guessing that I'm doing something fundamentally wrong, but all the docs suggest these are the right variable names to use.
You can't access json.platform but at that point json variable is json type. Are you sure that you can add a property to a json type variable if your json object lacks of that property? I mean: What if you first parse the json variable of json type to a normal object, then add new property, and finally stringify to json type again for body assigning purposes?
var json = JSON.parse(apim.getvariable('message.body')); //convert to normal object
json.platform = 'Powered by IBM API Connect'; //add new property
apim.setvariable('message.body', JSON.stringify(json)); //convert to json again before setting as body value
You need to get the context in some determined format, and in this function do your logic. For example if your message is in json you need to do:
apim.readInputAsJSON(function (error, json) {
if (error)
{
// handle error
apim.error('MyError', 500, 'Internal Error', 'Some error message');
}
else
{
//APIC: get the payload
var json = apim.getvariable('message.body');
//console.error("json %s", JSON.stringify(json));
if(json){
//same: code to inject new attribute
json.platform = 'Powered by IBM API Connect';
//APIC: set the payload
//message.body = json;
apim.setvariable('message.body', json);
}
}
});
Reference:
IBM Reference
You have the message.body empty, put a invoke/proxy policy before your gateway/javascript policy for example.

Parse a timestamp response file (tsr) using javascript

This code is written in python:
from asn1crypto import tsp, cms, util
response_file = open('timestamp-response.tsr','rb')
response = tsp.TimeStampResp.load(response_file.read())
token = response['time_stamp_token']
signed_data = token['content']
encap_content_info = signed_data['encap_content_info']
tst_info = encap_content_info['content'].parsed
signer_infos = signed_data['signer_infos']
signer_info = signer_infos[0]
signed_attrs = signer_info['signed_attrs']
signature = signer_info['signature']
I can't find way to perform the same action using javascript even the api of the libraries looks the same.
Helpful links:
https://kjur.github.io/jsrsasign/api/symbols/KJUR.asn1.tsp.TimeStampResp.html
https://github.com/wbond/asn1crypto/blob/master/asn1crypto/tsp.py
I am not aware of any ready-to-use library but I believe it should be possible to use ASN1.js to parse TimeStampResp structure with definitions from RFC3161 and extract the data you need.
Parsing DER encoded structure when you have its ASN.1 definition is the same thing as parsing XML structure when you have its XSD definition but it will probably take more time until you get familiar with ASN.1 stuff.
You could try pkijs. I did not try it on timestamps (only x509 certificates) but it seems this library does support it. It uses asn1js under the cover.
Time-stamping request:
Parsing internal values
Getting/setting any internal values
Creation of a new Time-stamping request "from scratch"
Validation of Time-stamping request signature
Time-stamping response:
Parsing internal values
Getting/setting any internal values
Creation of a new Time-stamping response "from scratch"
Validation of Time-stamping response signature

Parse serialized Laravel cache data with Javascript

I'm using Laravel's cache feature to store keys in Redis. The key is stored as an array which Laravel's cache automatically serializes and unserializes into something like this:
"s:18:\"[\"bob\",\"dave\"]\";"
In PHP Laravel handles the parsing, but I need to access the data from Javascript. I am using the ioredis package in node. Everything works fine except for unserializing the data.
var Redis = require('ioredis');
var rediscache = new Redis();
rediscache.get("mykey", function (err, result) {
//Attempt to parse?
result = JSON.parse(result);
}
The key is fetched correctly, but is stuck as a string. I tried JSON.parse but this throws an error, I suppose because the format is wrong.
Unexpected token s at Object.parse (native)
How can it be correctly unserialised? I ideally want to get it as a Javascript array so a value can be altered, then re-serialised and saved back to Redis.
Many thanks.
What you have is a serialized string which contains a JSON string.
You can use a library if you don't want to write it yourself: https://github.com/naholyr/js-php-unserialize
After that, you'll have a JSON string, which you can then parse.

Is it possible to post an array with $http.post?

I'm trying to save an json array to service in back-end via $http.post but I always get 400 Bad Request. I have googled all around and there's not a clear answer to be found.
My questions are follows:
1. Is it possible to post json array via $http.post?
2. If yes, how it is done?
3. If no, what other alternatives there would be to save json array with such aim?
To make this even more clear, I'm going to add some of my codes below which are necessary.
At Front-end
SavingsService
createBatchSavings: function(savingsBatch){
return $http.post('/finance/savings/create/batchsavings', savingsBatch).success(function(data){
return data;
});
}
Above function gets it's savingsBatch parameter properly. savingsBatch is json array.
At Back-end
SavingServiceImpl
#Component
#Path("/savings")
#Produces("application/json")
public class SavingsServiceImpl implements SavingsService {
#Autowired
FinanceEntityDao financeDao;
#POST
#Path("/create")
public FinanceEntity createSaving(FinanceEntity financeEntity) {
financeEntity.setType(FinanceType.SAVING);
financeEntity.setDateAdded(new Date());
return financeDao.save(financeEntity);
}
#POST
#Path("/create/batchsavings")
public List<FinanceEntity> createBatchSavings(List<FinanceEntity> savingsBatch) {
if(savingsBatch.size() > 0){
return financeDao.massSave(savingsBatch);
}
else {
throw new NullPointerException("Saving batch was null!");
}
}
}
I have also examined the header values. Request headers is having proper values but Response headers content-length is always zero.
Yes its absolutely possible to post an array data and the code you wrote at client side to post data is correct.
The status code 400 you are getting must be due to problem at your server side code. I see a method createBatchSavings in your server side code but your URL at client side is lower case, batchsavings.
This is just an hint. You need to add more information about server side code.
This problem is finally solved. There were two problems in this implementation. First one in front-end and second in back-end.
Front-end
First problem was that I tried to post json array straightly to Java service class, which won't work, because it must be converted into proper string json array. Code to send the json array from controller to service is something like this:
$scope.createBatchSavings = function(batchSavings){
return SavingsService.createBatchSavings(batchSavings).success(function(data){
swal("Saving batch saved!", "Saving batch was saved successfully!", "success");
$scope.savingsBatch = [];
});
}
Here batchSavings is json array which content-type in header was application/json. This must be stringified and thus above method must be written like below in order to pass proper json array to back-end service:
$scope.createBatchSavings = function(batchSavings){
return SavingsService.createBatchSavings(JSON.stringify(batchSavings)).success(function(data){
swal("Saving batch saved!", "Saving batch was saved successfully!", "success");
$scope.savingsBatch = [];
});
}
Back-end
Secondly this stringified array must be deserialized in the back-end. Previously the connection between front-end service and back-end service didn't even work because of passing inappropriate json array. So the connection was fixed by converting the json array into proper one.
In order for back-end service to work I had to change the parameter type from List<FinanceEntity> into String. Also I had to choose deserialization "machine". In my case I chose Gson. Thus below method:
#POST
#Path("/create/batchsavings")
public List<FinanceEntity> createBatchSavings(List<FinanceEntity> savingsBatch) {
if(savingsBatch.size() > 0){
return financeDao.massSave(savingsBatch);
}
else {
throw new NullPointerException("Saving batch was null!");
}
}
becomes:
#POST
#Path("/create/batchsavings")
public List<FinanceEntity> createBatchSavings(String savingsBatch) {
Gson gson = new Gson();
Type collectionType = new TypeToken<List<FinanceEntity>>(){}.getType();
List<FinanceEntity> savingsList = gson.fromJson(savingsBatch, collectionType);
if(savingsList.size() > 0){
return financeDao.massSave(savingsList);
}
else {
throw new NullPointerException("Saving batch was null!");
}
}
Now this whole thing works.
Just as a notification, if you have any dates you must format them into proper format because otherwise you will encounter Unparsable date problem in Java.
questions are follows:
Is it possible to post json array via $http.post? yes
If yes, how it is done?
$http({ method:'POST', url:'api/data', data:item array})
If no, what other alternatives there would be to save json array with such aim?
It is possible.

Categories

Resources