(w http.ResponseWriter, req *http.Request)
| 22 | ) |
| 23 | |
| 24 | func (s *Server) apiHandler(w http.ResponseWriter, req *http.Request) error { |
| 25 | // Parse path parameters |
| 26 | ctx := req.Context() |
| 27 | instanceID := req.PathValue("instance_id") |
| 28 | apiName := req.PathValue("name") |
| 29 | |
| 30 | // Add observability attributes |
| 31 | observability.AddRequestAttributes(ctx, |
| 32 | attribute.String("args.instance_id", instanceID), |
| 33 | attribute.String("args.name", apiName), |
| 34 | ) |
| 35 | s.addInstanceRequestAttributes(ctx, instanceID) |
| 36 | |
| 37 | // Check if user has access to query for API data |
| 38 | claims := auth.GetClaims(ctx, instanceID) |
| 39 | if !claims.Can(runtime.ReadAPI) { |
| 40 | return httputil.Errorf(http.StatusForbidden, "does not have access to custom APIs") |
| 41 | } |
| 42 | |
| 43 | // Parse args from the request body and URL query |
| 44 | args := make(map[string]any) |
| 45 | body, err := io.ReadAll(req.Body) |
| 46 | if err != nil { |
| 47 | return httputil.Errorf(http.StatusBadRequest, "failed to read request body: %w", err) |
| 48 | } |
| 49 | if len(body) > 0 { // For POST requests |
| 50 | if err := json.Unmarshal(body, &args); err != nil { |
| 51 | return httputil.Errorf(http.StatusBadRequest, "failed to unmarshal request body: %w", err) |
| 52 | } |
| 53 | } |
| 54 | for k, v := range req.URL.Query() { |
| 55 | // Set only the first value so that client does need to put array accessors in templates. |
| 56 | args[k] = v[0] |
| 57 | } |
| 58 | |
| 59 | // Find the API resource |
| 60 | api, err := s.runtime.APIForName(ctx, instanceID, apiName) |
| 61 | if err != nil { |
| 62 | if errors.Is(err, drivers.ErrResourceNotFound) { |
| 63 | return httputil.Errorf(http.StatusNotFound, "api with name %q not found", apiName) |
| 64 | } |
| 65 | return httputil.Error(http.StatusInternalServerError, err) |
| 66 | } |
| 67 | |
| 68 | // Rewrite the claims before passing them to the resolver |
| 69 | if api.Spec.SkipNestedSecurity { |
| 70 | claims.SkipChecks = true |
| 71 | } |
| 72 | |
| 73 | // Resolve the API to JSON data |
| 74 | res, _, err := s.runtime.Resolve(ctx, &runtime.ResolveOptions{ |
| 75 | InstanceID: instanceID, |
| 76 | Resolver: api.Spec.Resolver, |
| 77 | ResolverProperties: api.Spec.ResolverProperties.AsMap(), |
| 78 | Args: args, |
| 79 | Claims: claims, |
| 80 | }) |
| 81 | if err != nil { |
nothing calls this directly
no test coverage detected