package api import ( "context" "errors" "net/http" "git.golem15.com/golem15/sm-seo-plugin/classes" ) // GetGraphInput is the query of GET /_seo/api/v1/graph. type GetGraphInput struct { URL string `json:"url" query:"url" jsonschema:"the page: a path such as /blog/post or an absolute URL of the site"` Schema *string `json:"schema,omitempty" query:"schema" jsonschema:"an unsaved structured data value (the seo_set_url_seo schema string) to preview instead of the stored one; omitted: the stored value"` } // Graph serves GET /_seo/api/v1/graph?url=&schema= (D-46, D-10): the // JSON-LD @graph the resolve answer of the URL carries, built with the // given unsaved schema value when sent, and every node with its missing // required and recommended properties (rules false for a type Google has // no rules for). It answers {locale, url, graph, nodes}; url and graph are // null for an address that is not an ok page. 422 for a URL that is not a // path or http(s) URL, or for a schema value the SEO tab would refuse. func Graph(service func() *classes.Service) http.HandlerFunc { return manage(service, func(ctx context.Context, svc *classes.Service, r *http.Request) (int, any, error) { q := r.URL.Query() var override *string if q.Has("schema") { v := q.Get("schema") override = &v } answer, res, err := svc.GraphOfURL(ctx, q.Get("url"), override) if errors.Is(err, classes.ErrBadURL) { return 0, nil, Fail(http.StatusUnprocessableEntity, err.Error()) } if err != nil { return 0, nil, err } if override != nil && res.TypeKey != "" { if typ, ok := svc.Registry().ContentType(res.TypeKey); ok && typ.Content != nil { if err := svc.CheckSchema(ctx, typ.Content.Kind, res.TypeKey, res.RecordID, *override); err != nil { return 0, nil, err } } } return http.StatusOK, answer, nil }) }