aws-amplify / aws-amplify/amplify-android

Ability to use existing GraphQl Api without @model annotation

Open
#2,685 1 comment 1 reaction 0 assignees View on GitHub
api feature-request
Dominant language
Java
Stars
287
Forks
132
Avg merge
2d 2h
Merged PRs (30d)
45

Description

### Before opening, please confirm:

- [X] I have [searched for duplicate or closed issues](https://github.com/aws-amplify/amplify-android/issues?q=is%3Aissue+) and [discussions](https://github.com/aws-amplify/amplify-android/discussions).

### Language and Async Model

Kotlin - Coroutines

### Amplify Categories

GraphQL API

### Gradle script dependencies

```
// Amplify API and Datastore dependencies
implementation("com.amplifyframework:core:2.14.6")
implementation("com.amplifyframework:aws-api:2.14.6")
implementation("com.amplifyframework:core-kotlin:2.14.6")

```

### Environment information

```
# Put output below this line

------------------------------------------------------------
Gradle 8.2
------------------------------------------------------------

Build time: 2023-06-30 18:02:30 UTC
Revision: 5f4a070a62a31a17438ac998c2b849f4f6892877

Kotlin: 1.8.20
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 17.0.7 (JetBrains s.r.o. 17.0.7+0-17.0.7b1000.6-10550314)
OS: Mac OS X 14.2.1 aarch64

### Please include any relevant guides or documentation you're referencing

https://docs.amplify.aws/android/build-a-backend/graphqlapi/set-up-graphql-api/

```

### Describe the feature request

Currently Amplify SDK only supports generated code for @model type. e.g., Todo is a @model class, hence Amplify is generating ModelMutation or ModelQuery class (Todo implements Model)

```
val todo = Todo.builder()
.name("My first todo")
.description("todo description")
.build()
try {
val response = Amplify.API.mutate(ModelMutation.create(todo))
Log.i("MyAmplifyApp", "Added Todo with id: ${response.data.id}")
} catch (error: ApiException) {
Log.e("MyAmplifyApp", "Create failed", error)
}

//generated Todo Class
@ModelConfig(pluralName = "Todos")
public final class Todo implements Model {
......

```

But I have an existing endpoint, which does NOT contain @model annotation to its types. So, generated class does not contain any ModelQuery or ModelMutation class.
```

// Generated class does not implement Model
public final class Car23 {
..

```

To use `Amplify.API.query`, client code has to create SimpleGraphQl request using custom query and, which works, but getting complicated and lots of boilerplate code. see [here](https://github.com/aws-amplify/amplify-android/issues/2574)

```
private fun getCar(id: String) : GraphQLRequest {
val document = "query GetCar23(\$id: String!) {\n" +
" getCar23(id: \$id) {\n" +
" id\n" +
" name\n" +
" }\n" +
"}"

return SimpleGraphQLRequest(
document,
mapOf("id" to id),
String::class.java,
GsonVariablesSerializer()
)
}

=============================================

val response = Amplify.API.query(getCar("some_id))
val gson = Gson()
val graphqlResponse = gson.fromJson(response.data, Car::class.java)

```
However Aws App Sync [SDK](https://github.com/awslabs/aws-mobile-appsync-sdk-android) has the ability to generate all query/mutation/subscription classes, and client App does not require to create a custom query or boilerplate code. It is quite easy to use. Since it is advised to use Amplify SDK instead of Aws App Sync SDK, it would be great if Amplify SDK also has the same ability.

### Initialization steps (if applicable)

_No response_

### Code Snippet

```Kotlin
// Put your code below this line.

// Expecting GetCarQuery is a generated class by the Amplify SDK
val response = Amplify.API.query(GetCarQuery("some_id")

or
// Expecting CarCreationMutation is a generated class by the Amplify SDK
val response = Amplify.API.mutate(CarCreationMutation.create(car))
```

### amplifyconfiguration.json
```
{
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"api": {
"plugins": {
"awsAPIPlugin": {
"todo": {
"endpointType": "GraphQL",
"endpoint": "https://***********.appsync-api.eu-west-2.amazonaws.com/graphql",
"region": "eu-west-2",
"authorizationType": "API_KEY",
"apiKey": "da2-***********"
}
}
}
}
}

```
### GraphQL Schema

```graphql
schema {
query: Query
mutation: Mutation
subscription: Subscription
}

type Car23 {
id: String
name: String
}

type Car23Connection {
items: [Car23]
nextToken: String
}

type Mutation {
createCar23(input: CreateCar23Input!): Car23
deleteCar23(input: DeleteCar23Input!): Car23
updateCar23(input: UpdateCar23Input!): Car23
}

type Query {
getCar23(id: String!): Car23
listCar23s(filter: TableCar23FilterInput, limit: Int, nextToken: String): Car23Connection
}

type Subscription {
onCreateCar23(id: String, name: String): Car23 @aws_subscribe(mutations : ["createCar23"])
onDeleteCar23(id: String, name: String): Car23 @aws_subscribe(mutations : ["deleteCar23"])
onUpdateCar23(id: String, name: String): Car23 @aws_subscribe(mutations : ["updateCar23"])
}

input CreateCar23Input {
name: String
}

input DeleteCar23Input {
id: String!
}

input ModelSizeInput {
between: [Int]
eq: Int
ge: Int
gt: Int
le: Int
lt: Int
ne: Int
}

input TableBooleanFilterInput {
attributeExists: Boolean
eq: Boolean
ne: Boolean
}

input TableCar23FilterInput {
id: TableStringFilterInput
name: TableStringFilterInput
}

input TableFloatFilterInput {
attributeExists: Boolean
between: [Float]
eq: Float
ge: Float
gt: Float
le: Float
lt: Float
ne: Float
}

input TableIDFilterInput {
attributeExists: Boolean
beginsWith: ID
between: [ID]
contains: ID
eq: ID
ge: ID
gt: ID
le: ID
lt: ID
ne: ID
notContains: ID
size: ModelSizeInput
}

input TableIntFilterInput {
attributeExists: Boolean
between: [Int]
eq: Int
ge: Int
gt: Int
le: Int
lt: Int
ne: Int
}

input TableStringFilterInput {
attributeExists: Boolean
beginsWith: String
between: [String]
contains: String
eq: String
ge: String
gt: String
le: String
lt: String
ne: String
notContains: String
size: ModelSizeInput
}

input UpdateCar23Input {
id: String!
name: String
}

```

### Additional information and screenshots

_No response_

Contributor guide

Open the contributing guide

Research direction

The issue does not name repository files or tests. Start by reviewing the existing GraphQL code-generation flow and Amplify.API request APIs, then determine how schemas without @model should expose generated query, mutation, and subscription classes. Done means an existing GraphQL endpoint can be used without handwritten query boilerplate.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, graphql, kotlin
Domain
api, developer-experience
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.