Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Representing a list at the root of the output #2270

Closed
SimeonYovchev opened this issue May 2, 2024 · 8 comments
Closed

Representing a list at the root of the output #2270

SimeonYovchev opened this issue May 2, 2024 · 8 comments

Comments

@SimeonYovchev
Copy link

SimeonYovchev commented May 2, 2024

I am encountering an issue with representing a list at the root of the output. I have an API endpoint that returns an array of users like this:
[{ id: 1, name: 'A' }, { id: 2, name: 'B' }]
I am trying to build a model to handle this scenario
I have the following model:

@restJson1
service MyService {
    version: "1.0.0"
    operations: [
        GetUsersList
    ]
}

@readonly
@http(method: "GET", uri: "/api/users", code: 200)
operation GetUsersList {
    input := {
        @httpQuery("permissions")
        permissions: String
        @httpQuery("show_inactive")
        show_inactive: Boolean
    }
    output := {
        @httpPayload
        content: UserListContent
    }
}

structure UserListContent {
    list: UserList
}

list UserList {
    member: User
}

structure User {
    id: String
    name: String
}

When I try to call getUsersList operation I get the following error:
TypeError: Expected object, got array

How can I solve this?

@haydenbaker
Copy link
Contributor

haydenbaker commented May 8, 2024

Looks like you're using restJson1 which has the following caveat given here:

This protocol only permits the httpPayload trait to be applied to members that target structures, documents, strings, blobs, or unions.

@kubukoz
Copy link
Contributor

kubukoz commented May 8, 2024

output := {
        @httpPayload
        content: UserList
    }

do this instead, get rid of UserListContent and you should be all set. If not, I would suggest you post more detail, ideally a complete reproduction such as a github repo.

@kubukoz
Copy link
Contributor

kubukoz commented May 8, 2024

Looks like you're using restJson1 which has the following caveat given here:

This protocol only permits the httpPayload trait to be applied to members that target structures, documents, strings, blobs, or unions.

oh, I didn't know about that part. So yeah, my advice won't help 😓 I suppose it'll just fail validation due to targetting a list shape.

@haydenbaker
Copy link
Contributor

haydenbaker commented May 8, 2024

While it's not as straightforward (and not exactly what you're desiring), if you adjust your model as @kubukoz said, you can try modifying your server to return a payload like { "content": [{ "id": 1, "name": "A" }, { "id": 2, "name": "B" }]}, you should see that it works.

@SimeonYovchev
Copy link
Author

SimeonYovchev commented May 9, 2024

Thanks for reaching out @haydenbaker @kubukoz. Is it possible to achieve the desired result using some other protocol? If yes, could you suggest me one?

One other question:
Today I tried to use simpleRestJson protocol and changed the model to this:

use alloy#simpleRestJson

@simpleRestJson
service MyService {
    version: "1.0.0"
    operations: [
        GetUsersList
    ]
}

My smithy-build.json file looks like this:

{
  "version": "1.0",
  "sources": ["model"],
  "maven": {
    "dependencies": [
      "software.amazon.smithy:smithy-aws-traits:1.48.0",
      "software.amazon.smithy.typescript:smithy-aws-typescript-codegen:0.19.0",
      "com.disneystreaming.alloy:alloy-core:0.3.7"
    ]
  },
  "plugins": {
    "typescript-codegen": {
      "package": "@my-api/client",
      "packageVersion": "0.0.1"
    }
  }
}

but when I run smithy build I got the following warning in the terminal:

[WARNING] Unable to find a protocol generator for pdapi#PlantDemandService: The pdapi#PlantDemandService service supports the following unsupported protocols [alloy#simpleRestJson]. The following protocol generators were found on the class path: [aws.protocols#restXml, aws.protocols#ec2Query, aws.protocols#awsJson1_1, aws.protocols#awsQuery, aws.protocols#awsJson1_0, aws.protocols#restJson1]

When I open one of generated typescript commands, the serializer and deserializer methods don't have any implementation, just throws an error:

private serialize(
    input: GetUsersListCommandInput,
    context: __SerdeContext
  ): Promise<__HttpRequest> {
    throw new Error("No supported protocol was found");
  }
  
  private deserialize(
    output: __HttpResponse,
    context: __SerdeContext
  ): Promise<GetUsersListCommandOutput> {
    throw new Error("No supported protocol was found");
  }

Do you have any idea why this happens?
Thanks!

@kubukoz
Copy link
Contributor

kubukoz commented May 9, 2024

I think simpleRestJson doesn't have a Typescript implementation, at least not a public one.

@haydenbaker
Copy link
Contributor

You can try the other JSON protocols given in the error message. However, your best bet is to change the server response.

@kstich
Copy link
Contributor

kstich commented Jun 3, 2024

Closing due to inactivity and having proposed solutions. Please reopen if you need additional assistance.

@kstich kstich closed this as completed Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants