{"id":18244283,"url":"https://github.com/stackb/grpc-starlark","last_synced_at":"2025-04-08T18:33:33.075Z","repository":{"id":169179452,"uuid":"645051912","full_name":"stackb/grpc-starlark","owner":"stackb","description":"Starlark infused gRPC server","archived":false,"fork":false,"pushed_at":"2023-06-14T19:04:52.000Z","size":205,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-14T14:51:41.048Z","etag":null,"topics":["grpc","mock-server","starlark"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stackb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-24T20:19:40.000Z","updated_at":"2023-06-03T04:33:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"78c3fbb4-ce40-4ffc-91b4-f1b6b71e852b","html_url":"https://github.com/stackb/grpc-starlark","commit_stats":null,"previous_names":["stackb/grpc-starlark"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fgrpc-starlark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fgrpc-starlark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fgrpc-starlark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackb%2Fgrpc-starlark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackb","download_url":"https://codeload.github.com/stackb/grpc-starlark/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247902306,"owners_count":21015426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","mock-server","starlark"],"created_at":"2024-11-05T09:16:00.403Z","updated_at":"2025-04-08T18:33:33.065Z","avatar_url":"https://github.com/stackb.png","language":"Go","readme":"[![CI](https://github.com/stackb/grpc-starlark/actions/workflows/ci.yaml/badge.svg)](https://github.com/stackb/grpc-starlark/actions/workflows/ci.yaml)\n\n# grpc-starlark\n\n\u003ctable border=\"0\"\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/50580/141900696-bfb2d42d-5d2c-46f8-bd9f-06515969f6a2.png\" height=\"120\"/\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/7802525?v=4\u0026s=400\" height=\"120\"/\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"https://static.vecteezy.com/system/resources/previews/007/038/145/non_2x/nightingale-singing-tune-song-bird-musical-notes-music-concept-icon-in-circle-round-black-color-illustration-flat-style-image-vector.jpg\" height=\"120\"/\u003e\u003c/td\u003e\n    \u003c!-- image credit: https://www.vecteezy.com/vector-art/7038145-nightingale-singing-tune-song-bird-musical-notes-music-concept-icon-in-circle-round-black-color-vector-illustration-flat-style-image --\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eprotobuf\u003c/td\u003e\n    \u003ctd\u003egrpc\u003c/td\u003e\n    \u003ctd\u003estarlark\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n`grpc-starlark` is a:\n- library for embedding a gRPC-capable starlark interpreter,\n- standalone binary `grpcstar` that executes starlark scripts.\n\n\u003e The author pronounces this as `grip-ster` (like \"napster\", but you can say it however you like).\n\n`grpcstar` use cases include:\n\n- replacement for `grpcurl` when calling gRPC services from the command line\n- stand-in for `postman`\n- testing gRPC backends\n- mocking gRPC backends in integration tests\n- gRPC microservices with things like [Google Cloud\n  Run](https://cloud.google.com/run/docs/triggering/grpc) \n\n## Installation\n\nDownload a binary from the [releases\npage](https://github.com/stackb/grpc-starlark/releases), or install from source:\n\n```sh\ngo install github.com/stackb/grpc-starlark/cmd/grpcstar@latest\n```\n\n## Usage\n\n```\nusage: grpcstar [OPTIONS...] [ARGS...]\n\ngithub:\n\thttps://github.com/stackb/grpc-starlark\n\noptions:\n\t-h, --help [optional, false]\n\t\tshow this help screen\n\t-p, --protoset [required]\n\t\tfilename of proto descriptor set\n\t-f, --file [required]\n\t\tfilename of entrypoint starlark script\n\t\t(conventionally named *.grpc.star)\n\t-e, --entrypoint [optional, \"main\"]\n\t\tname of function in global scope to invoke upon script start\n\t-o, --output [optional, \"json\", oneof \"json|proto|text|yaml\"]\n\t\tformatter for output protobufs returned by entrypoint function\n\t-i, --interactive [optional, false]\n\t\tstart a REPL session (rather then exec the entrypoint)\n\nexample:\n\t$ grpcstar \\\n\t\t-p routeguide.pb \\\n\t\t-f routeguide.grpc.star \\\n\t\t-e call_get_feature \\\n\t\tlongitude=35.0 latitude=109.1\n```\n\n## Bazel Usage\n\nSee [bazel rule documentation](rules/).\n\n## Docker Usage\n\nAn image is pushed to [ghcr.io/stackb/grpc-starlark/grpcstar](https://github.com/orgs/stackb/packages/container/package/grpc-starlark%2Fgrpcstar) during the release\nworkflow.  It consists of small base layer and the `grpcstar` binary at the root\nof the container with the `Entrypoint` to set `/grpcstar`.\n\n```dockerfile\nFROM ghcr.io/stackb/grpc-starlark/grpcstar:v0.6.0\n\nCOPY service.descriptor.pb /\nCOPY server.grpc.star /\n\nCMD --protoset /service.descriptor.pb --file /server.grpc.star\n```\n\n### Proto Descriptor Set\n\ngrpcstar requires a precompiled proto descriptor set via the `--protoset` (`-p`)\nflag. This file defines the universe of message, enum, and service types that\ncan be used in your script.\n\nThis file can be generated by the protoc `--descriptor_set_out` flag and is used\nby other tools in the protobuf/gRPC ecosystem (see\n[grpcurl](https://github.com/fullstorydev/grpcurl#protoset-files)).\n\nFor bazel users, the `proto_library` rule produces this as its output file.  The\n[proto_descriptor_set](https://github.com/bazelbuild/rules_proto/blob/master/proto/private/rules/proto_descriptor_set.bzl)\nconcatenates multiple descriptor sets together (`cat foo.descriptor.pb\nbar.descriptor.pb \u003e combined.descriptor.pb`).\n\n### Script File\n\nThe script file `--file` (`-f`) is the entrypoint file executed by the embedded starlark interpreter. \n\nUse load statements (e.g. `load(\"filename{.star}\", \"symbol\")`) to populate\nadditional symbols into the entrypoint file.\n\n### Script Entrypoint\n\nThe script **must** contain a function named `main` that takes a single\npositional argument `ctx` (e.g.`def main(ctx):`).  The `--entrypoint` (`-e`)\nflag can be used to override this.\n\nThe `ctx` is a struct; `ctx.vars`  holds key-value pairs that can be set on the\ncommand line (e.g. `name=foo` would satisfy `ctx.vars.name == 'foo'`).\n\n### Script Output\n\nThe entrypoint function can either return nothing (`None`) or a list of protobuf\nmessages.  The messages will be printed to stdout and formatted according the\nthe `--output` flag (`-o`).  Choose one of `json`, `proto`, `text`, or `yaml`;\ndefault is `json`.\n\n`print(...)` statements are sent to stderr.\n\n### Script Concurrency Model\n\nThe starlark interpreter starts a single `main` thread for the top-level\nentrypoint file.  Each invocation of a `grpc.Server` handler callback function\nis run concurrently in a new thread.  `thread.defer` callbacks also occur in a\nnew thread.\n\n## API\n\n`grpc-starlark` is implemented using go and has an API similar to `grpc-go`.\n\n### Protobuf\n\nThe message and enum types are available via the `proto.package` function:\n\n```py\npb = proto.package(\"example.routeguide\")\nprint(pb.Rectangle)\n```\n\nThese define \"strongly-typed\" structs for use in creating and interacting with\nprotobuf messages:\n\n```py\ncolorado = pb.Rectangle(\n    lo = pb.Point(latitude = 36.999, longitude = -109.045),\n    hi = pb.Point(latitude = 40.979, longitude = -102.051),\n)\n```\n\nFor more details see\n[github.com/stripe/skycfg](https://github.com/stripe/skycfg), which provides the\ncore protobuf functionality.\n\n## gRPC\n\n### Server\n\nUse the `grpc.Server` constructor to make a new server.  Use the register\nfunction to provide function implementations for the service handlers.  Example:\n\n```py\nserver = grpc.Server()\n\nserver.register(\"example.routeguide.RouteGuide\", {\n    \"GetFeature\": get_feature,\n    \"ListFeatures\": list_features,\n    \"RecordRoute\": record_route,\n    \"RouteChat\": route_chat,\n})\n```\n\nUse a `net.Listener` to bind the server to a network address:\n\n```py\nlistener = net.Listener(address = \"localhost:8080\")\n```\n\nTo bind to a free port, use the defaults (`localhost` is the `host` and `0` is\nthe port)\n\n```py\nlistener = net.Listener()\nprint(listener.address) # localhost:50234\n```\n\n#### Unary RPC\n\n```py\ndef get_feature(stream, point):\n    \"\"\"get_feature implements a unary method handler\n\n    Args:\n        stream: the stream object\n        point: the requested Point\n    Returns:\n        a Feature, ideally nearest to the given point.\n\n    \"\"\"\n    return pb.Feature(name = \"point (%d,%d)\" % (point.longitude, point.latitude))\n```\n\nThe `stream` object can be used to access incoming headers `stream.ctx.metadata`\nor set outgoing headers/trailers (`stream.set_header`, `stream.set_trailer`).\n\nThe second positional argument is the request message.\n\nThe function should return an appropriate response message or a `grpc.Error`\nusing an status code and message (e.g. `return grpc.Error(code =\ngrpc.status.UNAUTHENTICATED, message = \"authorization header is required\"))`)\n\n#### Server Streaming RPC\n\n```py\n\ndef list_features(stream, rect):\n    \"\"\"list_features implements a server streaming handler\n\n    Args:\n        stream: the stream object\n        rect: the rectangle to get features within\n    Returns:\n        None\n\n    \"\"\"\n    features = [\n        pb.Feature(name = \"lo (%d,%d)\" % (rect.lo.longitude, rect.lo.latitude)),\n        pb.Feature(name = \"hi (%d,%d)\" % (rect.lo.longitude, rect.hi.latitude)),\n    ]\n    for feature in features:\n        stream.send(feature)\n```\n\nThe `stream.send` function is used to post response messages.\n\n#### Client Streaming RPC\n\n```py\n\ndef record_route(stream):\n    \"\"\"record_route implements a client streaming handler\n\n    Args:\n        stream: the stream object\n    Returns:\n        a RouteSummary with a summary of the traversed points.\n\n    \"\"\"\n    points = []\n    for point in stream:\n        points.append(point)\n    return pb.RouteSummary(\n        point_count = len(points),\n        distance = 2,\n        elapsed_time = 10,\n    )\n```\n\nThe `stream` is an iterable that will call `.RevcMsg` until the stream has been closed by the client.  \n\nAlternatively, the function `stream.recv` can be used to get a single message, or `None` if there are no more messages.\n\nThe return value of the function should return an appropriately typed message.\n\n#### Bidirectional Streaming RPC\n\n```py\ndef route_chat(stream):\n    \"\"\"route_chat implements a bidirectional streaming handler\n\n    Args:\n        stream: the stream object\n    Returns:\n        None\n\n    \"\"\"\n    notes = []\n    for note in stream:\n        notes.append(note)\n        stream.send(note)\n```\n\nIn this implementation the function broadcasts a reponse on every request.\n\n## time\n\nThe `time` module contains time-related functions.  For details, see \u003chttps://github.com/google/starlark-go/blob/master/lib/time/time.go\u003e.\n\n## os\n\nThe `os` module contains functions for interacting with the operating system.  \n\n- `os.getenv(\"NAME\")` returns the value of the environment variable `NAME` or `None` if not set.\n\nSee \u003chttps://github.com/stackb/grpc-starlark/tree/master/cmd/grpcstar/testdata\u003e for details.\n\n## thread\n\nThe `thread` module can be used to interact with the interpreter threading model.\n\n- `thread.sleep(duration)` pauses the current thread.\n- `thread.defer(fn, delay, count)` runs another function in a new thread after\n  the given delay.  An optional `count` argument will repeat the callback\n  invocation.  This function is akin to the javascript functions `setTimout` and\n  `setInterval`.\n- `thread.name` returns the name of the current thread.\n\nExample:\n\n```py\nthread.defer(lambda: server.start(listener))`\n```\n\n## net\n\nThe `net` module contains network-related functions.\n\n- `net.Listener` constructs a new listener via the\n  [net.Listen](https://pkg.go.dev/net#Listen) func.\n\n\n## process\n\nThe `process` module contains subprocess-related functions.\n\n- `process.run` runs a subprocess.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackb%2Fgrpc-starlark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackb%2Fgrpc-starlark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackb%2Fgrpc-starlark/lists"}