In my project folder I have a basic index.html file plus static files (js, css) as well as my main.py:
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi import Request
app = FastAPI()
templates = Jinja2Templates(directory="/")
app.mount("/", StaticFiles(directory="/"))
#app.get("/")
def serve_home(request: Request):
return templates.TemplateResponse("index.html", context= {"request": request})
How can I make fastapi work here? I just want my index.html and static files served on localhost.
Is it problematic not to have a static or templates folder?
Option 1: Static file mounting
It was easier than expected. Just needed to put all static files including index.html into static folder in project directory and mount static files.
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
That's it. My index.html is now available under http://localhost:8000/static/index.html.
In case it should be accessible right under http://localhost:8000/ without /static and the .html ending one needs to change two things. First it needs to be mounted on / instead of /static and an HTML flag must be set to true when mounting. So just use this line instead:
app.mount("/", StaticFiles(directory="static",html = True), name="static")
(Thanks to this answer)
The index.html is now available under http://localhost:8000/
Option 2: Serving only index.html
As fastapi is based on starlette, a simple FileResponse does the job.
from starlette.responses import FileResponse
#app.get("/")
async def read_index():
return FileResponse('index.html')
Found here.
The best and most simple solution that worked for me:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
api_app = FastAPI(title="api app")
#api_app.post("/set_influencers_to_follow")
async def set_influencers_to_follow(request):
return {}
app = FastAPI(title="main app")
app.mount("/api", api_app)
app.mount("/", StaticFiles(directory="ui", html=True), name="ui")
If project structure is like:
├── main.py
├── ui
│ ├── index.html
│ ├── style.css
│ ├── script.js
Related
I want to write a minimal FastAPI static file server launched from a script that allows you to specify the directory to share on the command line. Following the example in the FastAPI documentation, I wrote this.
import uvicorn
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
server = FastAPI()
if __name__ == "__main__":
import sys
directory = sys.argv[1]
server.mount("/static", StaticFiles(directory=directory), name="static")
uvicorn.run(app="my_package:server")
If I run this with the argument /my/directory where this directory contains file.txt I expect that I'd be able to download file.txt at the URL http://localhost:8000/static/file.txt, but this returns an HTTP 404.
How do I write this minimal static file server script?
The assumption I made about sys.argv not being available when uvicorn loads your module is wrong, so it should work as you expect by moving your static setup outside of the __main__ guard:
import uvicorn
import sys
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
server = FastAPI()
directory = sys.argv[1]
server.mount("/static", StaticFiles(directory=directory), name="static")
if __name__ == "__main__":
uvicorn.run(app="my_package:server")
When you call uvicorn.run(app="my_package:server"), it actually starts a separate process where my_package is imported. Therefore, everything inside if __name__ == "__main__": will not be run in the uvicorn process, so your directory will never be mounted.
One possible solution would be getting the directory from an environment variable, which is set from a small bash script:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
server = FastAPI()
directory = os.getenv("DIRECTORY")
server.mount("/static", StaticFiles(directory=directory), name="static")
start.sh:
#!/usr/bin/env bash
DIRECTORY=$1 uvicorn mypackage:server
I have made a Next.JS typescript monorepo here with the following folder structure:
.
└── packages
├── package.json // Housing the monorepo workspace
├── web-app // Housing the NextJS website
└── web-core // Housing the redux business logic
Whenever I run yarn dev inside the root or inside the web-app, I get the following parsing error:
error - Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
at useReduxContext (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/packages/web-app/node_modules/react-redux/lib/hooks/useReduxContext.js:30:11)
at useStore (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/packages/web-app/node_modules/react-redux/lib/hooks/useStore.js:28:28)
at useDispatch (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/packages/web-app/node_modules/react-redux/lib/hooks/useDispatch.js:24:17)
at Home (webpack-internal:///./pages/index.tsx:21:78)
at processChild (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/react-dom/cjs/react-dom-server.node.development.js:3353:14)
at resolve (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/react-dom/cjs/react-dom-server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/react-dom/cjs/react-dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/react-dom/cjs/react-dom-server.node.development.js:3690:29)
at Object.renderToString (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/react-dom/cjs/react-dom-server.node.development.js:4298:27)
at Object.renderPage (/Users/hasnainali/Downloads/Projects/Web/jest-rollup-issue/node_modules/next/dist/server/render.js:680:46) {
page: '/'
}
I am doing something wrong with the setup of the monorepo which I am failing to understand. Please help!
This is a follow up of my previous question.
The structure of the files is shown below. I have to run the scripts using python -m bokeh_module.bokeh_sub_module from the top directory. The image.png might come from an arbitrary directory later.
.
├── other_module
│ ├── __init__.py
│ └── other_sub_module.py
├── bokeh_module
│ ├── __init__.py
│ ├── image.png # not showing
│ └── bokeh_sub_module.py
└── image.png # not showing either
The bokeh_sub_module.py is using the standalone bokeh server. However the image will not show no matter where it is placed. I got this WARNING:tornado.access:404 GET /favicon.ico (::1) 0.50ms I'm not sure if this an issue from bokeh or tornado. Thank you for any help.
from other_module import other_sub_module
import os
from bokeh.server.server import Server
from bokeh.layouts import column
from bokeh.plotting import figure, show
import tornado.web
def make_document(doc):
def update():
pass
# do something with other_sub_module
p = figure(match_aspect=True)
p.image_url( ['file://image.png'], 0, 0, 1, 1)
doc.add_root(column(p, sizing_mode='stretch_both'))
doc.add_periodic_callback(callback=update, period_milliseconds=1000)
apps = {'/': make_document}
application = tornado.web.Application([(r"/(.*)", \
tornado.web.StaticFileHandler, \
{"path": os.path.dirname(__file__)}),])
server = Server(apps, tornado_app=application)
server.start()
server.io_loop.add_callback(server.show, "/")
server.io_loop.start()
I tried the argument extra_patterns and it does not work either...
You cannot use the file:// protocol with web servers and browsers. Just use regular http:// or https://. If you specify the correct URL, the StaticFileHandler should properly handle it.
Apart from that, your usage of Server is not correct. It doesn't have the tornado_app argument. Instead, pass the routes directly:
extra_patterns = [(r"/(.*)", tornado.web.StaticFileHandler,
{"path": os.path.dirname(__file__)})]
server = Server(apps, extra_patterns=extra_patterns)
BTW just in case - in general, you shouldn't serve the root of your app. Otherwise, anyone would be able to see your source code.
I have a simple angular app managed by Grunt.js. I use the angular router for different pages:
index.html
...
<body ng-app="app">
...
<div ng-view></div>
...
</div>
...
_users.html
<h1>Users</h1>
...
app.js
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'views/_home.html',
controller: 'HomeCtrl'
}).
when('/users', {
templateUrl: 'views/_users.html',
controller: 'UsersCtrl'
}).
otherwise({ redirectTo: '/' });
}]);
// ... controllers
The routing works fine for client side rendering, e.g requests of the form site.com, site.com/#/users, etc. If I apply $locationProvider.html5Mode({ enabled: true }), a direct call for site.com/users will fail, because there are no users.html or users/index.html files. Is there a smart grunt plugin which knows to render the views inside the layout when building a distribution directory? That is, generate a directory structure like for every nested view:
dist
├── index.html
└── users
│ └── index.html
├── css
│ └── app.css
└── js
└── app.js
Thanks.
So, to sum up our discussion in comments :
To get nice urls : you should configure $locationProvider and set html5Mode to true
Then, your server should look at the requested folders (i.e. looking into the folder my-folder for the URL site.com/my-folder/) so it won't work
So you have to make a basic rewrite rule in your htaccess (assuming you're working on Apache server), something like that (assuming index.html is the entry point of your app :
>
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/index.html$
RewriteCond %{REQUEST_URI} !\.(gif|jpe?g|png|css|js)$
RewriteRule .* /index.html [L,R=302]
From Angular doc : https://docs.angularjs.org/guide/$location#server-side
Unless if you really want to have static files to serve to the client (for any reason), this is the solution.
I just downloaded the latest Django version (1.4.1), and I can't figure out how to serve css files when developing locally using runserver. I've read the relevant Django docs on static files and many, many questions & answers here... sounds like it's supposed to be more or less automatic, but it's not working for me.
I'm working on the polls app from the tutorial.
404 from the log
[27/Apr/2012 01:04:09] "GET /polls/ HTTP/1.1" 200 210
[27/Apr/2012 01:04:09] "GET /polls/css/styles.css HTTP/1.1" 404 2596
Directory structure
mysite
|-- manage.py
|-- mysite
|-- __init__.py
|-- settings.py
|-- urls.py
|-- wsgi.py
|-- polls
|-- __init__.py
|-- models.py
|-- tests.py
|-- views.py
|-- static
|-- css
|-- styles.css
|-- templates
|-- polls
|-- index.html
index.html
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/styles.css">
settings.py
MEDIA_ROOT = ''
MEDIA_URL = ''
STATIC_ROOT = ''
STATIC_URL = '/static/'
STATICFILES_DIRS = ()
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
'django.core.context_processors.static',
)
^^^ I didn't have the TEMPLATE_CONTEXT_PROCESSORS variable in settings.py when I started the project and had to add it manually - should I be worried about that?
STATICFILES_DIRS is empty, because the css file is in a directory named static within the polls app, which is where Django looks for it automatically - right?
I also have django.contrib.staticfiles in my INSTALLED_APPS.
urls.py
I saw in the docs that this solution works for local development servers other than runserver - sounds like it shouldn't be necessary otherwise, right? (I currently have it commented out.)
EDIT: I uncommented these lines, but did not see a change - still getting the same 404 on the css file
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
Do I have my directory structure set up wrong? Am I missing necessary settings in settings.py? Any help would be very much appreciated! Thanks!
EDIT:
I took Mark's suggestion and read up on RequestContext. Changing my view from:
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
to
from django.template import RequestContext
...
return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list}, context_instance=RequestContext(request))
got the /static/ url to register:
[27/Apr/2012 13:56:55] "GET /static/css/styles.css HTTP/1.1" 200 19
This fixes the problem.
In order to use STATIC_URL in the template you need to be sure you are using a RequestContext along with adding 'django.core.context_processors.static' to TEMPLATE_CONTEXT_PROCESSORS. This is done for you if you are using the render shortcut. If you are not using a RequestContext then you can use the {% get_static_prefix %} template tag from the staticfiles template tag library. This is detailed in the docs here: https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/#other-helpers
.'
I had the same problem, and evnetually with the same coinfuration as mentioned above this did the trick:
i added in setting.py the path to my static directory in STATICFILES_DIRS:
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR,'static'),
)
when also in settings.py PROJECT_DIR is set to:
PROJECT_DIR=os.path.dirname(os.path.abspath(__file__))
From your 404, looks like you're not including {{ STATIC_URL }} in your template. That's probably the problem. instead of just "css/file", do "{{ STATIC_URL}}css/file"
Without looking too hard, your settings looks fine. If the above doesn't work, try running ./manage.py collectstatic and see if that helps (it moves static files from app directories into a project static directory).
And definitely uncomment those lines in your urls.py!
If you don't have static url patterns, when it goes to request something from /static/, it won't know what to do.
This worked for me under development server:
1. I added "static" folder under my application "myblog" directory.
2. Added "myblog.css" file inside "static" folder.
3. Linked the style sheet to my application's template, code is below.
<link rel="stylesheet" href="{{ STATIC_URL }}myblog.css" type="text/css" media="screen" />
I did not change settings.py or urls.py files in order to fix css, the changes were made are only according to tutorial, so you should have the same.