I'm designing some protobuf
schemas for a project, what I want is to have independent packages, and a shared package. please see the example below.
// file: shared.proto
syntax = "proto3";
package package.shared;
message Address {
string line = 1;
string city = 2;
string state = 3;
string country = 4;
uint32 zip = 5;
}
// file: invoice.proto
syntax = "proto3";
package package.invoice;
import "./shared.proto";
message Invoice {
// some fields
shared.Address address = 1;
}
// file: customer.proto
syntax = "proto3";
package package.customer;
import "./shared.proto";
message Customer {
// some fields
shared.Address address = 1;
}
I tried the above approach to design what I needed however, it's not working, getting the error Import Error: ./shared.proto is not found or has some error
Right now, I'm duplicating the shared fields with Invoice and Customer as a work around, I will be generating these protobuf
's for TypeScript and Java once complete.
If anyone knows a proper solution, please answer.
Note: This question is not a duplicate question, I tried to find import and shared package-related documents or answers, but still no luck.
Thanks
It is a little gnarly.
Think of protobuf packages like namespaces in your preferred programming language.
Generally, you want to reflect the package structure via the folder structure.
I tend to root my protos in a folder called protos
. I'm using foo
rather than package
because package
is a reserved name and could be problematic:
.
└── protos
└── foo
├── invoice
│ └── invoice.proto
└── shared
└── address.proto
The folder names should match the package (!) path (foo.invoice
, foo.shared
) while the file names generally reflect the message name.
invoice.proto
:
syntax = "proto3";
package foo.invoice;
import "foo/shared/address.proto";
message Invoice {
foo.shared.Address address = 1;
}
Invoice
in package foo.invoice
must reference Address
by its fully-qualified package name foo.shared.Address
.
address.proto
:
syntax = "proto3";
package foo.shared;
message Address {
string line = 1;
string city = 2;
string state = 3;
string country = 4;
uint32 zip = 5;
}
Then, using protoc
:
protoc \
--proto_path=${PWD}/protos \
--java_out=${PWD} \
${PWD}/protos/foo/shared/address.proto \
${PWD}/protos/foo/invoice/invoice.proto
Because we've a single root (${PWD}/protos
) for the protos we're using, we can using a single --proto_path=${PWD}/protos
to anchor the set.
It's necessary to fully specify the path (including the root) to each of the protos that we want to compile.
Produces:
.
├── foo
│ ├── invoice
│ │ └── InvoiceOuterClass.java
│ └── shared
│ └── AddressOuterClass.java
└── protos
└── foo
├── invoice
│ └── invoice.proto
└── shared
└── address.proto