MYMONDAY.ai
서비스스튜디오도구데이터·포맷73CSS 생성기19색상·이미지10인코딩·보안10웹·SEO11개발·데브옵스10파일·내보내기18계산기6가이드

JSON to Go 구조체 변환기

샘플 JSON 객체나 배열을 원래 키를 유지하는 json 태그와 선택 필드 포인터가 있는 Go 구조체로 바꿉니다.

  • 브라우저에서 처리
  • 가입 없음
  • 무료

도구 작업 공간

예제

옵션

포인터를 쓰면 null·누락과 0 값을 구분할 수 있습니다.

omitempty 추가

선택 필드 = 일부 샘플에서 빠진 키만.

JSON 입력

27줄435byte

결과

⌘/Ctrl + Enter로 복사
결과 · payload.go
package models

type Payload struct {
	ID        int             `json:"id"`
	Status    string          `json:"status"`
	Customer  PayloadCustomer `json:"customer"`
	Items     []PayloadItem   `json:"items"`
	Total     float64         `json:"total"`
	ShippedAt string          `json:"shipped_at"`
	Tracking  any             `json:"tracking"`
}

type PayloadCustomer struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
	Vip   bool   `json:"vip"`
}

type PayloadItem struct {
	Sku   string  `json:"sku"`
	Name  string  `json:"name"`
	Qty   int     `json:"qty"`
	Price float64 `json:"price"`
}
타입3
크기630byte

이 JSON to Go 구조체 변환기는 샘플 JSON 값을 읽어 package models 파일 하나에 타입 선언을 작성합니다(패키지 옵션으로 이름을 바꿀 수 있습니다). 중첩 객체는 각각 별도 구조체가 되고, 키는 대문자로 시작하는 PascalCase 필드가 되며, json:"key" 태그가 원래 키 철자를 유지하므로 encoding/json이 페이로드를 그대로 읽고 쓸 수 있습니다. 열 정렬은 gofmt가 출력하는 방식과 같습니다.

배열은 첫 번째 요소만이 아니라 모든 요소를 읽습니다. 같은 위치에 있는 객체를 하나의 구조체로 병합하고, 필드는 모든 요소의 키를 합친 집합이 됩니다. 일부 요소에 없거나 일부에서 null인 키는 포인터가 되고, 일부 요소에 없는 키에는 omitempty도 붙습니다. 이 두 규칙과 루트 타입 이름, 패키지 이름은 페이지의 옵션입니다.

입력은 브라우저 탭 안에서 파싱·변환되며 서버로 전송되지 않습니다. 입력 한도는 20 MiB입니다. 루트는 객체 또는 배열이어야 하고, 문자열·숫자·불리언·null 단독 값은 타입 이름을 붙일 대상이 없어 거부됩니다.

사용 방법

  1. JSON 객체 또는 배열 붙여 넣기

    샘플 페이로드를 붙여 넣거나 예제(API 응답, 중첩 배열, 엣지 케이스) 중 하나를 불러옵니다. 목록은 여러 레코드를 넣고, 값이 빠진 레코드를 하나 이상 포함하세요. 선택 필드는 붙여 넣은 레코드끼리 비교해서 찾기 때문입니다.

  2. 옵션 설정

    루트 타입 이름(기본 Payload)과 패키지(기본 models)를 입력하고, null·누락 필드에 포인터 사용을 켜거나 끄고, omitempty 추가에서 사용 안 함, 선택 필드만, 모든 필드 중 하나를 고릅니다.

  3. 구조체 읽기

    루트 선언이 먼저 나오고 중첩 구조체가 처음 만난 순서대로 이어집니다. 필드는 JSON 키 순서를 따릅니다. 루트가 배열이면 type Payload []PayloadItem 다음에 요소 구조체가 나옵니다.

  4. 복사 또는 다운로드

    코드를 복사하거나 파일로 내려받습니다. 파일 이름은 루트 타입 이름을 스네이크 케이스로 바꾼 것이라 기본값은 payload.go입니다.

  5. 직접 다듬기

    포인터와 omitempty가 API 명세와 맞는지 확인하고, 실제 타입을 아는 any는 구체 타입으로 바꾸고, int와 int64는 도메인에 맞는 폭으로 조정합니다. 시간 값은 string으로 나오므로 time.Time으로 직접 바꿔야 합니다.

작동 원리

JSON 값이 Go 타입이 되는 규칙

변환기는 JSON 숫자의 소수점·지수 표기를 보존한 뒤 같은 위치의 값을 병합합니다. -2147483648부터 2147483647까지의 정수 표기는 int, 그 범위 밖이면서 절댓값 2^63 미만이면 int64, 절댓값 2^63 이상이면 float64입니다. 10.0이나 1e3은 값이 정수여도 float64입니다.

JSON 값Go 타입비고
문자열string
true / falsebool
-2147483648부터 2147483647까지의 정수 표기int플랫폼 크기
그보다 크고 2^63 미만인 정수 표기int64샘플 값으로 결정
소수가 있는 숫자float64[1, 2.5]는 int와 float가 합쳐져 []float64
모든 샘플에서 nullany추론할 정보가 없고 포인터도 없음
다른 값과 함께 나온 null*T포인터 옵션을 켠 경우만, 슬라이스와 any는 제외
객체이름 있는 구조체같은 위치의 모든 객체가 하나로 병합
배열[]T그 위치의 모든 배열의 모든 요소를 병합한 T
빈 배열[]any참고할 요소가 없음
같은 위치에 서로 다른 형태any[1, "a"]는 []any

구조체와 필드 이름 규칙

중첩 구조체 이름은 부모 이름에 키를 이어 붙입니다. 루트의 user는 PayloadUser가 됩니다. 배열 요소는 키의 단수형을 씁니다. items는 PayloadItem, categories는 PayloadCategory, 복수형이 아닌 data는 PayloadDataItem입니다. 이름이 같은 선언이 둘이면 2부터 숫자 접미사가 붙습니다.

필드 이름은 유니코드 문자와 10진 숫자를 유지하고 camelCase 경계와 그 밖의 문자에서 단어를 나눈 뒤 PascalCase로 잇습니다. Go 관례에 맞게 약어는 모두 대문자로 씁니다: acl, api, ascii, cpu, css, dns, eof, guid, html, http, https, id, ip, json, lhs, qps, ram, rhs, rpc, sla, smtp, sql, ssh, tcp, tls, ttl, udp, ui, uid, uri, url, utf8, uuid, vm, xml, xmpp, xsrf, xss. 숫자로 시작하면 Field, 한중일 문자처럼 대소문자가 없는 문자로 시작하면 exported 필드가 되도록 X 접두사가 붙습니다.

user_id    -> UserID    `json:"user_id"`
api_url    -> APIURL    `json:"api_url"`
user-agent -> UserAgent `json:"user-agent"`
2fa        -> Field2fa  `json:"2fa"`

포인터와 omitempty

Go의 일반 필드로는 키가 없는 것과 0 값을 구분할 수 없습니다. 없는 active와 명시적 false가 모두 false로 읽힙니다. 기본 설정에서는 일부 요소에서 null이거나 일부 요소에 없는 스칼라·구조체 필드를 *T로 쓰므로 nil이 누락 또는 null을 뜻합니다. 슬라이스와 any는 이미 nil 상태가 있어서 포인터로 감싸지 않습니다.

omitempty 추가는 세 가지입니다. 사용 안 함은 태그에 아무것도 붙이지 않고, 선택 필드만(기본)은 일부 요소에 없던 키에만 ,omitempty를 붙이며, 모든 필드는 전부에 붙입니다. 포인터가 아닌 구조체 필드에는 omitempty가 효과가 없습니다. encoding/json은 구조체 값을 비어 있다고 보지 않기 때문입니다.

type PayloadItem struct {
	Sku  string `json:"sku"`
	Qty  *int   `json:"qty,omitempty"`
	Note any    `json:"note,omitempty"`
}

실제 예시

문자열 슬라이스가 있는 중첩 객체
입력
{"id":42,"user":{"name":"Ada","active":true},"roles":["admin","editor"]}
출력
package models

type Payload struct {
	ID    int         `json:"id"`
	User  PayloadUser `json:"user"`
	Roles []string    `json:"roles"`
}

type PayloadUser struct {
	Name   string `json:"name"`
	Active bool   `json:"active"`
}

루트 구조체가 먼저 나오고 중첩 구조체가 뒤따릅니다. 필드 이름과 타입은 gofmt처럼 열이 정렬됩니다.

키가 서로 다른 객체 배열
입력
{"items":[{"sku":"A1"},{"sku":"B2","qty":3,"note":null}]}
출력
package models

type Payload struct {
	Items []PayloadItem `json:"items"`
}

type PayloadItem struct {
	Sku  string `json:"sku"`
	Qty  *int   `json:"qty,omitempty"`
	Note any    `json:"note,omitempty"`
}

두 요소를 모두 읽습니다. qty는 두 번째에만 있어 *int와 omitempty가 되고, note는 거기서 null이라 any에 omitempty가 붙습니다.

숫자, null, 빈 배열, 혼합 배열
입력
{"price":19.0,"score":1.5,"big":3000000000,"deleted_at":null,"tags":[],"nums":[1,2.5],"mixed":[1,"a"]}
출력
package models

type Payload struct {
	Price     float64   `json:"price"`
	Score     float64   `json:"score"`
	Big       int64     `json:"big"`
	DeletedAt any       `json:"deleted_at"`
	Tags      []any     `json:"tags"`
	Nums      []float64 `json:"nums"`
	Mixed     []any     `json:"mixed"`
}

19.0은 소수점 표기를 보존해 float64가 됩니다. 3000000000은 32비트에 들어가지 않아 int64입니다. [1, 2.5]는 []float64로 합쳐지고, null·빈 배열·혼합 배열은 any입니다.

필드 이름, 약어, 이름 충돌
입력
{"user_id":7,"api_url":"https://example.com","user-agent":"curl","2fa":true,"first name":"Ada","a_b":1,"aB":2}
출력
package models

type Payload struct {
	UserID    int    `json:"user_id"`
	APIURL    string `json:"api_url"`
	UserAgent string `json:"user-agent"`
	Field2fa  bool   `json:"2fa"`
	FirstName string `json:"first name"`
	AB        int    `json:"a_b"`
	AB2       int    `json:"aB"`
}

user_id는 UserID, api_url은 APIURL이 되고, 숫자로 시작하면 Field 접두사가 붙으며, a_b와 aB는 충돌해 두 번째에 접미사 2가 붙습니다. 태그에는 항상 원래 키가 남습니다.

배열 루트와 옵션
입력
[{"id":1,"name":"Ada"},{"id":2}]
출력
package api

type Users []User

type User struct {
	ID   int    `json:"id,omitempty"`
	Name string `json:"name,omitempty"`
}

옵션: 루트 타입 이름 Users, 패키지 api, 포인터 끔, omitempty 추가는 모든 필드. 배열 루트는 슬라이스 타입과 요소 구조체로 나옵니다. 포인터를 끄면 name은 일반 string이고 비어 있을 때 omitempty로 빠집니다.

자주 하는 실수

  • 샘플 하나로는 항상 있는 필드인지 알 수 없습니다

    일부 요소에 키가 없을 때만 선택 필드로 봅니다. 레코드가 하나뿐이면 모든 필드가 필수처럼 보여서 포인터도 omitempty도 생기지 않습니다. 값이 빠진 레코드를 포함해 여러 개를 붙여 넣거나 API 문서와 대조해 포인터를 확인하세요.

  • 큰 정수는 변환 전에 이미 정밀도를 잃습니다

    타입 추론에서 9007199254740993 같은 ID를 JavaScript 숫자로 바꾸면 9007199254740992로 반올림되지만 필드는 int64로 나옵니다. 2^53을 넘는 정확한 ID는 문자열로 입력하고 실제 페이로드에서 문자열이나 json.Number로 다루세요.

  • 모든 샘플에서 null인 필드에는 타입 정보가 없습니다

    붙여 넣은 모든 레코드에서 deleted_at이 null이면 변환기는 any밖에 쓸 수 없습니다. 실제 타입을 알게 되면 *time.Time 같은 구체 포인터로 바꾸세요.

  • 소수점·지수 표기는 float64가 됩니다

    19.0과 1e3은 값이 정수여도 float64가 됩니다. 19처럼 정수로 적은 값은 int로 남으므로 API가 실제로 보내는 숫자 표기를 샘플에 넣으세요.

  • omitempty가 의미 있는 0 값을 지웁니다

    omitempty 추가를 모든 필드로 하면 0, false, 빈 문자열이 마샬링 때 빠져서 보내는 페이로드가 달라집니다. 선택 필드만을 쓰거나, 0이 의미 있는 곳에는 포인터를 쓰세요.

  • 섞인 형태는 any가 됩니다

    한 레코드에서는 숫자, 다른 레코드에서는 문자열인 키는 any가 되고 디코더가 실행 시점에 float64나 string으로 채웁니다. API를 정리하거나 UnmarshalJSON을 구현한 사용자 타입을 정의하세요.

자주 묻는 질문

배열의 모든 요소를 읽나요?

네. 같은 위치의 모든 객체를 키의 합집합을 가진 구조체 하나로 병합합니다. 일부 요소에 없는 키는 선택 필드가 되고, 같은 키에서 값의 타입이 다르면 any가 됩니다.

포인터와 omitempty는 언제 붙나요?

기본 설정에서는 일부 요소에서 null이거나 일부 요소에 없는 필드가 포인터가 되고, 일부 요소에 없던 필드에는 omitempty도 붙습니다. 슬라이스와 any는 포인터가 되지 않습니다. 포인터 옵션을 끄거나 omitempty 추가를 사용 안 함 또는 모든 필드로 바꾸면 달라집니다.

구조체와 패키지 이름을 바꿀 수 있나요?

네. 루트 타입 이름이 루트 구조체 이름이고 중첩 구조체 이름도 거기서 만들어지므로, Order로 하면 items 목록은 OrderItem이 됩니다. 패키지는 package 줄을 정합니다. 루트 이름은 Go의 공개 이름 형태로 변환됩니다.

숫자가 int, int64, float64 중 무엇이 되나요?

-2147483648부터 2147483647까지의 정수 표기는 int, 그 범위 밖이면서 절댓값 2^63 미만이면 int64, 절댓값 2^63 이상이면 float64입니다. 소수점·지수 표기나 같은 위치의 소수 값도 float64로 만듭니다.

타임스탬프를 인식하나요?

아니요. 날짜 문자열은 string으로 남습니다. 변환기는 형식이 아니라 JSON 타입만 보기 때문입니다. 필요하면 time.Time으로 직접 바꾸세요. encoding/json이 RFC 3339 문자열을 파싱해 줍니다.

출력이 gofmt 형식인가요?

필드 이름, 타입, 태그를 열 맞춰 정렬하고 탭으로 들여써서 이런 선언에 대한 gofmt 출력과 같습니다. 직접 고친 뒤에는 gofmt를 한 번 실행하세요.

입력한 JSON이 어딘가로 업로드되나요?

아니요. 파싱과 변환이 브라우저 안에서 실행되며 입력 한도는 20 MiB입니다.

마지막 업데이트: