I have a few questions about using the HTTP JSON API to interact with a ledger and gRPC-web
The docs state that the HTTP JSON API is distinct from the gRPC API in that certain functionalities are limited
This also makes sense, as invoking gRPC methods requires an HTTP/2 proxy for REST-full interactions
I also understand that the HTTP JSON API ultimately translates and forwards these requests into gRPC calls
- What exactly is the HTTP JSON API?
- Is there a gRPC-web proxy available for more direct interaction with the API?
- Is the HTTP JSON API an implementation of a proper gRPC-web proxy? (as opposed to a more specialized or custom built service?)
1 Like
No, it’s a custom-built service (more on that on the following answer).
It’s a custom-built service that sits in front a participant and exposes a slightly different interface that is more familiar to developers who are not accustomed to gRPC. In particular, it uses its own specific encoding for Daml values which is more lightweight to interpret on the client than what you would get natively out of gRPC.
The gRPC-Web tutorial uses Envoy. I would assume that’s a safe choice. Unfortunately I’m not aware of others.
A word of caution
The Ledger API is meant for fast, payload-agnostic transaction processing, not analytical workloads. As such, its querying capabilities are limited. Querying directly the ledger comes at the expense of flexibility. It also means that you are going to be bound 1:1 to the Daml models on the ledger and any upgrade will be breaking. Personally, I generally recommend having a service-specific backend that mediates between the ledger and downstream consumers. Of course, YMMV and you know your specific context best.
2 Likes
Thank you for taking the time to answer each of my questions, @stefanobaghino-da
This is unsupported, but we’ve managed to use envoy for a web-grpc interface, using this config:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: edge
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
virtual_hosts:
- name: direct_response_service
domains: ["*"]
routes:
- match:
prefix: "/"
direct_response:
status: 200
body:
filename: "./core/js/src/test/html/index.html"
- name: listener_1
address:
socket_address: { address: 0.0.0.0, port_value: 6865 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: ledger_api
timeout: 0s
max_stream_duration:
grpc_timeout_header_max: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_web
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
alpn_protocols: "h2"
tls_certificate_sds_secret_configs:
- name : participant_secrets
clusters:
- name: ledger_api
connect_timeout: 0.25s
http2_protocol_options: {}
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 5041
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
tls_certificate_sds_secret_configs:
- name : participant_secrets
secrets:
- name: participant_secrets
tls_certificate:
certificate_chain:
filename: "/path/to/participant.crt"
private_key:
filename: "/path/to/participant.pem"
One annoying this is that you need to have TLS support, so to test all this you also need to configure key certificates, which is an extra burden during initial development.
1 Like