jsonschema

package
v0.40.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package jsonschema builds and checks JSON Schema documents.

It exists for one reason: a schema written as JSON in a string is a schema nothing checks, and the first time it is wrong the caller sends a value the program ignores. Here a schema is a value the compiler knows the shape of, and the same value both renders the document and validates against it, so the two cannot disagree.

The whole surface is a builder and one function:

schema := jsonschema.Object(
	jsonschema.Prop("status", jsonschema.String().
		Description("Which posts to list").
		Enum("published", "draft").
		Required()),
	jsonschema.Prop("limit", jsonschema.Integer().Min(1).Max(100)),
)

if err := jsonschema.Validate(schema, decoded); err != nil {
	// every problem, in one error
}

Two callers, one shape of the same need

A model asked to fill in a tool call, and a model asked to write a module specification, are the same problem: something outside the program produces JSON, and the program has to refuse what it did not ask for before any of it reaches application code. Both callers used to carry their own schema code.

What this package is not

It is not the validation package. That one checks a request or a struct against rule strings and produces a sentence for a person. This one checks decoded JSON against a schema document, before a handler runs, and produces a sentence for a machine. Neither is implemented in terms of the other, and neither grows the other's vocabulary.

Objects are closed

An object refuses a property it did not declare, and says so in the rendered document with additionalProperties: false. JSON Schema's own default is the opposite, and the default is wrong for this job: a producer that invents a property and is never told keeps inventing it.

Reading a schema this package did not write

Deserialize is the other direction, and FromArray is the same thing from an already-decoded map. It reads a document into the same values the builder produces, so a schema that arrived as JSON is checked by the same Validate as one written in Go.

It reads the subset this package can represent, and every keyword outside it is an error naming the keyword rather than a silent drop. There is no Parse that takes bytes: encoding/json.Unmarshal into a map[string]any is the decoder, and a second one here would be a second answer to what the document says.

Where the types live

The types are the package itself, so the call reads jsonschema.String(). The sub-package hesape/jsonschema/types holds no types and exists only to say so: splitting them out would put half a schema behind a second import path for no gain, and Validate switches over a closed set that has to be declared where it is checked.

Index

Constants

View Source
const Draft = "https://json-schema.org/draft/2020-12/schema"

Draft is the JSON Schema dialect every Document declares.

Variables

This section is empty.

Functions

func Serialize

func Serialize(t Type) (map[string]any, error)

Serialize renders a type as the map form of its schema document.

The document is produced by marshalling the type and decoding the result, so there is one renderer and not two: the map this returns and the bytes encoding/json.Marshal writes cannot disagree about what the schema says. The cost is that a map decoded from JSON holds every number as a float64, so a minLength of 3 reads back as float64(3). Deserialize takes it either way.

The key order the types chose is lost, because a Go map has none. The bytes keep it; marshal the type when the order matters.

AnyOfType renders as anyOf rather than failing: it is a schema this package can both write and check, and refusing to serialize what it can validate would be a document that disagrees with the program.

func Validate

func Validate(schema Type, value any) error

Validate checks a decoded JSON value against a schema.

The value is what encoding/json produces for an any: map[string]any, []any, string, float64, bool or nil. It is checked before a handler runs, which is what lets that handler read a declared field without checking it, and what stops a value nobody declared from reaching application code.

Every problem is reported at once, in the order the schema declares them. A producer told one mistake per attempt spends three attempts on a form it could have filled in on the second.

Types

type AnyOfType

type AnyOfType struct {
	// contains filtered or unexported fields
}

AnyOfType is a value that must satisfy at least one of several schemas.

func AnyOf

func AnyOf(options ...Type) *AnyOfType

AnyOf builds an alternative between whole schemas.

func (*AnyOfType) Description

func (b *AnyOfType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*AnyOfType) MarshalJSON

func (t *AnyOfType) MarshalJSON() ([]byte, error)

MarshalJSON renders the alternatives. A nullable AnyOf carries null as one more alternative, because there is no kind to add it to.

func (*AnyOfType) Nullable

func (b *AnyOfType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*AnyOfType) Options

func (t *AnyOfType) Options() []Type

Options returns the alternatives, in the order given.

func (*AnyOfType) Required

func (b *AnyOfType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*AnyOfType) Title

func (b *AnyOfType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*AnyOfType) ToArray

func (b *AnyOfType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*AnyOfType) ToString

func (b *AnyOfType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

type ArrayType

type ArrayType struct {
	// contains filtered or unexported fields
}

ArrayType is an ordered list.

func Array

func Array() *ArrayType

Array builds an array type. Call Items to say what the elements are; an array with no Items accepts any element.

func (*ArrayType) Default

func (t *ArrayType) Default(v []any) *ArrayType

Default sets the value used when the property is absent.

func (*ArrayType) Description

func (b *ArrayType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*ArrayType) Items

func (t *ArrayType) Items(item Type) *ArrayType

Items sets the schema every element must satisfy.

func (*ArrayType) MarshalJSON

func (t *ArrayType) MarshalJSON() ([]byte, error)

MarshalJSON renders the array, its constraints and its element schema.

func (*ArrayType) Max

func (t *ArrayType) Max(v int) *ArrayType

Max sets the maximum number of elements, inclusive.

func (*ArrayType) Min

func (t *ArrayType) Min(v int) *ArrayType

Min sets the minimum number of elements, inclusive.

func (*ArrayType) Nullable

func (b *ArrayType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*ArrayType) Required

func (b *ArrayType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*ArrayType) Title

func (b *ArrayType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*ArrayType) ToArray

func (b *ArrayType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*ArrayType) ToString

func (b *ArrayType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

func (*ArrayType) Unique

func (t *ArrayType) Unique() *ArrayType

Unique requires the elements to differ from one another.

type BooleanType

type BooleanType struct {
	// contains filtered or unexported fields
}

BooleanType is true or false.

func Boolean

func Boolean() *BooleanType

Boolean builds a boolean type.

func (*BooleanType) Default

func (t *BooleanType) Default(v bool) *BooleanType

Default sets the value used when the property is absent.

func (*BooleanType) Description

func (b *BooleanType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*BooleanType) MarshalJSON

func (t *BooleanType) MarshalJSON() ([]byte, error)

MarshalJSON renders the boolean.

func (*BooleanType) Nullable

func (b *BooleanType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*BooleanType) Required

func (b *BooleanType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*BooleanType) Title

func (b *BooleanType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*BooleanType) ToArray

func (b *BooleanType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*BooleanType) ToString

func (b *BooleanType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

type Document

type Document struct {
	// ID is the address the document is published at. It renders as $id.
	ID string

	// Root is the schema itself. A Document without one is an error.
	Root Type

	// Examples are whole values that satisfy Root. They are the cheapest
	// instruction a producer gets, and worth one.
	Examples []any
}

Document is a schema published on its own: a root type, plus the keywords that let a reader say which dialect it is written in and where it came from.

It renders as one object -- the identity keywords and the root's own keywords side by side -- which is the shape a schema file has:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.test/module.schema.json",
  "type": "object",
  "properties": { ... }
}

Title and description belong to Root. There is one place to write them.

func (Document) MarshalJSON

func (d Document) MarshalJSON() ([]byte, error)

MarshalJSON renders the document. Use encoding/json.MarshalIndent to write it to a file; the indenter reads this output like any other.

type IntegerType

type IntegerType struct {
	// contains filtered or unexported fields
}

IntegerType is a whole number.

func Integer

func Integer() *IntegerType

Integer builds an integer type.

func (*IntegerType) Default

func (t *IntegerType) Default(v int) *IntegerType

Default sets the value used when the property is absent.

func (*IntegerType) Description

func (b *IntegerType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*IntegerType) Enum

func (t *IntegerType) Enum(values ...int) *IntegerType

Enum limits the value to a set.

func (*IntegerType) MarshalJSON

func (t *IntegerType) MarshalJSON() ([]byte, error)

MarshalJSON renders the integer and its constraints.

func (*IntegerType) Max

func (t *IntegerType) Max(v int) *IntegerType

Max sets the maximum value, inclusive.

func (*IntegerType) Min

func (t *IntegerType) Min(v int) *IntegerType

Min sets the minimum value, inclusive.

func (*IntegerType) MultipleOf

func (t *IntegerType) MultipleOf(v int) *IntegerType

MultipleOf requires the value to be a multiple of v.

func (*IntegerType) Nullable

func (b *IntegerType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*IntegerType) Required

func (b *IntegerType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*IntegerType) Title

func (b *IntegerType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*IntegerType) ToArray

func (b *IntegerType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*IntegerType) ToString

func (b *IntegerType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

type Invalid

type Invalid struct {
	Problems []Problem
}

Invalid is the error Validate returns. It carries every problem, so a caller that wants to act on one field can, and a caller that only prints gets the whole answer from Error.

func (*Invalid) Error

func (e *Invalid) Error() string

Error joins every problem into one sentence.

type NumberType

type NumberType struct {
	// contains filtered or unexported fields
}

NumberType is a number, whole or fractional.

func Number

func Number() *NumberType

Number builds a number type.

func (*NumberType) Default

func (t *NumberType) Default(v float64) *NumberType

Default sets the value used when the property is absent.

func (*NumberType) Description

func (b *NumberType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*NumberType) Enum

func (t *NumberType) Enum(values ...float64) *NumberType

Enum limits the value to a set.

func (*NumberType) MarshalJSON

func (t *NumberType) MarshalJSON() ([]byte, error)

MarshalJSON renders the number and its constraints.

func (*NumberType) Max

func (t *NumberType) Max(v float64) *NumberType

Max sets the maximum value, inclusive.

func (*NumberType) Min

func (t *NumberType) Min(v float64) *NumberType

Min sets the minimum value, inclusive.

func (*NumberType) MultipleOf

func (t *NumberType) MultipleOf(v float64) *NumberType

MultipleOf requires the value to be a multiple of v, and renders as the multipleOf keyword.

The check is exact arithmetic on a binary float, and 0.1 is not representable in one: a rule written as MultipleOf(0.01) for money will refuse amounts that are correct. Money is an integer of cents, and IntegerType.MultipleOf is the rule for it. This is here because JSON Schema has the keyword for numbers and a document that carries it has to survive Deserialize and render back unchanged.

func (*NumberType) Nullable

func (b *NumberType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*NumberType) Required

func (b *NumberType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*NumberType) Title

func (b *NumberType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*NumberType) ToArray

func (b *NumberType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*NumberType) ToString

func (b *NumberType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

type ObjectType

type ObjectType struct {
	// contains filtered or unexported fields
}

ObjectType is a value with named properties.

An object refuses a property it did not declare. See the package comment for why that is the default and not a switch.

func Object

func Object(properties ...Property) *ObjectType

Object builds an object from its properties, in the order given.

The properties are taken in order, because a Go map has none and a schema whose properties render differently on two runs is a schema nobody can diff.

The object is closed: additionalProperties renders as false. That is this package's default and not JSON Schema's -- see the package comment. ObjectType.WithoutAdditionalProperties is the same thing said out loud.

func (*ObjectType) Default

func (t *ObjectType) Default(v map[string]any) *ObjectType

Default sets the value used when the property is absent.

func (*ObjectType) Description

func (b *ObjectType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*ObjectType) MarshalJSON

func (t *ObjectType) MarshalJSON() ([]byte, error)

MarshalJSON renders the object, its properties in declaration order, and the names of the properties marked Required.

func (*ObjectType) Nullable

func (b *ObjectType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*ObjectType) Properties

func (t *ObjectType) Properties() []Property

Properties returns the object's properties in declaration order.

It is here so a caller can print or walk a schema without decoding the document it just rendered.

func (*ObjectType) Required

func (b *ObjectType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*ObjectType) Title

func (b *ObjectType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*ObjectType) ToArray

func (b *ObjectType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*ObjectType) ToString

func (b *ObjectType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

func (*ObjectType) WithoutAdditionalProperties

func (t *ObjectType) WithoutAdditionalProperties() *ObjectType

WithoutAdditionalProperties disallows properties the object did not declare. It closes the object: additionalProperties renders as false.

It is already true of every object Object builds, so calling it changes nothing and is not required. It exists so a schema can say it explicitly, and because an object that came back from Deserialize open is closed by exactly this call.

type Problem

type Problem struct {
	// Path is where the problem is, in dotted form: "filters.tag",
	// "tags[2]". It is empty for the value handed to Validate.
	Path string

	// Message is what is wrong with it, as a predicate: "is required",
	// "must be a string".
	Message string
}

Problem is one thing wrong with a value.

func (Problem) String

func (p Problem) String() string

String renders the problem as a sentence.

type Property

type Property struct {
	// Name is the key the value appears under.
	Name string
	// Type is the schema the value must satisfy.
	Type Type
}

Property is one named member of an object.

func Prop

func Prop(name string, t Type) Property

Prop names a property of an object.

type StringType

type StringType struct {
	// contains filtered or unexported fields
}

StringType is a text value.

func String

func String() *StringType

String builds a string type.

func (*StringType) Default

func (t *StringType) Default(v string) *StringType

Default sets the value used when the property is absent.

func (*StringType) Description

func (b *StringType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*StringType) Enum

func (t *StringType) Enum(values ...string) *StringType

Enum limits the value to a set.

It is worth reaching for. A producer given a closed list picks from it, and a producer given "the status" invents one.

func (*StringType) Format

func (t *StringType) Format(v string) *StringType

Format records one of JSON Schema's built-in formats, such as "email" or "date-time".

It is written into the document and is not checked by Validate: JSON Schema itself defines format as an annotation, and a value refused for a reason the published document does not state is worse than one that is not refused.

func (*StringType) MarshalJSON

func (t *StringType) MarshalJSON() ([]byte, error)

MarshalJSON renders the string and its constraints.

func (*StringType) Max

func (t *StringType) Max(v int) *StringType

Max sets the maximum length in characters, inclusive.

func (*StringType) Min

func (t *StringType) Min(v int) *StringType

Min sets the minimum length in characters, inclusive.

func (*StringType) Nullable

func (b *StringType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*StringType) Pattern

func (t *StringType) Pattern(expr string) *StringType

Pattern sets a regular expression the value must match.

It compiles here rather than at validation time, so a broken expression is a panic where it was written instead of a refusal where it was used.

func (*StringType) Required

func (b *StringType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*StringType) Title

func (b *StringType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*StringType) ToArray

func (b *StringType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*StringType) ToString

func (b *StringType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

type Type

type Type interface {
	json.Marshaler
	// contains filtered or unexported methods
}

Type is one node of a schema: the kind a value must have, and the constraints on it.

The set of implementations is closed -- ObjectType, StringType, IntegerType, NumberType, BooleanType, ArrayType, UnionType and AnyOfType. Validate switches on that set, so a ninth shape declared outside this package would be a schema Validate cannot check. The unexported method is what closes it.

func Deserialize

func Deserialize(schema map[string]any) (Type, error)

Deserialize builds a type from the supported JSON Schema subset.

It reads what this package writes, and the part of JSON Schema that maps onto it: the six kinds, the type-as-a-list union, local "$ref" pointers, and the nullable "anyOf"/"oneOf" shape that a generator emits for an optional value. Anything outside that subset is an error naming the keyword, never a silent drop -- a schema that deserializes into something weaker than it says is a validator that passes values the document forbids.

What it cannot keep

Property order. A JSON object has none once decoded into a Go map, and ObjectType renders its properties in declaration order, so the properties of a deserialized object are ordered by name. A document round-tripped through Serialize and back therefore renders with its properties sorted; everything else about it is unchanged.

Objects come back as they were written

Object closes an object because that is this package's default (see the package comment). This does not: an object is closed only when the document says additionalProperties is false, because the job here is to read a schema faithfully rather than to tighten one. ObjectType.WithoutAdditionalProperties closes one that came back open.

func FromArray

func FromArray(schema map[string]any) (Type, error)

FromArray builds a type from a raw map of the supported JSON Schema subset. It delegates to Deserialize.

The map is what encoding/json.Unmarshal produces for an any: every number is a float64 and every object is a map[string]any. Serialize produces the same shape, so a document this package rendered reads back through here.

A schema this package cannot represent is an error naming what it could not read.

type UnionType

type UnionType struct {
	// contains filtered or unexported fields
}

UnionType is a value that may be any of several primitive kinds. It renders as JSON Schema's type-as-a-list form.

It is the short way to write a value that differs only in kind. When the alternatives differ in more than kind -- one has a pattern, the other a minimum -- they are separate schemas and the answer is AnyOf.

func Union

func Union(types ...string) *UnionType

Union builds a union of the named primitive kinds: string, integer, number, boolean, object or array. The name "null" is accepted and marks the union nullable.

An unsupported name panics. A schema is written once, at start-up, and a typo there is a mistake in the program, not in the data. Deserialize reads names out of a document rather than out of a program and gets an error for the same input.

func (*UnionType) Description

func (b *UnionType) Description(v string) T

Description says what the value is for.

It is worth writing on every property. A description is the cheapest thing in the document and it is the only place a producer learns what the program meant by a name.

func (*UnionType) MarshalJSON

func (t *UnionType) MarshalJSON() ([]byte, error)

MarshalJSON renders the union as a list of type names.

func (*UnionType) Nullable

func (b *UnionType) Nullable() T

Nullable allows the value to be null. Without it, an explicit null is refused like any other wrong kind.

func (*UnionType) Required

func (b *UnionType) Required() T

Required marks the property as mandatory. An object missing it is refused before anything reads it.

It is declared on the property's own type and hoisted into the parent object's required list when the document renders, which is where JSON Schema keeps it.

func (*UnionType) Title

func (b *UnionType) Title(v string) T

Title sets the type's title: a short label for the value, for a reader.

func (*UnionType) ToArray

func (b *UnionType) ToArray() (map[string]any, error)

ToArray converts the type to its map form. It delegates to Serialize.

func (*UnionType) ToString

func (b *UnionType) ToString() (string, error)

ToString converts the type to its string representation: the schema document as pretty-printed JSON, indented with four spaces.

It renders the type rather than the map [ToArray] returns, so the keys come out in the order the type declares them: type before properties, and properties in the order they were written. A Go map has no order, which is why the two differ.

func (*UnionType) Types

func (t *UnionType) Types() []string

Types returns the union's member type names, in the order given.

Directories

Path Synopsis
Package types is empty on purpose, and holds no types.
Package types is empty on purpose, and holds no types.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL