Skip to content
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

FastAPI app #27

Merged
merged 8 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions fastapi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SpiceQL FastAPI App

## Create local instance

### 1. Create conda environment
Create the conda environment to run your local instance in:
```
conda create -n spiceql-api -f environment.yaml
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved
```

### 2. Set environment variables
Similarly to your SpiceQL conda environment, set `SPICEROOT` or `ISISDATA` to your ISIS data area. You may also need to set `SSPICE_DEBUG` to any value, like `True`.
jlaura marked this conversation as resolved.
Show resolved Hide resolved

To set an environment variable within the scope of your conda environment:
```
conda activate spiceql-api
conda env config vars set SPICEROOT=/path/to/isis_data
```

### 3. Run the app
Inside the `app/` dir, run the following command:
```
uvicorn app.main:app --reload --port 8080
```
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved

You can access the Swagger UI of all the endpoints at http://127.0.0.1:8080/docs.
Empty file added fastapi/app/__init__.py
Empty file.
227 changes: 227 additions & 0 deletions fastapi/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
"""Module providing SpiceQL endpoints"""

from ast import literal_eval
from typing import Annotated, Any
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
import pyspiceql


# Models
class MessageItem(BaseModel):
message: str

class ResultModel(BaseModel):
result: Any = Field(serialization_alias='return')

class ErrorModel(BaseModel):
error: str

class ResponseModel(BaseModel):
statusCode: int
body: ResultModel | ErrorModel

# Create FastAPI instance
app = FastAPI()

# General endpoints
@app.get("/")
async def root():
return {"message": "Visit the /docs endpoint to see the Swagger UI."}
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved

@app.post("/customMessage")
async def message(
message_item: MessageItem
):
return {"message": message_item.message}


# SpiceQL endpoints
@app.get("/getTargetStates")
async def getTargetStates(
ets: Annotated[list[float], Query()] | str,
target: str,
observer: str,
frame: str,
abcorr: str,
mission: str,
ckQuality: str = "",
spkQuality: str = "",
searchKernels: bool = False):
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved
try:
if isinstance(ets, str):
ets = literal_eval(ets)
result = pyspiceql.getTargetStates(ets, target, observer, frame, abcorr, mission, ckQuality, spkQuality, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)
jlaura marked this conversation as resolved.
Show resolved Hide resolved

@app.get("/getTargetOrientations")
async def getTargetOrientations(
ets: Annotated[list[float], Query()] | str,
toFrame: int,
refFrame: int,
mission: str,
ckQuality: str = "",
searchKernels: bool = False):
try:
if isinstance(ets, str):
ets = literal_eval(ets)
result = pyspiceql.getTargetOrientations(ets, toFrame, refFrame, mission, ckQuality, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/strSclkToEt")
async def strSclkToEt(
frameCode: int,
sclk: str,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.strSclkToEt(frameCode, sclk, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/doubleSclkToEt")
async def doubleSclkToEt(
frameCode: int,
sclk: float,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.doubleSclkToEt(frameCode, sclk, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/utcToEt")
async def utcToEt(
utc: str,
searchKernels: bool = False):
try:
result = pyspiceql.utcToEt(utc, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/translateNameToCode")
async def translateNameToCode(
frame: str,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.translateNameToCode(frame, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/translateCodeToName")
async def translateCodeToName(
frame: int,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.translateCodeToName(frame, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/getFrameInfo")
async def getFrameInfo(
frame: int,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.getFrameInfo(frame, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/getTargetFrameInfo")
async def getTargetFrameInfo(
targetId: int,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.getTargetFrameInfo(targetId, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/findMissionKeywords")
async def findMissionKeywords(
key: str,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.findMissionKeywords(key, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/findTargetKeywords")
async def findTargetKeywords(
key: str,
mission: str,
searchKernels: bool = False):
try:
result = pyspiceql.findTargetKeywords(key, mission, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/frameTrace")
async def frameTrace(
et: float,
initialFrame: int,
mission: str,
ckQuality: str = "",
searchKernels: bool = False):
try:
result = pyspiceql.frameTrace(et, initialFrame, mission, ckQuality, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)

@app.get("/extractExactCkTimes")
async def extractExactCkTimes(
observStart: float,
observEnd: float,
targetFrame: int,
mission: str,
ckQuality: str = "",
searchKernels: bool = False):
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved
try:
result = pyspiceql.extractExactCkTimes(observStart, observEnd, targetFrame, mission, ckQuality, searchKernels)
body = ResultModel(result=result)
return ResponseModel(statusCode=200, body=body)
except Exception as e:
body = ErrorModel(error=str(e))
return ResponseModel(statusCode=500, body=body)
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved

8 changes: 8 additions & 0 deletions fastapi/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
channels:
- conda-forge

dependencies:
- fastapi
- pydantic==2.6.3
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved
- spiceql
chkim-usgs marked this conversation as resolved.
Show resolved Hide resolved
- uvicorn
Loading