graphiti-api/spraypaint.js

Same jsonapiType for 2 resources in two different namespaces throws Uncaught Error

Opened this issue · 5 comments

I have 2 resources in different namespaces with the same base url. When I try and set the jsonapiType for both of these to the same string - my_type in my models, I receive:

Uncaught Error: Type "<my_type>" already registered on base class function Subclass() {
                return _super !== null && _super.apply(this, arguments) || this;

I had a little look and I think it's down to JsonapiTypeRegistry class.

Will be happy to submit a PR.

You should be able to handle this with a separate ApplicationResource - each one gets its own type registry. So If you had ModelA inherit from ApplicationResourceA, and ModelB inherit from ApplicationResourceB, it should work. Let me know how it goes!

Do you mean?

@Model()
class ApplicationRecordA extends SpraypaintBase {
  static baseUrl = "http://localhost:3000"
  static apiNamespace = "/api/v1"
}

@Model()
class Person extends ApplicationRecordA {
  static jsonapiType = "people"

  @Attr() firstName: string
  @Attr() lastName: string

  @HasMany() pets: Pet[]

  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

class ApplicationRecordB extends SpraypaintBase {
  static baseUrl = "http://localhost:3000"
  static apiNamespace = "/api/v1"
}

@Model()
class Pet extends ApplicationRecordB {
  static jsonapiType = "people"

  @Attr() name: string
}

Yes, both models should work...that said, I'm not sure if the relationship would work.

That solution worked! Thanks @richmolj.

Still feels like a workaround and given that we are unsure about the relationships, do you think this could be solved in another way? Luckily, in my current set up, these models don't have any relationships.

Again, happy to put the work in to create a PR.

So, a little background on the thinking here. The id/type combo is meant to uniquely identify records. So let's imagine API1 has employees and tags, API2 has positions and tags.

Imagine a request like "load the employee, their tags, their positions, and the tags in those positions". Our API response could have the resource identifier tags/123 in two places - we wouldn't be able to uniquely identify records.

Spraypaint works by building a registry of Model: type. This way when we look at a response, we don't need to do anything more than say "find the corresponding model for this type and instantiate it". If there are multiple types, we wouldn't be able to do this. It's especially a concern where the client isn't making a request (imagine pushing a JSON:API payload over a websocket, and needing to find the corresponding model instances in memory).

So I think it runs against the JSON:API grain a bit. That said, it's not uncommon and you're not the only user that's asked about this. I typically say that you should prefix the types to be unique, e.g. api2/tags. That said, I'm not against a PR that allows multiple types (if such a thing is possible), but it's likely a significant refactor.