Django Rest Framework- How to send data as strings - api

I want to send all the data in a response as string, like in database id is stored as integers but I want to send it as string in response.
eg: I have the response as
{
"categories": [
{
"id": 1,
"category": "xya",
"quantity": 25
}
]
}
I want it to be as:
{
"categories": [
{
"id": "1",
"category": "xya",
"quantity": "25"
}
]
}
I am using ModelSerializer to send all the fields.

Another option is to convert int to str using the to_representation method of your model serializer.
class YourSerializer(serializers.ModelSerializer):
# other fields
def to_representation(self, instance):
""" Override `to_representation` method """
repr = super().to_representation(instance)
repr['id'] = str(repr['id'])
repr['quantity'] = str(repr['quantity'])
return repr

You can explicitly define id field in your serializer to be CharField()
Like this
class YourSerializer(serializers.ModelSerializer):
# other fields
id = serializers.CharField()
class Meta:
model = SomeModel
fields = ('id', ..... other fields)

Related

Karate filtering json response

In my Karate tests (0.9.4), I have a json response like the following:
[
{
"id": "id_number_1",
"name": "name"
},
{
"id": "id_number_2",
"name": "name 2",
"nestedThing" {
"id": "another_id",
"name": object2_name"
}
},
{
"id": "id_number_3",
"name": "name 3"
}
]
Some of the objects in the response will have a nestedThing and others will not. First, I want to get rid of all the items in the list that do not have nestedThing. Second, once that's done, I want to def a list that only contains the first-level id fields. So, it would look like:
["id_number_1", "id_number_3"]
This can be done in one line:
* def ids = response.filter(x => !x.nestedThing).map(x => x.id)
Refer: https://github.com/karatelabs/karate#json-transforms
EDIT: the below works in versions 0.9.X
* def temp = karate.filter(response, function(x){ return !x.nestedThing })
* def ids = karate.map(temp, function(x){ return x.id })
* match ids == ['id_number_1', 'id_number_3']

Type mismatch during Gson deserialize json response with kotlin

I am trying to serialize the json response below, but I am unsure how to do it.
This is the Json my backend returns:
[
{
"title": "Dummy section, should not be seen",
"type": "dummy_test",
"metadata": []
},
{
"title": "Title1",
"type": "categories_products",
"metadata": [
{
"id": "1272"
}
]
},
{
"title": "Title2",
"type": "categories_products",
"metadata": [
{
"id": "996"
}
]
}
]
This is my ExploreItem class:
data class ExploreItem(
#SerializedName("metadata") val metadata: List<Metadata> = listOf(),
#SerializedName("title") val title: String = "",
#SerializedName("type") val type: String = ""
) {
enum class ExploreItemType(val value: String) {
#SerializedName("unknown")
UNKNOWN("unknown"),
#SerializedName("other_companies")
OTHER_COMPANIES("other_companies"),
#SerializedName("categories_products")
CATEGORIES_PRODUCTS("categories_products"),
#SerializedName("popular_categories")
POPULAR_CATEGORIES("popular_categories")
}
}
data class Metadata(
#SerializedName("id") val id: String = ""
)
And now I am trying to serialize it in the repository like this:
Serializer.defaultJsonParser.fromJson(response.body!!.string(),ExploreItem::class.java )
but it doesn't work because it's expecting a list of ExploreItem. How can I rewrite the serializer expression to parse it into a list?
From your error
Type mismatch. Required:List Found:ExploreItem!
Post errors is very important, Gson is telling you that it wants a List and not an object of ExploreItem.
In other words, you are telling to Gson with the call Serializer.defaultJsonParser.fromJson(response.body!!.string(),ExploreItem::class.java )
"Hey Gson, from the string I want an object ExploreItem", and Gson is telling you "Hey my friend, you string start with [ ] for sure it is a list of something and not a single object."
You need to pass in the Serializer.defaultJsonParser.fromJson(response.body!!.string(),List<ExploreItem>::class.java)
P.s: I'm not sure about the Kotlin syntax

How to create a Marshmallow SQL schema for GeoJson

I am trying to create an API using flask, SQLAlchemy, Marshmallow, PostGIS that return GeoJson FeatureCollection. I want to be able to work with any Geo Objects (Point, Polygone,...).
I tried many things but never successfully recreated the GeoJson FeatureCollection format. It is possible to force a shape to a marshmallow schema ?
This is SQLAlchemy model:
class Locations(db.Model):
__tablename__ = 'locations'
id: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
name: int = db.Column(db.String, nullable=False)
linename: str = db.Column(db.String, nullable=False)
point = db.Column(Geometry('POINT'))
This is my marshmallow schema,
class LocationsSchema(SQLAlchemyAutoSchema):
point = fields.Method('wkt_to_geojson')
def wkt_to_geojson(self, obj):
return {'type': 'Feature', 'properties': {'linename': obj.linename}, 'geometry': shapely.geometry.mapping(to_shape(obj.point))}
class Meta:
model = Locations
locations_schema = LocationsSchema(many=True, only=["point"])
This is my blueprint route:
#map_data_blueprint.route('/locations', methods=['GET'])
def all_items():
locations = Locations.query.all()
serialized = locations_schema.dump(locations)
return jsonify(serialized)
This is the json I receive from the API:
[
{
"id": 2,
"point": {
"geometry": {
"coordinates": [
6.130649,
49.609332
],
"type": "Point"
},
"properties": {
"linename": "1"
},
"type": "Feature"
}
},
{
"id": 3,
"point": {
"geometry": {
"coordinates": [
6.126288,
49.598557
],
"type": "Point"
},
"properties": {
"linename": "1"
},
"type": "Feature"
}
}]
But I am trying to get the FeatureCollection Geojson format here is an example here.
I found a solution by combining geoalchemy2.shape, shapely and geojson package. I removed the marshmallow layer for this specific API as I have not found a way with the marshmallow layer.
def parse_geojson(obj):
geo = shapely.geometry.mapping(to_shape(obj.point))
if geo:
return geojson.Feature(
id=obj.id,
geometry=geo,
properties={
"linename": obj.linename
})
#map_data_blueprint.route('/locations', methods=['GET'])
def all_items():
locations = Locations.query.all()
features = [parse_geojson(location) for location in locations]
serialized = geojson.dumps(geojson.FeatureCollection(features))
return serialized
I don't know if it is best practice to serialize the query answer in the route or not but this works.

Karate: Traverse thru a complex JSON to find a match

I am hitting an API end point and getting something like below.
{
"emp": {
"id": "123",
"firstNm": "test",
"lastNm": "last",
"dob": "200-01-01",
"gender": {
"code": "F",
"name": "Female",
"description": "Female"
},
"test1": [
{
"tes2": "F50045A3B994FB2BDF4E3D3FC906F592",
"t2": "a23",
"test3": {
"code": "432",
},
"ind": [
"ABC",
"BCD",
]
}
]
}
}
I want to match the elements in the array
"ind": [
"ABC",
"BCD",
]
I have tried the below:
Feature: test
Background:
* url BaseUrl
* configure headers = read('classpath:headers.js')
Scenario Outline: test
Given path '/path'
And param id = <id>
When method get
Then status 200
* def json = response
* def has = {ind:['#string'] }
* def indicator = { ind: '#[] has' }
* match json.member == '#[] indicator'
Examples:
| id |
| '1234' |
But observed the below exception:
expected: '#[] ind', reason: not an array or list
Can someone please help?
I am not really following your logic since indicators is not in the json response or defined variable but to get to the ind array the path is emp.test1[0].ind
if you want to match that the array has ABC and BCD you would do the following
* match response.emp.test1[0].ind == ['ABC', 'BCD']

How to access a particular set of keys in array of Json values which i get as response?

For a particular API , I get a response which is similar to the following .
[
{ "name":"Ford", "model":"Mustang" },
{ "name":"BMW", "model": "320" },
{ "name":"Fiat", "model": "500" }
]
I want to store the values for the key 'name' in a separate variable .
Please read the documentation on using JsonPath carefully: https://github.com/intuit/karate#get
Here is an example which works with your data:
* def response =
"""
[
{ "name":"Ford", "model":"Mustang" },
{ "name":"BMW", "model": "320" },
{ "name":"Fiat", "model": "500" }
]
"""
* def names = $[*].name
* match names == ['Ford', 'BMW', 'Fiat']