-
-
Notifications
You must be signed in to change notification settings - Fork 664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
typer-web to run typer cli as a web server (like click-web did) #433
Comments
This would be a great feature to have, or alternatively some official guidance on how to use typer and fastapi at the same time (they are siblings, but do they get along?) |
This is what Hug does, which the FastAPI documentation mentions. Hug supports using the same function for both a Web API and a CLI (the following is from their docs): """An example of writing an API to scrape hacker news once, and then enabling usage everywhere"""
import hug
import requests
@hug.local()
@hug.cli()
@hug.get()
def top_post(section: hug.types.one_of(('news', 'newest', 'show'))='news'):
"""Returns the top post from the provided section"""
content = requests.get('https://news.ycombinator.com/{0}'.format(section)).content
text = content.decode('utf-8')
return text.split('<tr class=\'athing\'>')[1].split("<a href")[1].split(">")[1].split("<")[0] So, the question is really, can you do this with Typer and FastAPI? I think yes: from typer import Typer
from fastapi import FastAPI
cli_app = Typer()
webapp = FastAPI()
@webapp.get("/hello/{name}")
@cli_app.command()
def hello(name: str):
print(f"Hello {name}")
@webapp.get("/goodbye/{name}")
@cli_app.command()
def goodbye(name: str, formal: bool = False):
if formal:
print(f"Goodbye Ms. {name}. Have a good day.")
else:
print(f"Bye {name}!")
if __name__ == "__main__":
cli_app() There are two ways to use this file, which let's say is called
|
Since the type annotations contain most of the business logic, not the decorators, even a pretty complicated Typer or FastAPI configuration should work with minimal repeated logic; a few exceptions of course, like if both the FastAPI endpoint and Typer command had to be deprecated, that would have be be specified in both decorators. To ensure there is really a single source of truth for every shared behavior of these two interfaces, someone would need to write a single class that handles both. The single class - Minimal working example of getting around that issue: from typer import Typer
from fastapi import FastAPI
class HybridAPI(FastAPI):
def __init__(self, *args, typer_args=[], typer_kwargs={}, **kwargs):
self.cli_app = Typer(*typer_args, **typer_kwargs)
super().__init__(*args, **kwargs)
def get(self, *args, typer_args=[], typer_kwargs={}, **kwargs):
fastAPIGet = super().get(*args, **kwargs)
cliCommand = self.cli_app.command(*typer_args, **typer_kwargs)
return lambda func: fastAPIGet(cliCommand(func))
app = HybridAPI()
@app.get("/hello/{name}")
def hello(name: str):
print(f"Hello {name}")
@app.get("/goodbye/{name}")
def goodbye(name: str, formal: bool = False):
if formal:
print(f"Goodbye Ms. {name}. Have a good day.")
else:
print(f"Bye {name}!")
if __name__ == "__main__":
app.cli_app() All Typer and FastAPI functionality works. Of course, this only implements To be clear I think this is a bad idea, but it was interesting to think about! Using two decorators, with some repeated information between them, is a small price to pay for defining business logic once. |
Typer- and FastAPI-specific type annotations should work just fine together: import typer
import fastapi
...
@app.get('/test')
def test(
boolparam: Annotated[bool, typer.Option(prompt="Are you sure?"), fastapi.Body()],
):
... |
For all of the people that stumbles on this issue. Take your Typer() instance and do the following commands.py import typer
typer_app = typer.Typer() main.py from click_web import create_click_web_app
import commands
import typer
typer_app = typer.Typer()
cmd = typer.main.get_command(commands.typer_app)
cmd.name = "cli"
app = create_click_web_app(commands, cmd) start.sh export FLASK_ENV=development
export FLASK_APP=app.py
flask run |
First Check
Commit to Help
Example Code
Description
Is it possible to create a typer-web module, which supports both the typer cli mode and the fastapi server mode? Click-web project https://github.com/fredrik-corneliusson/click-web can be used to generate a web app for click cli in a very simple way. It'd be great if typer can provide such a tool that supports both cli mode and web-server mode transparently.
Wanted Solution
As the description.
Wanted Code
NA
Alternatives
No response
Operating System
Linux
Operating System Details
No response
Typer Version
0.6.1
Python Version
3.7
Additional Context
No response
The text was updated successfully, but these errors were encountered: