Is there a way to add GraphQL type descriptions to a GraphQL Schema used by AppSync?
ApolloServer and graphql-js support this with comments in the schema file (see here ). Is there something similar for AppSync so I can use GraphQL type introspection to see field descriptions?
You should be able to do this with a comment just over the type (note that it must be the line immediately before). It might look like this:
# A comment on a post.
type Comment {
id: ID!
content: String
}
Related
TL;DR: Is there a doc somewhere online that fully explains the syntax of GitHub REST API URL templates?
Making a simple GET https://api.github.com/ request, I get a collection of URLs in response, e.g. (excerpt):
{
"current_user_url": "https://api.github.com/user",
"user_url": "https://api.github.com/users/{user}",
"gists_url": "https://api.github.com/gists{/gist_id}",
"user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
"user_search_url": "https://api.github.com/search/users?q={query}{&;amp;page,per_page,sort,order}",
"label_search_url": "https://api.github.com/search/labels?q={query}&;amp;repository_id={repository_id}{&page,per_page}"
}
I can surely make some guesses about how to interpret some parts of the syntax:
{user} in /users/{user} is a required path parameter;
{/gist_id} is an optional path parameter;
{?type,page,per_page,sort} is a list of query parameters (unordered, all optional);
etc.
… but it feels wrong to guess, and I couldn't find any explanation of this syntax on the Internet.
Can somebody help me understand, what are the constructs of this syntax and how to parse it?
I'm having trouble documenting optional response fields with Spring Docs.
My test code:
mockMvc.perform(get("/foo").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("foo", responseFields(
fieldWithPath("success").description("Indicates request successful or not."),
fieldWithPath("message").description("Message.").optional()
)));
My response:
{
"success" : true
}
The error:
org.springframework.restdocs.payload.FieldTypeRequiredException:
Cannot determine the type of the field 'message' as it is not present
in the payload. Please provide a type using
FieldDescriptor.type(Object type).
Spring REST Docs documentation states (https://docs.spring.io/spring-restdocs/docs/2.0.5.RELEASE/reference/html5/#documenting-your-api-request-response-payloads-fields)
Similarly, the test also fails if a documented field is not found in
the payload and the field has not been marked as optional.
So what am I doing wrong?
While the message field is marked as optional, REST Docs still wants to document it for you. Part of that documentation is the field's type. The field's missing from the response so REST Docs can't guess it automatically. Instead, you need to tell it using the type method:
fieldWithPath("message").description("Message.").optional().type(JsonFieldType.STRING)
Edit: I implemented below, published it to GitHub for a user auth.
Edit based on comment: Can a DTO file be replaced by the classes that #nestjs/graphql generates based on GraphQL types? Can I create a NestJS / MongoDB / Mongoose / GraphQL app by generating these classes, then extending them for my MongoDB Schema. Then, after this question, any best practices opinions are welcomed, but the answer will be accepted that answers the above. Below is the original post:
What is the best way to describe a user model? Is it to define the graphQL types and use that to generate classes to replace dto files and import into Mongoose for the MongoDB schema? Below I'll explain what I'm doing, and what may work better. The number of files I have repeating myself doesn't seem to be scalable.
Here are the many ways I describe the same user:
users.types.graphql - GraphQL types, which contains create user inputs, update user inputs, etc. It contains things such as:
type Mutation {
createUser(createUserInput: CreateUserInput): User
}
input CreateUserInput {
username: String
email: String
password: String
}
type User {
_id: String!
username: String
email: String
password: String
}
user.interfaces.ts - Describes the user type, used by MongoDB Schema and my user.service.ts which contains:
export interface IUser {
email: string;
password: string;
username: string;
}
user.schema.ts - MongoDB Schema. Describes a user to Mongoose. It also extends the user interface in user.interfaces.ts and Document to expose instance methods for strict type checking (I can add .checkPassword to an IUserDocument):
export interface IUserDocument extends IUser, Document {
checkPassword(
password: string,
callback: (error?: Error, same?: boolean) => any,
): void;
}
export const UserSchema: Schema = new Schema(....
UserSchema.pre<IUserDocument>('save', function(next) {
UserSchema.methods.checkPassword = function(....
create-user.dto.ts and all kinds of dtos for each operation. These seem redundant with my GraphQl types file with describing inputs above. Here is a dto:
export class CreateUserDto {
readonly email: string;
readonly password: string;
readonly username: string;
}
I'm wondering what the best practice is to have one truth data to my user models. I'm thinking:
Use
GraphQLModule.forRoot({
definitions: {
path: join(process.cwd(), 'src/graphql.classes.ts'),
outputAs: 'class',
},
And use that for my interfaces and my dto files since it outputs:
export class CreateUserInput {
username?: string;
email?: string;
password?: string;
}
export class User {
_id: number;
username?: string;
email?: string;
password?: string;
}
Would dto files even be needed then? Does it matter they aren't readonly? Can I split up these classes into my respective folders (Users into user folder, products into products folder) automatically?
I'll post a public GitHub link when I'm done with a cookie cutter NestJS, MongoDB, Passport-JWT, GraphQL backend with user authentication so people have a reference (there is one out there that uses DTOs).
I stumbeld over your question having similar issues setting up some nest.js/graphQL/mongoose kind of API.
Coming from a laravel/REST/SQL background I was very annoyed with the redundancy and have no idea of how to build up some kind of generic CRUD standard, where adding new resources would be easy and fast e.g. using a node script to create the boilerplate code etc.
So one could focus on implementing the "new" functionalities instead of writing tons of code for always the same stuff.
I took a look into your GitHub project and it seems to me you already have optimized this in a way (e.g. user.schema is both for mongoose and graphql)? I started using the code first approach concerning graphQL but I think you are following the schema first approach there?
Would be very interested in exchanging some thoughts about that topic as there is not much to be found here or somewhere else concerning nest.js!
Is it possible to use annotations (at field-level) to provide description for fields?
I know I can use description method for that
.andDo(document("index", responseFields(
fieldWithPath("contact").description("The user's contact details"),
but I would prefer to put that description together with field definition, in my response object.
class IndexResponse {
//The user's contact details
String contract;
}
I know that I could have generated constraint descriptions (http://docs.spring.io/spring-restdocs/docs/current/reference/html5/#_using_constraint_descriptions_in_generated_snippets) but it generated description only for validation annotations.
I am looking for something like https://github.com/swagger-api/swagger-core/wiki/Annotations#apimodelproperty from Swagger.
It doesn't. I'm the lead of the REST Docs project and it's my opinion that annotations aren't a good way to write documentation. If you disagree with that opinion and want to use annotations, you could write an add-on that's similar to what's done from constraint descriptions. You could pass it a class to introspect and automatically generate FieldDescriptor instances that you can then pass into the request and response field snippets.
We built an extension to Spring REST Docs that allows using Javadoc for field descriptions:
class IndexResponse {
/**
* The user's contact details
*/
String contract;
}
But currently this only works if Jackson and MockMvc tests are used.
Project: https://github.com/ScaCap/spring-auto-restdocs
An introduction article: https://dzone.com/articles/introducing-spring-auto-rest-docs
I've implemented a REST/CRUD backend by following this article as an example: http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/ . I have MongoDB running locally, I'm not using MongoLabs.
I've followed the Google tutorial that uses ngResource and a Factory pattern and I have query (GET all items), get an item (GET), create an item (POST), and delete an item (DELETE) working. I'm having difficulty implementing PUT the way the backend API wants it -- a PUT to a URL that includes the id (.../foo/) and also includes the updated data.
I have this bit of code to define my services:
angular.module('realmenServices', ['ngResource']).
factory('RealMen', function($resource){
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT'},
remove: {method:'DELETE'}
});
I call the method from this controller code:
$scope.change = function() {
RealMen.update({entryId: $scope.entryId}, function() {
$location.path('/');
});
}
but when I call the update function, the URL does not include the ID value: it's only "/realmen", not "/realmen/ID".
I've tried various solutions involving adding a "RealMen.prototype.update", but still cannot get the entryId to show up on the URL. (It also looks like I'll have to build the JSON holding just the DB field values myself -- the POST operation does it for me automatically when creating a new entry, but there doesn't seem to be a data structure that only contains the field values when I'm viewing/editing a single entry).
Is there an example client app that uses all four verbs in the expected RESTful way?
I've also seen references to Restangular and another solution that overrides $save so that it can issue either a POST or PUT (http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/). This technology seems to be changing so rapidly that there doesn't seem to be a good reference solution that folks can use as an example.
I'm the creator of Restangular.
You can take a look at this CRUD example to see how you can PUT/POST/GET elements without all that URL configuration and $resource configuration that you need to do. Besides it, you can then use nested resources without any configuration :).
Check out this plunkr example:
http://plnkr.co/edit/d6yDka?p=preview
You could also see the README and check the documentation here https://github.com/mgonto/restangular
If you need some feature that's not there, just create an issue. I usually add features asked within a week, as I also use this library for all my AngularJS projects :)
Hope it helps!
Because your update uses PUT method, {entryId: $scope.entryId} is considered as data, to tell angular generate from the PUT data, you need to add params: {entryId: '#entryId'} when you define your update, which means
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT', params: {entryId: '#entryId'}},
remove: {method:'DELETE'}
});
Fix: Was missing a closing curly brace on the update line.
You can implement this way
$resource('http://localhost\\:3000/realmen/:entryId', {entryId: '#entryId'}, {
UPDATE: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId' },
ACTION: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId/action' }
})
RealMen.query() //GET /realmen/
RealMen.save({entryId: 1},{post data}) // POST /realmen/1
RealMen.delete({entryId: 1}) //DELETE /realmen/1
//any optional method
RealMen.UPDATE({entryId:1}, {post data}) // PUT /realmen/1
//query string
RealMen.query({name:'john'}) //GET /realmen?name=john
Documentation:
https://docs.angularjs.org/api/ngResource/service/$resource
Hope it helps