Replies: 5 comments 5 replies
-
Hey @RemiSahl thanks for opening the discussion. Sadly I don't think there is a better way. I've opened an issue #457 to start thinking about it but still can't find a good solution |
Beta Was this translation helpful? Give feedback.
-
Hello @vincentsarago and thank you for answering my question. If I may, I think moving the rasterio logic outside of the fastApi routes declaration would allow me to import the required piece of code separately and fix my code duplication issue. Moreover, moving the rasterio manipulation logic outside of the Factory code would also open the door for different implementations of the geospatial data manipulation (using gdal python bindings instead of rasterio for example). |
Beta Was this translation helpful? Give feedback.
-
we could also do something like def tile(self, tile_routes: List[str]):
"""Register /tiles endpoint."""
def tile(
z: int = Path(..., ge=0, le=30, description="TMS tiles's zoom level"),
x: int = Path(..., description="TMS tiles's column"),
y: int = Path(..., description="TMS tiles's row"),
tms: TileMatrixSet = Depends(self.tms_dependency),
scale: int = Query(
1, gt=0, lt=4, description="Tile size scale. 1=256x256, 2=512x512..."
),
format: ImageType = Query(
None, description="Output image type. Default is auto."
),
src_path=Depends(self.path_dependency),
layer_params=Depends(self.layer_dependency),
dataset_params=Depends(self.dataset_dependency),
postprocess_params=Depends(self.process_dependency),
colormap=Depends(self.colormap_dependency),
render_params=Depends(self.render_dependency),
tile_buffer: Optional[float] = Query(
None,
gt=0,
alias="buffer",
title="Tile buffer.",
description="Buffer on each side of the given tile. It must be a multiple of `0.5`. Output **tilesize** will be expanded to `tilesize + 2 * tile_buffer` (e.g 0.5 = 257x257, 1.0 = 258x258).",
),
reader_params=Depends(self.reader_dependency),
env=Depends(self.environment_dependency),
):
"""Create map tile from a dataset."""
tilesize = scale * 256
with rasterio.Env(**env):
with self.reader(src_path, tms=tms, **reader_params) as src_dst:
data = src_dst.tile(
x,
y,
z,
tilesize=tilesize,
tile_buffer=tile_buffer,
**layer_params,
**dataset_params,
)
dst_colormap = getattr(src_dst, "colormap", None)
if not format:
format = ImageType.jpeg if data.mask.all() else ImageType.png
image = data.post_process(**postprocess_params)
content = image.render(
img_format=format.driver,
colormap=colormap or dst_colormap,
**format.profile,
**render_params,
)
return Response(content, media_type=format.mediatype)
for r in tile_routes:
self.router.add_api_route(
path=r,
methods=["GET"],
endpoint=tile,
**img_endpoint_params,
) def DatasetPathParams(layer: str = Path(..., description="Layer Name")) -> str:
"""Create dataset path from args"""
...
return url
@dataclass
class MyTiler(TilerFactory):
path_dependency = DatasetPathParams
def register_routes(self):
self.bounds()
self.info()
self.statistics()
self.tilejson()
self.wmts()
self.point()
self.preview()
self.part()
self.tile(
[
"/tiles/{layer}/{z}/{x}/{y}",
"/tiles/{layer}/{TileMatrixSetId}/{z}/{x}/{y}",
]
) Not really ✨ |
Beta Was this translation helpful? Give feedback.
-
@RemiSahl With the latest version of titiler (master) I've tried to reduce as much as possible to code (e.g removing timings). I gave more though to you PR, I see the advantage of extracting the complexity outside the factory, but IMO it only solve the issue for the |
Beta Was this translation helpful? Give feedback.
-
FYI: I just found a nice way to add more Path dependencies to a whole factory: stac-utils/titiler-pgstac#73 (comment) In ☝️ we add def ItemPathParams(
request: Request,
collection_id: str = Path(..., description="STAC Collection ID"),
item_id: str = Path(..., description="STAC Item ID"),
) -> Dict: as Path param (instead of |
Beta Was this translation helpful? Give feedback.
-
Hello!
I am trying to add a custom /tile routes on the TilerFactory in order to match my API specifications.
In order to this, I followed the methodology documented here: https://devseed.com/titiler/advanced/customization/#add-a-mosaicjson-creation-endpoint. I created a child class of the TilerFactory which exposes my custom route. I also implemented a custom path_dependency which allows src_path to be resolved using my custom parameters (here: project_id, layer_id, and time).
However, I did not find a way to bind my custom route to the /tiles function defined in the TilerFactory class. Therefore, I had to duplicate the code responsible for fetching a tile in my custom route, and this is potentially a pain to maintain in the future, should the /tile fetch logic changes. Can you think of another way to do this while avoiding code-duplication ?
I initially tried to call the /tile route, but it is apparently not possible: fastapi/fastapi#874.
As advised in the issue, one way to fix this would be to move the code responsible for fetching the tiles using rasterio in a separate module: " the easiest way to accomplish this might be to separate the shared business logic into a reusable function."
This is what the code of my factory looks like for now:
PS: Thanks for developing this library, it's very cool!
Beta Was this translation helpful? Give feedback.
All reactions