def refToClassName(ref, needSimple=False): ''' convert a ref string to java class name ''' try: refType, refName = util.parseSwaggerRef(ref) except RuntimeError: print('"%s" is not a swagger reference' % ref) return ref prefix = '' if refType == 'definitions': # models prefix = modelPackage location = refName.split('/') result = prefix if len(location) > 0: location[-1] = util.camelize(location[-1]) for l in location: result += '.' + l # simple class name if needSimple: result = result.split('.')[-1] return result
def renderApi(swagger, templatePath): if not isTemplatePathValid(templatePath): return with open(templatePath) as f: template = f.read() ''' api context { 'package': 'xxx', 'modelPackage': 'xxx', 'imports': [{'import': 'xxx'}, ...] 'classname': 'xxx', // seems that each class is created according to the 'tags''s last item 'operations': [ { 'summary': 'xxx', 'apiDescription': 'xxx', 'methodName': 'xxx', 'httpMethod': 'xxx', 'path': 'xxx', 'responseType': 'xxx', 'hasForm': true/false, 'parameters':[ { 'paramIn': 'xxx', 'inKey': 'xxx', 'paramName': 'xxx', 'paramDescription': 'xxx', 'paramType': 'xxx', 'isEnum': 'xxx', 'enumValues': [...], 'hasMore': true/false } ] } ] } ''' # get tags list first, the list item claims the api class name contexts = {} tags = set() if swagger.tags: for tag in swagger.tags: tags.add(tag.get('name')) for path in swagger.paths: for operation in path.operations: if operation.tags: tags.add(operation.tags[-1]) else: # this operation has no tags, generate one by the path. add the tag to the operation's 'tags' tag = getTagByPath(path.path) tags.add(tag) operation.tags = [tag] # now we have all tags. create blank render context for each one for tag in tags: context = {} context['package'] = apiPackage context['modelPackage'] = modelPackage context['classname'] = toApiClassName(tag) context['operations'] = [] contexts[tag] = context # fill operations for path in swagger.paths: for operation in path.operations: # tags has been filled above, won't be null tag = operation.tags[-1] context = contexts[tag] optContext = {} optContext['summary'] = operation.summary optContext['apiDescription'] = operation.description pathVar = path.path pathVar = re.sub(r'^/*(.*)', r'\1', pathVar) pathVar = re.sub(r'([^/]*)/*$', r'\1', pathVar) optContext['path'] = pathVar optContext['httpMethod'] = toFieldName(operation.method, True) optContext['methodName'] = toApiMethodName(operation.method, path.path) responseType = None for responseItem in operation.responses: if responseItem.code.startswith('2'): # try to parse response type if not responseItem.schema: responseType = 'Void' else: isArray = responseItem.schema.get('type') if isArray: items = responseItem.schema.get('items') if items: itemRef = items.get('$ref') if itemRef: responseType = toDataType('array') % refToClassName(itemRef, True) else: ref = responseItem.schema.get('$ref') responseType = refToClassName(ref, True) optContext['responseType'] = responseType parameters = [] for parameter in operation.parameters: paramSrc = None if parameter.ref: # parse the reference type, name = util.parseSwaggerRef(parameter.ref) for p in swagger.parameters: if p.key == name: paramSrc = p else: paramSrc = parameter pContext = {} # if paramter 'in' is 'formData', 'paramIn' value in Retrofit is 'Field' if paramSrc.location == 'formData': pContext['paramIn'] = 'Field' optContext['hasForm'] = True else: pContext['paramIn'] = util.camelize(paramSrc.location) # in retrofit annotations, @Body and @QueryMap(impossible in this parser) don't need a value if str(paramSrc.location).lower() != 'body': pContext['inKey'] = paramSrc.name pContext['paramName'] = toFieldName(paramSrc.name) pContext['paramDescription'] = paramSrc.description pType = None # now simply consider the schema is a json object, not an array if paramSrc.schema: ref = paramSrc.schema.get("$ref") if ref: pType = refToClassName(ref, True) else: pType = toDataType(paramSrc.type) if paramSrc.type == 'array': if paramSrc.itemRef: pType = pType % refToClassName(paramSrc.itemRef, True) elif paramSrc.itemType: pType = pType % toDataType(paramSrc.itemType, True) if paramSrc.itemEnum: pContext['isEnum'] = 'true' pContext['enumValues'] = paramSrc.itemEnum pContext['paramType'] = pType pContext['hasMore'] = True parameters.append(pContext) if len(parameters) > 0: parameters[-1]['hasMore'] = False optContext['parameters'] = parameters context['operations'].append(optContext) # now we have contexts. render each one for key in contexts: context = contexts.get(key) result = pystache.render(template, context) savePath = apiDir + '/' + context['classname'] + '.java' saveTo(savePath, result)