jldupont
jldupont

Reputation: 96806

protoRPC: returning dict

How does one return a dict like object through protoRPC ?

I tried using the FieldList to no avail. I only see the following field definitions:

       'IntegerField',
       'FloatField',
       'BooleanField',
       'BytesField',
       'StringField',
       'MessageField',
       'EnumField',

Upvotes: 3

Views: 2356

Answers (4)

volent
volent

Reputation: 471

It's possible to create a custom JsonField like this :

In  [1]: class JsonField(messages.StringField):
             type = dict

You can then use it as any other field :

In  [2]: class MyMessage(messages.Message):
             data = JsonField(1)

In  [3]: m = MyMessage(data={"foo": "bar"})

In  [4]: m.data
Out [4]: {'foo': 'bar'}

Upvotes: 2

Dave
Dave

Reputation: 3570

A bit involved, but I have a recipe for something quite close to a dict implementation for protorpc: https://gist.github.com/linuxluser/32d4a9c36ca0b8715ad4

It is restricted to using string-only keys and simple (not nested) values. But if your data fits in that category, this solution should work well.

The idea has 2 parts:

  1. Create a new field type MultiField that can hold an arbitrary value type.
  2. Create a dict-like type MapField that stores key-value pairs in a list of MultiField types.

You use it like so:

import messages
import mapfield

class MyMessage(messages.Message):
  some_dict = mapfield.MapField(1)


my_message = MyMessage(some_dict={"foo": 7, "bar": False, "baz": 9.2, "qux": "nog"})

It's only a start. Probably could be better. Improvements are welcomed. :)

Upvotes: 0

bossylobster
bossylobster

Reputation: 10163

There are two scenarios:

1) Your dict has a well-defined schema: This is the best use case for ProtoRPC and if possible you should try to fit it into a schema. In this case, you would use a MessageField with some Message class that matches the schema in your dictionary.

For example, instead of

{'amount': 31, 'type': 'fish', mine: False}

you could define

from protorpc import messages
class MyCatch(messages.Message):
  amount = messages.IntegerField(1)
  type = messages.StringField(2)
  mine = messages.BooleanField(3)

and then use this message definition in a field via

messages.MessageField(MyCatch, index, ...)

2) Your dict does not have a well-defined schema: In this case you can use json to dump your dictionary to a string and request ensure_ascii=True to make sure the return type is a bytes (str) object. Then you can just use a BytesField.

For example:

import json

class MyMessage(messages.Message):
   some_dict = messages.BytesField(1)

my_dict = {'amount': 31, 'type': 'fish', mine: False}
message = MyMessage(some_dict=json.dumps(my_dict, ensure_ascii=True))

The use of ensure_ascii is optional as True is the default, but this may change depending on your environment.

Instead you could use pickle to serialize your dictionary. The method pickle.dumps always outputs ASCII/binary, so by swapping out json.dumps for pickle.dumps and dropping the ensure_ascii=True, you'd have the same outcome.

Upvotes: 8

Mario Jorge Valle
Mario Jorge Valle

Reputation: 168

For the first option in the approved answer, we can add a parameter repeated=True, so we'll have a list of json as the answer. I checked about it at https://developers.google.com/appengine/docs/python/tools/protorpc/overview?hl=en#Defining_the_Response_Message

Upvotes: 1

Related Questions