Go Module 17
JSON: encoding/json and encoding/json/v2 interview questions
Interview questions on “JSON: encoding/json and encoding/json/v2”: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between omitempty and omitzero?
Answered in the lesson JSON with encoding/json: tags, omitzero, streams
-
Mid
How do encoding/json/v2 and encoding/json/jsontext relate to encoding/json in Go 1.27?
Answered in the lesson JSON v2 in Go 1.27: encoding/json/v2 and jsontext
-
Fresher
Do you have to change code from encoding/json to encoding/json/v2 when you upgrade to Go 1.27?
Answered in the lesson Migrating a service from JSON v1 to v2 safely
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A bookings API returns cancelled_at set to the zero time, the year 1, for every active booking, and a partner's dashboard now shows them all as cancelled. The field is a time.Time tagged omitempty. Explain the cause, choose a fix, and say what the fix changes for clients that already read the field.
- What it tests
- Knowing why omitempty never drops a struct, choosing between omitzero and a pointer field, and treating a key that disappears from a response as a change to the API's contract.
- First step
- Reproduce it in a test: marshal an active booking and look for cancelled_at in the bytes. Then explain that time.Time is a struct, which omitempty never treats as empty, so the zero instant is written. Decide what an absent key should mean to clients before you change the tag.
- Follow-ups
-
- When would you use a *time.Time field instead of omitzero?
- How do you roll the fix out to clients that read the year-1 value today?
- What does Unmarshal leave in the field when cancelled_at is absent, and when it is null?
From the lesson JSON with encoding/json: tags, omitzero, streams
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A payment webhook decodes partner requests with json.NewDecoder(r.Body).Decode(&ev). One partner misspelt amount for weeks and the handler saw 0; another sent two JSON objects in one body. How do you make decoding strict, and how do you switch it on without breaking partners?
- What it tests
- Knowing what Decode accepts by default, DisallowUnknownFields, a second Decode that must return io.EOF, a limit on the body, the difference between shape and validation, and an observe-first rollout.
- First step
- Write down what the handler accepts today: unknown keys are skipped, only the first value is read and names match in any case. Add tests with the misspelt key and with two objects in one body, watch both pass on the current code, then change the decoder until both fail.
- Follow-ups
-
- Why is Decoder.More not a check for trailing data?
- How do you find the requests that strict decoding would refuse before you refuse any?
- What can a strict decoder built on encoding/json still not refuse?
From the lesson JSON with encoding/json: tags, omitzero, streams
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An API gateway reads the role member of a JSON body to decide whether a request may continue, then forwards the same bytes to a Go service that decodes them with encoding/json. Why can the two disagree about one body, and how do you make sure they cannot?
- What it tests
- Recognising parser differentials, such as names written twice, matching that ignores case and invalid UTF-8, and closing them by refusing ambiguous bodies and by letting one parse decide.
- First step
- List the inputs two parsers may read differently, starting with a body that names role twice and one that writes Role in capitals. Write a test that sends each to both sides and fails when they disagree, and run it before you change anything.
- Follow-ups
-
- What does encoding/json/v2 refuse by default, and which of these cases does that close?
- How do you protect the service while the gateway still uses another parser?
- Why is forwarding the gateway's own encoding stronger than validating the original bytes?
From the lesson JSON v2 in Go 1.27: encoding/json/v2 and jsontext
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid
A service's config struct has Timeout time.Duration, and its JSON files hold numbers such as 30000000000. After a move to encoding/json/v2, Marshal fails with "no default representation". What are the options, which do you choose for files people edit, and how do the existing files keep loading?
- What it tests
- Knowing why v2 refuses durations, the choice between v1's nanoseconds and a form set with a marshaler, reading two formats during a transition, and tests that pin both.
- First step
- Find every Duration that reaches JSON with a test that marshals each config type under v2 and fails on the error. Then choose the format by who reads the files: people want "30s", programs written for v1 want nanoseconds.
- Follow-ups
-
- Why does v2 refuse to choose a format for time.Duration?
- How does the reader accept both the old numbers and the new strings?
- Where do you register the marshalers so that no call forgets them?
From the lesson JSON v2 in Go 1.27: encoding/json/v2 and jsontext
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A nightly job reads a 2 GB JSON array of transactions with json.Unmarshal into a slice and is killed for running out of memory. Rewrite it with encoding/json/jsontext so that memory stays flat, every bad record is reported with its position, and one bad record does not stop the run.
- What it tests
- Streaming an array with ReadToken, PeekKind and ReadValue or UnmarshalDecode, telling semantic from syntactic errors, reporting JSON Pointers and byte offsets, and measuring memory before and after.
- First step
- Measure first: run the job on a sample of known size and record its peak memory. Then replace the single Unmarshal with a loop that reads the opening bracket, takes one element at a time, processes it and only then reads the next.
- Follow-ups
-
- Should the loop decode each record straight from the stream, or read it as raw JSON first?
- Which errors may the job skip, and which must stop it?
- How do you show that memory no longer grows with the input?
From the lesson JSON v2 in Go 1.27: encoding/json/v2 and jsontext
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
Plan the move of a public booking API, 40 endpoints used by mobile apps that update slowly, from encoding/json to encoding/json/v2. Which strategy do you choose, in what order do you remove the compatibility options, and what evidence lets you remove each one?
- What it tests
- Choosing between the three strategies, starting from DefaultOptionsV1, finding the options the API depends on, golden contract tests, a sampled comparison in production, and changelogs for changes clients can see.
- First step
- Upgrade the toolchain first and change no call, so that any problem belongs to the new implementation alone. Then move every call to v2 with DefaultOptionsV1 behind one helper, prove with golden tests that the bytes did not change, and only then start removing options.
- Follow-ups
-
- How do you find which of DefaultOptionsV1's options the API depends on?
- Which options go first, and which last?
- What goes into the API's changelog when an option is removed?
From the lesson Migrating a service from JSON v1 to v2 safely
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After a service moves from Go 1.26 to Go 1.27 with no code change, a test that compares a json.Unmarshal error message fails, and a partner's error parser breaks. What changed, how do you confirm it, and what do you do now and later?
- What it tests
- Knowing that encoding/json runs on v2 since Go 1.27 and that its error text may differ, confirming the cause with a GOEXPERIMENT=nojsonv2 build, and replacing text comparisons with errors.As and fields.
- First step
- Run the failing test on two builds, the Go 1.27 default and one with GOEXPERIMENT=nojsonv2. If only the default fails, the difference comes from the implementation underneath encoding/json, not from the service's code.
- Follow-ups
-
- Which parts of an UnmarshalTypeError should a test rely on?
- Is a GOEXPERIMENT=nojsonv2 build a fix?
- What should the partner's parser read instead of the message?
From the lesson Migrating a service from JSON v1 to v2 safely
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After a package switched to encoding/json/v2, its golden-file tests fail on some runs and pass on others, and a response cache keyed by a hash of the body almost never hits. What causes both, and how do you fix them?
- What it tests
- Knowing how map key order differs between v1 and v2, the option that fixes it, comparing canonical forms in tests, and what a cache key should be built from.
- First step
- Run the failing test ten times with -count=10 and compare two failing outputs: the same members appear in another order. Then find which values in the response are maps, because only their keys change places.
- Follow-ups
-
- Which option fixes the order, and what does it cost?
- When is comparing canonical forms better than fixing the order?
- What else in v2's output or errors can differ from run to run?
From the lesson Migrating a service from JSON v1 to v2 safely
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes