pyopenapi / pyswagger

An OpenAPI (fka Swagger) client & converter in python, which is type-safe, dynamic, spec-compliant.
MIT License
384 stars 88 forks source link

How to iterate all of the apis in the app.op? #66

Closed LouisZou closed 8 years ago

LouisZou commented 8 years ago

I try to get the apis with app.op.keys(), but it return "path!##!Id". I only want to get the ID.

And How can iterate all of the path and then get the supported method in it. is there a sample or guide to do this?

LouisZou commented 8 years ago

That's meaning, Now I load a json file but I don't know the real Id or path in this json. I need to get the list from our swaggerAPP.op and then test them one by one.

mission-liao commented 8 years ago

Hi, I'm curious that how could you test API without knowing their definition in advance? Even if I provide a way for you to iterate all APIs by giving you IDs, how could you test them after that step?

LouisZou commented 8 years ago

Thanks mission-liao, in my test case, the details is as the following:

  1. I have a swagger definition that include about 100 APIs.
  2. I read the file using swagerApp and then I will test them one by one.
  3. I want to use a loop to get each APIs, such as for apis in app.op.keys(). and I don't want to get them by app.op["id1...N"] envn if I know each id of them, because that I think I will write 100 lines code.
  4. I have a test data that I can write the test data according to the definition such as: Id1: get, "Tom" Id2:post, "user:Tom, Age:1"

so that I can iterate the APis (app.ops) and then test it with the test data.

LouisZou commented 8 years ago

I think I can also test them from test data, such as :

  1. read test data and get all of the Ids
  2. get op using the id just like app.op[Id]
  3. get the data for testing from the test data and then call request to get response

is this OK?

But in this way, I think if I lost some data of api in test data, I cannot test all of the Apis in definition. The purpose is testing all of the apis in definition. :)

mission-liao commented 8 years ago

I think you can write a scanner to collect all those IDs on you own, the app.op is a little bit more complicated than what you need (to be compatible with Swagger 1.2).

Here is a pseudo code(not tested) to collect all Operation objects in pyswagger, similar to what we did in pyswagger.scanner.TypeReduce:

from pyswagger import SwaggerApp
from pyswagger.scan import Scanner, Dispatcher
from pyswagger.spec.v2_0.objects import Operation

# define your scanner
class OperationCollector(object):
    class Disp(Dispatcher): pass

    def __init__(self):
        self.cached_obj = []

    @Disp.register([Operation])
    def _op(self, path, obj, _):
        self.cached_obj.append(obj)

# load your definition
app = SwaggerApp.create("path_to_your_definition")
s = Scanner(app)
coll = OperationCollector()
s.scan(root=app.root, route=[coll])

# access all Operation objects, no matter with IDs or not
for v in coll.cached_obj:
    pass
LouisZou commented 8 years ago

Thanks mission-liao. I can iterate the op list by the method above. but I don't know the op is which one (related to Id or other information) I think I can also get the list by the following method: for ops in app.op.keys(): print ops print app.op[ops] the ops is "Tag!##!Id", maybe I can analyze it and get the correct Id. or I will get the Ids from test data (data-driven test) and assure I have all of the test data according to the Ids in definition.

Thanks again for you kindly reply.

mission-liao commented 8 years ago

Hi, did you tried the scanner way?

if you need the ID of Operation, just cache them ( a modified version of previous pesudo code ):

from pyswagger import SwaggerApp
from pyswagger.scan import Scanner, Dispatcher
from pyswagger.spec.v2_0.objects import Operation

# define your scanner
class OperationCollector(object):
    class Disp(Dispatcher): pass

    def __init__(self):
        self.cached_obj = {}   # <- a dict

    @Disp.register([Operation])
    def _op(self, path, obj, _):
        self.cached_obj[obj.operationId] = obj   # cache Operation, indexed by operationId

# load your definition
app = SwaggerApp.create("path_to_your_definition")
s = Scanner(app)
coll = OperationCollector()
s.scan(root=app.root, route=[coll])

# access all Operation objects, no matter with IDs or not
for opId, op in coll.cached_obj:    #   <- should be simple enough
    pass
LouisZou commented 8 years ago

Thanks mission-liao. Yes. I have tried to use scanner just like the sample that you provided. and I can get the Ids. but for the sample code #2 , when I run it, there is a error: ValueError: too many values to unpack If I fix the line "for opId, op in coll.cached_obj:" to "for opId in coll.cached_obj:", it work well.

mission-liao commented 8 years ago

Glad those pseudo code works.

mission-liao commented 8 years ago

Close this issue for reducing monitoring effort, reopen it if anything goes wrong.