summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-fastapi-etag.spec441
-rw-r--r--sources1
3 files changed, 443 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..b58e3b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/fastapi-etag-0.4.0.tar.gz
diff --git a/python-fastapi-etag.spec b/python-fastapi-etag.spec
new file mode 100644
index 0000000..ad266ed
--- /dev/null
+++ b/python-fastapi-etag.spec
@@ -0,0 +1,441 @@
+%global _empty_manifest_terminate_build 0
+Name: python-fastapi-etag
+Version: 0.4.0
+Release: 1
+Summary: Convenience library for working with etags in fastapi
+License: MIT
+URL: https://github.com/steinitzu/fastapi-etag
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/96/38/840966db80f5d8cd419754fad150edd16ed161ffb473379f0e7e0f7fad1f/fastapi-etag-0.4.0.tar.gz
+BuildArch: noarch
+
+
+%description
+# fastapi-etag
+
+## Quickstart
+
+Basic etag support for FastAPI, allowing you to benefit from conditional caching in web browsers and reverse-proxy caching layers.
+
+This does not generate etags that are a hash of the response content, but instead lets you pass in a custom etag generating function per endpoint that is called before executing the route function.
+This lets you bypass expensive API calls when client includes a matching etag in the `If-None-Match` header, in this case your endpoint is never called, instead returning a 304 response telling the client nothing has changed.
+
+The etag logis is implemented with a fastapi dependency that you can add to your routes or entire routers.
+
+Here's how you use it:
+
+```python3
+# app.py
+
+from fastapi import FastAPI
+from starlette.requests import Request
+from fastapi_etag import Etag, add_exception_handler
+
+app = FastAPI()
+add_exception_handler(app)
+
+
+async def get_hello_etag(request: Request):
+ return "etagfor" + request.path_params["name"]
+
+
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+async def hello(name: str):
+ return {"hello": name}
+
+```
+
+Run this example with `uvicorn: uvicorn --port 8090 app:app`
+
+Let's break it down:
+
+```python3
+add_exception_handler(app)
+```
+
+The dependency raises a special `CacheHit` exception to exit early when there's a an etag match, this adds a standard exception handler to the app to generate a correct 304 response from the exception.
+
+```python3
+async def get_hello_etag(request: Request):
+ name = request.path_params.get("name")
+ return f"etagfor{name}"
+```
+
+This is the function that generates the etag for your endpoint.
+It can do anything you want, it could for example return a hash of a last modified timestamp in your database.
+It can be either a normal function or an async function.
+Only requirement is that it accepts one argument (request) and that it returns either a string (the etag) or `None` (in which case no etag header is added)
+
+
+```python3
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+def hello(name: str):
+ ...
+```
+
+The `Etag` dependency is called like any fastapi dependency.
+It always adds the etag returned by your etag gen function to the response.
+If client passes a matching etag in the `If-None-Match` header, it will raise a `CacheHit` exception which triggers a 304 response before calling your endpoint.
+
+
+Now try it with curl:
+
+```
+curl -i "http://localhost:8090/hello/bob"
+HTTP/1.1 200 OK
+date: Mon, 30 Dec 2019 21:55:43 GMT
+server: uvicorn
+content-length: 15
+content-type: application/json
+etag: W/"etagforbob"
+
+{"hello":"bob"}
+```
+
+Etag header is added
+
+Now including the etag in `If-None-Match` header (mimicking a web browser):
+
+```
+curl -i -X GET "http://localhost:8090/hello/bob" -H "If-None-Match: W/\"etagforbob\""
+HTTP/1.1 304 Not Modified
+date: Mon, 30 Dec 2019 21:57:37 GMT
+server: uvicorn
+etag: W/"etagforbob"
+```
+
+It now returns no content, only the 304 telling us nothing has changed.
+
+### Add response headers
+
+If you want to add some extra response headers to the 304 and regular response,
+you can add the `extra_headers` argument with a dict of headers:
+
+```
+@app.get(
+ "/hello/{name}",
+ dependencies=[
+ Depends(
+ Etag(
+ get_hello_etag,
+ extra_headers={"Cache-Control": "public, max-age: 30"},
+ )
+ )
+ ],
+)
+def hello(name: str):
+ ...
+```
+
+This will add the `cache-control` header on all responses from the endpoint.
+
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
+
+
+
+%package -n python3-fastapi-etag
+Summary: Convenience library for working with etags in fastapi
+Provides: python-fastapi-etag
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-fastapi-etag
+# fastapi-etag
+
+## Quickstart
+
+Basic etag support for FastAPI, allowing you to benefit from conditional caching in web browsers and reverse-proxy caching layers.
+
+This does not generate etags that are a hash of the response content, but instead lets you pass in a custom etag generating function per endpoint that is called before executing the route function.
+This lets you bypass expensive API calls when client includes a matching etag in the `If-None-Match` header, in this case your endpoint is never called, instead returning a 304 response telling the client nothing has changed.
+
+The etag logis is implemented with a fastapi dependency that you can add to your routes or entire routers.
+
+Here's how you use it:
+
+```python3
+# app.py
+
+from fastapi import FastAPI
+from starlette.requests import Request
+from fastapi_etag import Etag, add_exception_handler
+
+app = FastAPI()
+add_exception_handler(app)
+
+
+async def get_hello_etag(request: Request):
+ return "etagfor" + request.path_params["name"]
+
+
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+async def hello(name: str):
+ return {"hello": name}
+
+```
+
+Run this example with `uvicorn: uvicorn --port 8090 app:app`
+
+Let's break it down:
+
+```python3
+add_exception_handler(app)
+```
+
+The dependency raises a special `CacheHit` exception to exit early when there's a an etag match, this adds a standard exception handler to the app to generate a correct 304 response from the exception.
+
+```python3
+async def get_hello_etag(request: Request):
+ name = request.path_params.get("name")
+ return f"etagfor{name}"
+```
+
+This is the function that generates the etag for your endpoint.
+It can do anything you want, it could for example return a hash of a last modified timestamp in your database.
+It can be either a normal function or an async function.
+Only requirement is that it accepts one argument (request) and that it returns either a string (the etag) or `None` (in which case no etag header is added)
+
+
+```python3
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+def hello(name: str):
+ ...
+```
+
+The `Etag` dependency is called like any fastapi dependency.
+It always adds the etag returned by your etag gen function to the response.
+If client passes a matching etag in the `If-None-Match` header, it will raise a `CacheHit` exception which triggers a 304 response before calling your endpoint.
+
+
+Now try it with curl:
+
+```
+curl -i "http://localhost:8090/hello/bob"
+HTTP/1.1 200 OK
+date: Mon, 30 Dec 2019 21:55:43 GMT
+server: uvicorn
+content-length: 15
+content-type: application/json
+etag: W/"etagforbob"
+
+{"hello":"bob"}
+```
+
+Etag header is added
+
+Now including the etag in `If-None-Match` header (mimicking a web browser):
+
+```
+curl -i -X GET "http://localhost:8090/hello/bob" -H "If-None-Match: W/\"etagforbob\""
+HTTP/1.1 304 Not Modified
+date: Mon, 30 Dec 2019 21:57:37 GMT
+server: uvicorn
+etag: W/"etagforbob"
+```
+
+It now returns no content, only the 304 telling us nothing has changed.
+
+### Add response headers
+
+If you want to add some extra response headers to the 304 and regular response,
+you can add the `extra_headers` argument with a dict of headers:
+
+```
+@app.get(
+ "/hello/{name}",
+ dependencies=[
+ Depends(
+ Etag(
+ get_hello_etag,
+ extra_headers={"Cache-Control": "public, max-age: 30"},
+ )
+ )
+ ],
+)
+def hello(name: str):
+ ...
+```
+
+This will add the `cache-control` header on all responses from the endpoint.
+
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
+
+
+
+%package help
+Summary: Development documents and examples for fastapi-etag
+Provides: python3-fastapi-etag-doc
+%description help
+# fastapi-etag
+
+## Quickstart
+
+Basic etag support for FastAPI, allowing you to benefit from conditional caching in web browsers and reverse-proxy caching layers.
+
+This does not generate etags that are a hash of the response content, but instead lets you pass in a custom etag generating function per endpoint that is called before executing the route function.
+This lets you bypass expensive API calls when client includes a matching etag in the `If-None-Match` header, in this case your endpoint is never called, instead returning a 304 response telling the client nothing has changed.
+
+The etag logis is implemented with a fastapi dependency that you can add to your routes or entire routers.
+
+Here's how you use it:
+
+```python3
+# app.py
+
+from fastapi import FastAPI
+from starlette.requests import Request
+from fastapi_etag import Etag, add_exception_handler
+
+app = FastAPI()
+add_exception_handler(app)
+
+
+async def get_hello_etag(request: Request):
+ return "etagfor" + request.path_params["name"]
+
+
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+async def hello(name: str):
+ return {"hello": name}
+
+```
+
+Run this example with `uvicorn: uvicorn --port 8090 app:app`
+
+Let's break it down:
+
+```python3
+add_exception_handler(app)
+```
+
+The dependency raises a special `CacheHit` exception to exit early when there's a an etag match, this adds a standard exception handler to the app to generate a correct 304 response from the exception.
+
+```python3
+async def get_hello_etag(request: Request):
+ name = request.path_params.get("name")
+ return f"etagfor{name}"
+```
+
+This is the function that generates the etag for your endpoint.
+It can do anything you want, it could for example return a hash of a last modified timestamp in your database.
+It can be either a normal function or an async function.
+Only requirement is that it accepts one argument (request) and that it returns either a string (the etag) or `None` (in which case no etag header is added)
+
+
+```python3
+@app.get("/hello/{name}", dependencies=[Depends(Etag(get_hello_etag))])
+def hello(name: str):
+ ...
+```
+
+The `Etag` dependency is called like any fastapi dependency.
+It always adds the etag returned by your etag gen function to the response.
+If client passes a matching etag in the `If-None-Match` header, it will raise a `CacheHit` exception which triggers a 304 response before calling your endpoint.
+
+
+Now try it with curl:
+
+```
+curl -i "http://localhost:8090/hello/bob"
+HTTP/1.1 200 OK
+date: Mon, 30 Dec 2019 21:55:43 GMT
+server: uvicorn
+content-length: 15
+content-type: application/json
+etag: W/"etagforbob"
+
+{"hello":"bob"}
+```
+
+Etag header is added
+
+Now including the etag in `If-None-Match` header (mimicking a web browser):
+
+```
+curl -i -X GET "http://localhost:8090/hello/bob" -H "If-None-Match: W/\"etagforbob\""
+HTTP/1.1 304 Not Modified
+date: Mon, 30 Dec 2019 21:57:37 GMT
+server: uvicorn
+etag: W/"etagforbob"
+```
+
+It now returns no content, only the 304 telling us nothing has changed.
+
+### Add response headers
+
+If you want to add some extra response headers to the 304 and regular response,
+you can add the `extra_headers` argument with a dict of headers:
+
+```
+@app.get(
+ "/hello/{name}",
+ dependencies=[
+ Depends(
+ Etag(
+ get_hello_etag,
+ extra_headers={"Cache-Control": "public, max-age: 30"},
+ )
+ )
+ ],
+)
+def hello(name: str):
+ ...
+```
+
+This will add the `cache-control` header on all responses from the endpoint.
+
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md)
+
+
+
+%prep
+%autosetup -n fastapi-etag-0.4.0
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-fastapi-etag -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Mon May 29 2023 Python_Bot <Python_Bot@openeuler.org> - 0.4.0-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..9cca238
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+e5222da7a1d2021e81c9ea6313afdde1 fastapi-etag-0.4.0.tar.gz