Blob storage service (gRPC)#

Service for storing and retrieving blobs in object storage with workspace-based authorization.

Endpoints#

Get signed URL for blob#

gRPC /nominal.blob_storage_service.v1.BlobStorageService/GetSignedUrlForBlob

Retrieve a signed URL for downloading a blob. The URL is valid for 15 minutes.

Request: GetSignedUrlForBlobRequest

owning_rid ResourceIdentifier required

​

Fields of ResourceIdentifier
rid string required

Matches ^ri\.[a-z][a-z0-9\-]*\.([a-z0-9][a-z0-9\-]*)?\.[a-z][a-z0-9\-]*\.[a-zA-Z0-9\-\._]+$.

file_name string required

​

Response: GetSignedUrlForBlobResponse

url string

This is a short lived signed url that can be used by the client to retrieve the object

Request

import grpc
from nominal.protos.blob_storage_service.v1 import blob_storage_service_pb2, blob_storage_service_pb2_grpc

channel = grpc.secure_channel("api.gov.nominal.io:443", grpc.ssl_channel_credentials())
blob_storage_service = blob_storage_service_pb2_grpc.BlobStorageServiceStub(channel)
auth = [("authorization", "Bearer <api key>")]

request = blob_storage_service_pb2.GetSignedUrlForBlobRequest(
    owning_rid={"rid": "<rid>"},
    file_name="<file name>",
)
response = blob_storage_service.GetSignedUrlForBlob(request, metadata=auth)
print(response)
package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"

	blob_storage_servicev1 "github.com/nominal-io/nominal-api-protos-go/nominal/protos/blob_storage_service/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

func main() {
	conn, err := grpc.NewClient("api.gov.nominal.io:443",
		grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	blobStorageService := blob_storage_servicev1.NewBlobStorageServiceClient(conn)
	ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer <api key>")

	request := &blob_storage_servicev1.GetSignedUrlForBlobRequest{
		OwningRid: &blob_storage_servicev1.ResourceIdentifier{
			Rid: "<rid>",
		},
		FileName: "<file name>",
	}
	response, err := blobStorageService.GetSignedUrlForBlob(ctx, request)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(response)
}

Response

{
  "url": "<url>"
}

Upload blob stream#

gRPC /nominal.blob_storage_service.v1.BlobStorageService/UploadBlobStream client streaming

Upload a blob using streaming. The blob will be stored with authorization checks based on the provided owningRid.

Request: a stream of UploadBlobStreamRequest

owning_rid ResourceIdentifier required

​

Fields of ResourceIdentifier
rid string required

Matches ^ri\.[a-z][a-z0-9\-]*\.([a-z0-9][a-z0-9\-]*)?\.[a-z][a-z0-9\-]*\.[a-zA-Z0-9\-\._]+$.

file_name string required

​

ensure_unique boolean required

when set to true, ensure_unique will attach the current timestamp to the file name this will ensure that we do not overwrite an existing file in blob storage

content bytes required

​

Response: UploadBlobStreamResponse

file_name string

This is the key that can be used in a retrieve blob request in order to retrieve this specific blob. If ensure_unique is not set, this will match the file name provided in UploadBlobStreamRequest

Request

import grpc
from nominal.protos.blob_storage_service.v1 import blob_storage_service_pb2, blob_storage_service_pb2_grpc

channel = grpc.secure_channel("api.gov.nominal.io:443", grpc.ssl_channel_credentials())
blob_storage_service = blob_storage_service_pb2_grpc.BlobStorageServiceStub(channel)
auth = [("authorization", "Bearer <api key>")]

request = blob_storage_service_pb2.UploadBlobStreamRequest(
    owning_rid={"rid": "<rid>"},
    file_name="<file name>",
    ensure_unique=True,
    content=b"<content>",
)
response = blob_storage_service.UploadBlobStream(iter([request]), metadata=auth)
print(response)
package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"

	blob_storage_servicev1 "github.com/nominal-io/nominal-api-protos-go/nominal/protos/blob_storage_service/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

func main() {
	conn, err := grpc.NewClient("api.gov.nominal.io:443",
		grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	blobStorageService := blob_storage_servicev1.NewBlobStorageServiceClient(conn)
	ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "Bearer <api key>")

	request := &blob_storage_servicev1.UploadBlobStreamRequest{
		OwningRid: &blob_storage_servicev1.ResourceIdentifier{
			Rid: "<rid>",
		},
		FileName:     "<file name>",
		EnsureUnique: true,
		Content:      []byte("<content>"),
	}
	stream, err := blobStorageService.UploadBlobStream(ctx)
	if err != nil {
		log.Fatal(err)
	}
	if err := stream.Send(request); err != nil {
		log.Fatal(err)
	}
	response, err := stream.CloseAndRecv()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(response)
}

Response

{
  "file_name": "<file name>"
}

Types#

ResourceIdentifier#

This is used to identify any type of blob that will be in object storage.

rid string required

Matches ^ri\.[a-z][a-z0-9\-]*\.([a-z0-9][a-z0-9\-]*)?\.[a-z][a-z0-9\-]*\.[a-zA-Z0-9\-\._]+$.

Page design based on Scalar, MIT License.