2

=================================

Note: Using @Larme's trick to print out debugDescription of the request, and comparing with my working curl request, I was able to figure out the dumb bugs I made. 1. In the server request handler, I return a serializerError when something unrecognized, pretty confusing. 2. I made a stupid mistake in my request from swift, putting "GET_RECIPES" instead of "GET_RECIPE".

================================

I have a http service implemented with django rest framework, when I send requests via swift/alamofire, it cannot get the correct json response. However, requests sent via curl and postman get the correct json response. So I am confused what where is the issue, the django service side or swift request side?

  1. I have tried using .responseString instead of .responseJSON in swift to print out the resposne, but still the data is not in the response, basically the error occurs when the request reaches the server side.
  2. From django server side, the error reads "TypeError: Object of type 'property' is not JSON serializable". OK it seems the issue is from django side...
  3. But from curl and postman, I can get the json response without an issue, with the response header containing "Content-Type": "application/json", and for the django side everything is also OK. Then does this mean the django server can handle json response and it should be the issue of the swift request??

Code in swift,

let parameters: [String: Any] = [
    "type": "GET_RECIPE",
    "details": ["ingredients" : ["egg", "bread"]]
]
let headers = ["Content-Type": "application/json"]
Alamofire.request(url, mothod: .post, parameters: parameters, 
                  headers: headers, encoding: JSONEncoding.default)
                .responseJSON {response in
                if let data = response.result.value {
                    print(data)
                }
}

Code of the request handler

class RecipesSerilizer(serializers.ModelSerializer):
    class Meta:
        model = Recipes
        fields = ('id', 'url', 'author', 'category', 'title', 'description',
                  'instructions', 'tip', 'raw', 'score')

def get_recipes_given_ingredients(data):
    logger.info('Get recipes for {}'.format(data.get('details')))
    details = data.get('details')
    ingredients = details.get('ingredients')
    logger.info('GET_RECIPE for ingredients {}'.format(ingredients))
    recipes = queries.get_recipe_recommendation_given_ingredients(ingredients)
    serializer = RecipesSerilizer(recipes, many=True)
    return Response(serializer.data)

Trace stack from the server side:

Internal Server Error: /get-recipes/
Traceback (most recent call last):
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\django\core\handlers\base.py", line 145, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\django\core\handlers\base.py", line 143, in _get_response
    response = response.render()
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\django\template\response.py", line 106, in render
    self.content = self.rendered_content
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\response.py", line 72, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\renderers.py", line 733, in render
    context = self.get_context(data, accepted_media_type, renderer_context)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\renderers.py", line 688, in get_context
    'content': self.get_content(renderer, data, accepted_media_type, renderer_context),
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\renderers.py", line 424, in get_content
    content = renderer.render(data, accepted_media_type, renderer_context)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\renderers.py", line 107, in render
    allow_nan=not self.strict, separators=separators
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\utils\json.py", line 28, in dumps
    return json.dumps(*args, **kwargs)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\json\__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\json\encoder.py", line 201, in encode
    chunks = list(chunks)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\json\encoder.py", line 437, in _iterencode
    o = _default(o)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\site-packages\rest_framework\utils\encoders.py", line 68, in default
    return super(JSONEncoder, self).default(obj)
  File "C:\Users\Yuanjun\Anaconda2\envs\online_bid\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'property' is not JSON serializable
[14/May/2019 08:29:32] "POST /get-recipes/ HTTP/1.1" 500 124585

  • I've seen this before where it depended on whether or not there was a trailing slash on the url. It'd be a quick test to see if this resolves your issue. – Don May 14 '19 at 02:21
  • @Don Thanks for the suggestion. I do have the trailing slash on the url. Removing the trailing slash does raise a 500 code in the http response, but it's a different one with runtime Error at django side. – Yuanjun Zhou May 14 '19 at 02:47
  • Sorry, I can't be of more help. My backend developer never explained why it mattered. Hopefully, someone will come along who knows. – Don May 14 '19 at 02:55
  • 1
    Can you show the postman request details? – Kamran May 14 '19 at 06:13
  • You have a curl working? Then instead of doing `Alamofire.request(...).responseJSON{...}`, do `let request = Alamofire.request(...); print(request.debugDescription); request.responseJSON{...}`, compare the output. I explained there (https://stackoverflow.com/questions/53637437/alamofire-with-d/53637821#53637821) the trick – Larme May 14 '19 at 12:41
  • @Larme Thank you very much for sharing this! It is a great way to debug that I did not know. – Yuanjun Zhou May 15 '19 at 00:49
  • **_from curl and postman, I can get the json response without an issue_** Why don't you show the curl command or the postman settings? Your code is sending something different than the curl or postman, but no readers cannot say where. – OOPer May 15 '19 at 01:17

2 Answers2

0

i think your problem is that you are trying to send a post to a get request.

try changing your alamofire request as follows:

let parameters: [String: Any] = [
    "type": "GET_RECIPE",
    "details": ["ingredients" : ["egg", "bread"]]
]
let headers = ["Content-Type": "application/json"]
Alamofire.request(url, mothod: .get, parameters: parameters, 
                  headers: headers, encoding: JSONEncoding.default)
                .responseJSON {response in
                if let data = response.result.value {
                    print(data)
                }
}
Mr Spring
  • 533
  • 8
  • 17
  • No, I implemented the django post handler, although I admit that the name of the end point is a bit misleading. I can curl or postman to get the response using post request. – Yuanjun Zhou May 14 '19 at 12:28
0

Probably the server crashes while handling your request or cannot find the given URL(because of the trailing slash). text/html is usually returned if the server has crashed while running in DEBUG mode. This is how it shows the crash reason in a pretty way with the stack trace.

It is really hard to tell what happened in your case. It would be great if you provided the stack trace of the error.

  • You are right, the server is running in DEBUG mode. It is not due to trailing slash. I edit the original question to post the trace stack from the server side. `TypeError: Object of type 'property' is not JSON serializable` shows up, but when using curl or postman to send the same post request, it works just fine. This confuses me. – Yuanjun Zhou May 14 '19 at 12:32
  • @YuanjunZhou seems like this statement returns wrong and unexpected data `recipes = queries.get_recipe_recommendation_given_ingredients(ingredients)`. Could you catch its result? Also, I would suggest using class-based views like `APIView` from `rest_framework`. – Emir Amanbekov May 15 '19 at 03:12