-
Notifications
You must be signed in to change notification settings - Fork 15
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
Hawaii throws: Unhandled exception. Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: D. Path '', line 0, position 0. #38
Comments
HI @abelbraaksma thanks for filing the issue, not being able to parse the JSON suggests that the JSON is malformed which you can get if you are not referencing the RAW file contents from github when pointing the schema configuration at it I will have a look when I can, right now only with access to my phone |
@abelbraaksma This is what I meant, the following works for me using latest Hawaii v0.60.0 {
"schema": "https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json",
"project": "StripeAutogen",
"output": "./output",
"target": "fsharp",
"synchronous": true,
"asyncReturnType": "async",
"resolveReferences": false,
"emptyDefinitions": "ignore"
} The project is generated successfully but unfortunately it doesn't compile. Stripe has a really complex API and uses This is definitely another issue though I want to get Hawaii to the point where everything it generates, at least compiles and not generate things that are not supported yet |
@Zaid-Ajaj, thanks for getting back to me so quickly! I tried to read the let getSchema(schema: string) (overrideSchema: JToken option) =
let schemaContents =
if File.Exists schema && schema.EndsWith ".json" then
let content = File.ReadAllText schema
JObject.Parse(content)
elif File.Exists schema && schema.EndsWith ".xml" then
Console.WriteLine "Detected local OData schema"
let openApiJson = readLocalODataSchema schema
JObject.Parse openApiJson
elif schema.StartsWith "http" && schema.EndsWith "$metadata" then
Console.WriteLine "Detected external OData schema"
let openApiJson = readExternalODataSchema schema
JObject.Parse openApiJson
elif schema.StartsWith "http" then
let content =
client.GetStringAsync(schema)
|> Async.AwaitTask
|> Async.RunSynchronously
JObject.Parse(content)
else
// assume the schema is coming in as a string
// convert it into a memory stream
// this is useful for unit tests
JObject.Parse(schema) From this, I found that:
So, I tried with the following to circumvent the file-extension restriction: elif File.Exists schema then
// another file that is not `.json` or `.xml`, assume yaml or json with a different extension
let content = File.ReadAllText schema
JObject.Parse(content) which allowed it to parse the local file correctly. Now I have the same results as you. Your config worked because you referenced the online file. Mine didn't work because I started out playing with I may issue a PR with a few changes in the function so that the user feedback is a little better in case it falls through to the |
I also noted that it can't process everything of Stripe. It's not just the # apologies this is yaml, but it is slightly more readable than JSON,
# which I ended up using for generating the code
get:
description: "<p>Returns a list of people associated with the account’s legal
entity. The people are returned sorted by creation date, with the most recent
people appearing first.</p>"
operationId: GetAccountPeople
parameters:
- description: A cursor for use in pagination. `ending_before` is an object
ID that defines your place in the list. For instance, if you make a list
request and receive 100 objects, starting with `obj_bar`, your subsequent
call can include `ending_before=obj_bar` in order to fetch the previous
page of the list.
in: query
name: ending_before
required: false
schema:
maxLength: 5000
type: string
style: form
- description: Specifies which fields in the response should be expanded.
explode: true
in: query
name: expand
required: false
schema:
items:
maxLength: 5000
type: string
type: array
style: deepObject
- description: A limit on the number of objects to be returned. Limit can range
between 1 and 100, and the default is 10.
in: query
name: limit
required: false
schema:
type: integer
style: form
- description: Filters on the list of people returned based on the person's
relationship to the account's company.
explode: true
in: query
name: relationship
required: false
schema:
properties:
director:
type: boolean
executive:
type: boolean
owner:
type: boolean
representative:
type: boolean
title: all_people_relationship_specs
type: object
style: deepObject
- description: A cursor for use in pagination. `starting_after` is an object
ID that defines your place in the list. For instance, if you make a list
request and receive 100 objects, ending with `obj_foo`, your subsequent
call can include `starting_after=obj_foo` in order to fetch the next page
of the list.
in: query
name: starting_after
required: false
schema:
maxLength: 5000
type: string
style: form
requestBody:
content:
application/x-www-form-urlencoded:
encoding: {}
schema:
additionalProperties: false
properties: {}
type: object
required: false
responses:
'200':
content:
application/json:
schema:
description: ''
properties:
data:
items:
"$ref": "#/components/schemas/person"
type: array
has_more:
description: True if this list has another page of items after
this one that can be fetched.
type: boolean
object:
description: String representing the object's type. Objects of
the same type share the same value. Always has the value `list`.
enum:
- list
type: string
url:
description: The URL where this list can be accessed.
maxLength: 5000
type: string
required:
- data
- has_more
- object
- url
type: object
x-expandableFields:
- data
description: Successful response.
default:
content:
application/json:
schema:
"$ref": "#/components/schemas/error"
description: Error response. The generated function is as follows, note the ///<summary>
///&lt;p&gt;Returns a list of people associated with the account’s legal entity. The people are returned sorted by creation date, with the most recent people appearing first.&lt;/p&gt;
///</summary>
///<param name="endingBefore">A cursor for use in pagination. `ending_before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with `obj_bar`, your subsequent call can include `ending_before=obj_bar` in order to fetch the previous page of the list.</param>
///<param name="expand">Specifies which fields in the response should be expanded.</param>
///<param name="limit">A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.</param>
///<param name="relationship">Filters on the list of people returned based on the person's relationship to the account's company.</param>
///<param name="startingAfter">A cursor for use in pagination. `starting_after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with `obj_foo`, your subsequent call can include `starting_after=obj_foo` in order to fetch the next page of the list.</param>
member this.GetAccountPeople
(
?endingBefore: string,
?expand: list<string>,
?limit: int,
?relationship: Newtonsoft.Json.Linq.JObject, // a default JObject is generated here, but wrecks the calls later on
?startingAfter: string
) =
async {
let requestParts =
[ if endingBefore.IsSome then
RequestPart.query ("ending_before", endingBefore.Value)
if expand.IsSome then
RequestPart.query ("expand", expand.Value)
if limit.IsSome then
RequestPart.query ("limit", limit.Value)
if relationship.IsSome then
RequestPart.query ("relationship[director]", relationship.Value.director) // this is problematic
RequestPart.query ("relationship[executive]", relationship.Value.executive)// and this
RequestPart.query ("relationship[owner]", relationship.Value.owner) // and this
RequestPart.query ("relationship[representative]", relationship.Value.representative) // and this
if startingAfter.IsSome then
RequestPart.query ("starting_after", startingAfter.Value) ]
let! (status, content) = OpenApiHttp.getAsync httpClient "/v1/account/people" requestParts
if status = HttpStatusCode.OK then
return GetAccountPeople.OK(Serializer.deserialize content)
else
return GetAccountPeople.DefaultResponse(Serializer.deserialize content)
} |
Hi @abelbraaksma, thanks again for digging into this 🙏 I understand the problem here it seems that Hawaii is not adequate enough to account for Stripe API at the moment. Requiring an ///<summary>
///&lt;p&gt;Returns a list of people associated with the account’s legal entity. The people are returned sorted by creation date, with the most recent people appearing first.&lt;/p&gt;
///</summary>
///<param name="endingBefore">A cursor for use in pagination. `ending_before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with `obj_bar`, your subsequent call can include `ending_before=obj_bar` in order to fetch the previous page of the list.</param>
///<param name="expand">Specifies which fields in the response should be expanded.</param>
///<param name="limit">A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.</param>
///<param name="relationship">Filters on the list of people returned based on the person's relationship to the account's company.</param>
///<param name="startingAfter">A cursor for use in pagination. `starting_after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with `obj_foo`, your subsequent call can include `starting_after=obj_foo` in order to fetch the next page of the list.</param>
member this.GetAccountPeople
(
?endingBefore: string,
?expand: list<string>,
?limit: int,
?relationship: GetAccountPeopleRelationshipInput,
?startingAfter: string
) =
async {
let requestParts =
[ if endingBefore.IsSome then
RequestPart.query ("ending_before", endingBefore.Value)
if expand.IsSome then
RequestPart.query ("expand", expand.Value)
if limit.IsSome then
RequestPart.query ("limit", limit.Value)
if relationship.IsSome then
RequestPart.query ("relationship[director]", relationship.Value.director) // this is problematic
RequestPart.query ("relationship[executive]", relationship.Value.executive)// and this
RequestPart.query ("relationship[owner]", relationship.Value.owner) // and this
RequestPart.query ("relationship[representative]", relationship.Value.representative) // and this
if startingAfter.IsSome then
RequestPart.query ("starting_after", startingAfter.Value) ]
let! (status, content) = OpenApiHttp.getAsync httpClient "/v1/account/people" requestParts
if status = HttpStatusCode.OK then
return GetAccountPeople.OK(Serializer.deserialize content)
else
return GetAccountPeople.DefaultResponse(Serializer.deserialize content)
} In any case, a simpler solution is to change the indexers from say RequestPart.query ("relationship[director]", relationship.Value.director) to RequestPart.query ("relationship[director]", relationship.Value.["director"].ToObject<string>()) At the moment, I am very low on time to pick up this issue but always happy to accept PRs and review/merge them 😄 |
wait, does it or does it not support .yaml files? Im getting this error with a very simple API doc |
I got this error: |
Hi @Zaid-Ajaj, I was trying out this awesome project to create a client for Stripe (using this: https://github.com/stripe/openapi/blob/master/openapi/spec3.yaml), which has an OpenApi spec in JSON and YAML. However, either way I try it,
hawaii
crashes with the following exception:This exception appears to incorrectly render the path/file name that causes the error, and "line 0, pos 0" suggests something odd is going on.
Tbh, I'm fully aware that this is a massive API from Stripe, so I wouldn't entirely expect it to go as smoothly as any smaller API. Though I also tried it with some smaller APIs and still got the same error, so maybe something else is the matter. To that end, this is the config I was using:
EDIT: I get exactly the same error when I use
"schema": "thisfiledoesnotexist.yml"
, in other words, this appears to happen prior to opening the file, as with a non-existing file I receive the same error...Version of Hawaii:
The text was updated successfully, but these errors were encountered: