Closed LouisZou closed 8 years ago
Hi, pyswagger can only produce request with content-type: application/json, an modification for content-type other than json is still ongoing here.
One thing needs to be clarified before going further: is "application/my+json" a special json, or just a special name in your service for json?
Thanks mission-liao, the type "application/my+json" is a special type in our restful service and the server will check the type of request.
I think I can do some customization for this issue by change the code "class SwaggerRequest(object)".
I think I can read the real type from the json file and I need only set this type into header and then send request to my restful api server.
The problem is, the way to handle content type in pyswagger is static, and can't be pluggable, which means it can't things like "application/my+json".
A fix would be required for pyswagger to be extensible, One more thing to make sure @LouisZou , so "application/my+json" is actually a different name for json, which is nothing different from how we encode swagger primitives to json?
Sure, the "application/my+json" is also a json type but special name in my restful server. I can also deal with it as a normal json format.
OK, I think that use case should be covered by that PR.
Hi mission-liao, I found this issue is fixed with issue#49. And now how can I use it with the newest pyswagger? just like: req, resp = op(user='Tom') req.mime = ("myjson", "myjson") resp = client.request((req, resp),) -- and then analyze the resp to get response from http server. is this correct?
And sorry for I don't understand the sentence req, resp = op(user='Tom') does this sentence will execute the method op? can I use it like "req, resp=op()"? because I will decide how to set the parameter later such as, op(body=mybody) or op(user='Tom'). in fact, my read code will be: client.request(eval("op(" + tagUser +"='Tom'")) -- tagUser is a variable whose value is "user".
The design of pyswagger to perform an Operation Object is to return a tuple of (SwaggerReqeust, SwaggerResponse). If you just use it in this form:
client.request(op(user="Tom"))
The tuple of SwaggerRequest, SwaggerResponse is silently pass to client.request. If you need more customization, you need to pass them in this form
req, resp = op(user="Tom")
req.mime .... # any customization
resp.xxxx
client.request((req, resp,)) # pass them as a tuple
The mime part is still under review, and would be merged to next release.
Thanks mission-liao. for the req, resp, can I consider them as the meaning of the words. Assume now my restful server need content-type is myjon1 in request and accept is myjon2 in response, so I will write: req.mime("myjon1","") resp.mime("","myjon2") it this correct?
or: req.mime("myjson1","myjson2")
No, you can refer to that PR for more info.
req.produce(...)
req.consume(...)
This PR is merged in latest build.
HI mission, I used the newest revision 0.8.18, when I call the request, it failed with the following message : Could not find codec for "myjson", => it is in the function marshall.
I noticed the following code:
class MimeCodec:
def __init__(self):
self._codecs = {}
self.register('text/plain', PlainCodec())
jsonCodec = JsonCodec()
self.register('application/json', jsonCodec)
self.register('text/json', jsonCodec)
I have a new mime type in my definition file and I want to set this type to header and then send request to server. for my curl command ,it like this: curl --header {"Content-Type":"myjson", "Accept":"myjson"}
does need this mime to be registered just like above code?
Addition: in the revision 0.8.17, I can fix the code as the following and then I can use "my+json" as content-type and Accept in the header and then send request .
so I also think pyswagger can read the real mime-type for each operation from my definition file and then send request with them.
How can I realize this simply?
Hi, the guy helped to implement that feature also provide a guide to register a customized codec. If that one doesn't solve your problem, please help to provide more details about what you want to do.
Hi mission-liao, I write my program according to the guide code but the above error occurs. And now I add the following code ,it can work. in site-packages/pyswagger/primitives/codec.py 6 class MimeCodec: 7 def init(self): ... 13 self.register('application/my01+json', jsonCodec) 14 self.register('application/my02+json', jsonCodec)
so the method marshal know my mime type and then the request work well.
but about this issue. I think I don't need to marshal and unmashal my data according to my mime type. I only need to set the Content-Type and Accept in Header of Request. And I think these types should be read from definition file by pyswagger because I specify the consume and produce in my operation.
what do you think?
Hi, I will write a test sample for your case tomorrow. Besides that, I can't get your point for:
don't need to marshal and unmashal my data according to my mime type
I can't get your point, any python primitives (dict, list) should be marshalled to some representative form in string when sending to servers.
works with sample code:
from pyswagger import SwaggerApp
from pyswagger.primitives import MimeCodec
from pyswagger.primitives.codec import JsonCodec
# init codecs
codecs = MimeCodec()
jc = JsonCodec()
codecs.register('application/my01+json', jc)
codecs.register('application/my02+json', jc)
# init SwaggerApp with customized primitive factory
app = SwaggerApp.load('./swagger.json', mime_codec=codecs)
app.prepare()
op = app.s('/t').get
# make sure my01xxxxx in that 'op'
print op._mime_codec._codecs.keys() # expected ['application/my02+json', 'application/my01+json', 'application/json', 'text/plain', 'text/json']
with sample spec
{
"swagger":"2.0",
"host":"http://test.com",
"basePath":"/v1",
"paths":{
"/t":{
"get":{
"parameters":[
{
"in":"body",
"name":"body",
"schema":{
"$ref":"#/definitions/MyRequest"
}
}
],
"responses":{
"default":{
"description":"void"
}
}
}
}
},
"definitions":{
"MyRequest":{
"properties":{
"units":{
"additionalProperties":{
"format":"int32",
"type":"integer"
}
},
"username":{
"type":"string"
}
}
}
}
}
Thanks mission. before I add the register sentence in the codec.py, it work well. that's meaning user can also call this method register in self's code.
I will fix my code.
hi mission, sorry for so late to test the code. now i used the register code like above and I can print myjson1/2 with the code but the request failed with the exception: Exception:unbound method marshal() must be called with JsonCodec instance as first argument (got Model instance instead)
And in my source code 30 codecs.register('application/json',JsonCodec) 31 codecs.register('application/myjson2', JsonCodec) line 30 is ok but line 31 failed with the above exception.
Addition, If I add the register code in the file primitives/codec.py: 6 class MimeCodec: 7 def init(self): ... 13 self.register('application/myjson01', jsonCodec) 14 self.register('application/myjson02', jsonCodec)
it work well
Could you paste the full trace of that exception?
Hi mission, Here is the full exception. File "/scratch/shuluo/swagger/swagger_sdk/compute-controlplane/virtualenv/lib/python2.6/site-packages/pyswagger/io.py", line 75, in _prepare_body return content_type, self.__op._mime_codec.marshal(content_type, body, _type=_type, _format=_format, name=name) File "/scratch/shuluo/swagger/swagger_sdk/compute-controlplane/virtualenv/lib/python2.6/site-packages/pyswagger/primitives/codec.py", line 29, in marshal return codec.marshal(value, **kwargs) TypeError: unbound method marshal() must be called with JsonCodec instance as first argument (got Model instance instead)
It seems like there is something in this line: app = SwaggerApp.load('./swagger.json', mime_codec=codecs)
I guess some code in my sample is wrong, and would only failed when something really loaded.....
"""
should be instance, not class
"""
codecs.register('application/json',JsonCodec) # Wrong
codecs.register('application/myjson2', JsonCodec) # Wrong
"""
should work in this way
"""
jsonC = JsonCodec()
codecs.register('application/json',jsonC)
codecs.register('application/myjson2', jsonC)
Sorry for my wrong sample.
Hi, mission, it works now. Thanks very much!
It should be fine to close it now, please feel free to reopen it when things go wrong.
I call the request and found the log like following: pyswagger.core - INFO - request.header: {'Accept': 'application/json'}
But for my restful API, need the special accept and content-type such as "application/my+json", so the request failed because of error media type. how to send the correct type for my request.