=====
Usage
=====

First, you have to create a project with ``zemfrog``::

    $ zemfrog create frog


Project Layouts
---------------

The application structure is as follows::

    frog (root directory)
    ├── apis
    ├── commands
    ├── extensions
    ├── middlewares
    ├── models
    ├── tasks
    ├── static
    ├── templates
    ├── templates/emails
    ├── config.py
    ├── Procfile
    ├── README.rst
    ├── requirements.txt
    └── wsgi.py

* ``apis`` - This directory is for all REST API resources.
* ``commands`` - This directory is for the commands that will be registered in the flask command.
* ``extensions`` - This directory is for a list of flask extensions.
* ``handlers`` - This directory is for error handlers.
* ``middlewares`` - This directory is a list of middleware.
* ``models`` - This directory is for a list of sqlalchemy ORM models.
* ``tasks`` - This directory is for the celery task list.
* ``static`` - Static files.
* ``templates`` - Templates folder.
* ``templates/emails`` - This directory is for the list of email templates.
* ``config.py`` - Flask application configuration file.
* ``Procfile`` - Configuration file for deploying on heroku.
* ``README.rst`` - A short description of how to run zemfrog applications.
* ``requirements.txt`` - List of application dependencies.
* ``wsgi.py`` - Flask application here.

Assume if you already installed virtualenv and go run the application::

    $ cd frog
    $ virtualenv venv
    $ source venv/bin/activate
    $ pip install -r requirements.txt
    $ flask run


Configuration
-------------

There are several configurations in the zemfrog application, including:

* ``EXTENSIONS`` - List your flask extensions here.
* ``COMMANDS`` - List your commands here.
* ``BLUEPRINTS`` - List your blueprint here.
* ``ERROR_HANDLERS`` - List of error handlers.
* ``MIDDLEWARES`` - List of middleware here.
* ``APIS`` - List your REST API resources here.
* ``API_DOCS`` - Configuration for automation creates REST API documentation using ``flask-smorest``. Default value is ``True``.
* ``CREATE_DB`` - Configuration for automation creates tables of all models. Default value is ``True``, but I will remove this configuration in the future.
* ``API_PREFIX`` - URL prefix for all endpoints in the ``apis`` directory.
* ``API_SECURITY_DEFINITIONS`` - Follow this https://swagger.io/docs/specification/authentication/.
* ``API_SECURITY_PARAMS`` - Follow this https://swagger.io/docs/specification/authentication/
* ``API_SPEC_OPTIONS`` - See here https://flask-smorest.readthedocs.io/en/latest/openapi.html#populate-the-root-document-object
* ``APPS`` - List of sub applications.
* ``TASKS`` - Celery task list.
* ``STATICFILES`` - List of static files to serve.

Yep! that's all the configuration for the zemfrog application.
However, you can also add configurations for celery and other flask extensions in config.py :)


Routes
------

.. note::

    The route format specification is ``(url, view, methods)``.

Example::

    # urls.py

    routes = [
        ('/', views.index, ['GET']),
    ]

Commands
--------

In the flask application there is a feature to add "own commands" to flask commands. However, these are not automatically added by flask.
Don't worry, this behavior will be handled by zemfrog automatically.

Let's create a boilerplate command::

    $ flask command new foo

Now you have ``foo.py`` in the commands directory and you will see the ``command`` variable in the file ``foo.py``.
This variable will be imported and added to the flask command by zemfrog automatically.

Then add a command to the ``COMMANDS`` configuration in config.py::

    COMMANDS = ['foo']

Now you can see the command foo is registered in the application::

    $ flask foo


Error Handling
--------------

In zemfrog you can handle errors easily, you just need to make a boilerplate handler. Like this::

    $ flask handler new not_found

And in the ``handlers/not_found.py`` module there is a ``handler`` function which zemfrog will import automatically.

Now register to the ``ERROR_HANDLERS`` configuration. Like this::

    ERROR_HANDLERS = {
        404: "not_found"
    }

.. note::

    The format of the error handler is ``{code_or_exception: "error handler"}``


Multiple Static Files
---------------------

You can add more static files to serve via the ``STATICFILES`` configuration, like this::

    STATICFILES = [
        ("/assets", "assets", "assets")
    ]

Static file format values ​​are (``path``, ``endpoint``, ``static_folder``, ``static_host``).

.. note::

    the ``static_host`` value is optional


Background Tasks
----------------

In zemfrog, it is integrated with Celery for background tasks.
So you need to understand about celery. See here https://docs.celeryproject.org/en/stable/getting-started/introduction.html for more details.

And how do I make a background task?

All background tasks are in the ``tasks`` directory of the project layouts.
And in the ``tasks`` directory, a sample background task is also available.

.. code-block:: python

    from zemfrog.globals import celery
    from zemfrog.globals import mail


    @celery.task
    def send_email(*args, **kwds):
        mail.send_message(*args, **kwds)


.. note::
    If you want to create a background task, you have to use the ``celery`` app from the ``zemfrog.globals``.
    Like the sample above.


Blueprints
----------

Make a boilerplate blueprint::

    $ flask blueprint new account

The blueprint structure will look like this::

    account
    ├── __init__.py
    ├── routes.py
    ├── urls.py
    └── views.py

* ``routes.py`` - Your blueprint is here.
* ``urls.py``   - All your endpoints are here.
* ``views.py``  - All your view functions here.

Let's create 2 view functions::

    # account/views.py

    def login():
        return "login"

    def logout():
        return "logout"

Register the view function to the blueprint, otherwise your view function will not be in the blueprint.

.. code-block:: python

    # account/urls.py

    routes = [
        ('/login', views.login, ['POST']),
        ('/logout', views.logout, ['POST'])
    ]

Now all views will be listed on the blueprint. However, you need to register your blueprints in the flask app.
Add your blueprint name to the ``BLUEPRINTS`` configuration in config.py::

    BLUEPRINTS = ['account']

And, now you can see the blueprint ``account`` has been registered in the flask application::

    $ flask routes


Middlewares
-----------

In this section, I will explain how easy it is to create middleware.
Let's start by creating the boilerplate middleware::

    $ flask middleware new auth

The above command will create an ``auth.py`` file to the ``middlewares`` directory and in the ``auth.py`` file there is a function ``init_middleware``.
This function is to register your middleware in the flask application.

And register your middleware to config file::

    MIDDLEWARES = ["auth"]

API
---

zemfrog is specially designed for building REST APIs quickly.
In zemfrog you can create a basic CRUD or just boilerplate API.

All API resources are located in the ``apis`` directory.

Let's start by creating an API resource::

    $ flask api new article

Now you have the article API resource::

    apis
    ├── article.py
    ├── __init__.py

The following are the variables in the API article (on the last line):

* ``tag`` - API name (which is the name of the blueprint).
* ``description`` - API description.
* ``url_prefix`` - URL prefix for the API resource.
* ``routes`` - All of your API endpoints.

Now, we will create a basic REST API.

.. note::

    You cannot create a REST API if you don't have an ORM model for that API.

Let's create a ``Product`` model.

Change the file ``models/__init__.py`` to be like this::

    from zemfrog.globals import db
    from sqlalchemy import Column, String, Integer

    class Product(db.Model):
        id = Column(Integer, primary_key=True)
        name = Column(String)

.. warning::

    Keep in mind, you have to create an API with the same name as your ORM model.
    And don't forget to add the ``--crud`` option.

And we can create a REST API::

    $ flask api new Product --crud

This REST API will not work if you haven't added it to the ``APIS`` config.
Let's add it to the config::

    APIS = ['Product']


Multiple Application
--------------------

In zemfrog you can easily create sub applications.

Let's start by creating a sub application as below::

    $ flask app new sub

And add your sub-application to the ``APPS`` configuration in the config.py file::

    APPS = ["sub"]

You can also add sub-applications using a dictionary::

    APPS = [
        {
            "name": "sub", # Your application name.
            "path": "/sub-app", # Application URL prefix. (optional)
            "help": "Sub app command" # Help messages for your app commands. (optional)
        }
    ]

To manage nested applications you just need to use the ``sub`` command::

    $ flask sub
