• # [aiohttp|flask|bottle|pyramid] + hapic + [marshmallow|serpyco]

    Posté par (site web personnel, Mastodon) . En réponse au journal Python pour la rentrée 2019 - Hors Série - Python revient dans la course face à Node.js. Évalué à 5.

    Hello,

    A algoo, on travaille à mort en python (on fait du python en backend, du JS en front) et on a des contraintes variées selon les projets. Le problème récurrent : développer des API REST (mais pas que) et qu'elles soient vraiment auto-documentées.

    Du coup on a développé hapic qui interface un framework web classique + un (ou des) lib de sérialisation et validation (marshmallow, serpyco) et génère la doc au format OpenAPI et peut aussi la servir avec une ligne de code supplémentaire.

    Concrètement :

    • on utilise pyramid+hapic+marshmallow sur tracim - la documentation est auto-générée par introspection au démarrage du serveur,
    • on utilise aiohttp+hapic+serpyco sur un projet client (contexte embarqué, besoin de performance et d'optimisation de l'utilisation du CPU et des entrées-sorties)

    Serpyco, c'est un collègue à nous qui le développe c'est un serialiser très rapide qui est dévelopé en python et cython.

    Hapic est pas hyper bien documenté, mais ça fait vraiment bien le job, et en plus ça permet de séparer le code source lié aux API et le code purement métier (exemple : la gestion des cas d'erreurs peut se traiter sous forme de décorateur, donc le code métier implémente le cas nominal et n'est pas pollué par des if/elif/else pour gérer les cas d'erreur).

    Un petit exemple de code extrait du code source tracim :

    • handle_exception intercepte des exceptions et génère une erreur JSON avec le code HTTP demandé
    • input_path, input_body, output_body serialisent et valident les structures
    • with_api_doc active l'introspection et la génération de la documentation
    • le code que l'on écrit ne manipule que des objets/classes python, on ne mélange plus d'intelligence HTTP ou JSON dans le code.
     @hapic.with_api_doc(tags=[SWAGGER_TAG__CONTENT_HTML_DOCUMENT_ENDPOINTS])
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
     @hapic.handle_exception(ContentFilenameAlreadyUsedInFolder, HTTPStatus.BAD_REQUEST)
     @check_right(is_contributor)
     @check_right(is_html_document_content)
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
     @hapic.input_body(TextBasedContentModifySchema())
     @hapic.output_body(TextBasedContentSchema())
     def update_html_document(
     self, context, request: TracimRequest, hapic_data=None
     ) -> ContentInContext:
     """
     update_html_document
     """
     app_config = request.registry.settings["CFG"] # type: CFG
     api = ContentApi(
     show_archived=True,
     show_deleted=True,
     current_user=request.current_user,
     session=request.dbsession,
     config=app_config,
     )
     content = api.get_one(hapic_data.path.content_id, content_type=content_type_list.Any_SLUG)
     with new_revision(session=request.dbsession, tm=transaction.manager, content=content):
     api.update_content(
     item=content,
     new_label=hapic_data.body.label,
     new_content=hapic_data.body.raw_content,
     )
     api.save(content)
     api.execute_update_content_actions(content)
     return api.get_content_in_context(content)
    

    #tracim pour la collaboration d'équipe __ #galae pour la messagerie email __ dirigeant @ algoo