I'm trying to write a basic REST-style query for a database in Go. I've never worked with REST before, so I'm a bit unclear as to how deeply the principle about being able to handle any kind of data is supposed to go. Does it violate the principle to make assumptions about the data/data types I'm getting from the database in the code for the client? Should I write the former or the latter struct to unpack the JSON data into?
type datum struct {
ID int16 `json:"src_id"`
Time int64 `json:"timestamp"`
Lat float64 `json:"latitude"`
Long float64 `json:"longitude"`
Thermo float64 `json:"ir_thermo_temperature_filtered"`
Humid float64 `json:"relative_humidity"`
AirTemp float64 `json:"air_temp"`
Wind float64 `json:"wind_speed_world_filtered"`
}
type datum struct {
ID interface{} `json:"src_id"`
Time interface{} `json:"timestamp"`
Lat interface{} `json:"latitude"`
Long interface{} `json:"longitude"`
Thermo interface{} `json:"ir_thermo_temperature_filtered"`
Humid interface{} `json:"relative_humidity"`
AirTemp interface{} `json:"air_temp"`
Wind interface{} `json:"wind_speed_world_filtered"`
}
My thinking is that maybe the latter struct violates REST principles because it makes assumptions about the data types that you'd be receiving from the server, so it isn't properly uniform. I'm hoping I'm not correct, but I can see that conclusion could come from a strict reading of the REST principles.
I believe you are reading REST principles incorrectly.
REST is an architecture, not a protocol with strict rules. The key points are that it is stateless and that it represents the underlying resources similar to how the web operates.
REST describes resources (datum, in your case), how you can access and modify those resources, and how those resources should describe what other resources can be accessed relative to that resource. This is similar to how web browsing works: each page has a unique URI, and the page may contain data (fields of datum), and links to other pages you can reach from that page.
So in your case, the fields of datum is analogous to the contents of a web page. If you have other resources reachable from the datum, then you have to provide those as URIs to the caller, and the caller can follow them. That doesn't mean that you have to give up type safety and deal with all kinds of data. Again, this is not a protocol. If the information submitted is not in the expected format, you should return an error. Since your communication format is JSON, your data types are limited to a string, number, and boolean. You are expecting an integer for ID, and if the client sends you a string (even if it is something like "123"), it is an error. Use the first struct, if unmarshaling the input returns an error, return that to the caller.
Related
I have a messaging app, where I have a Chats collection in my Firebase Firestore database. I use a custom object which is Codable to read and write changes to firebase.
struct ChatFirebaseDO: Codable {
#DocumentID var id: String?
... {100 other fields} ...
var lastMessageDate: Date
}
When a user sends a new message, I update this lastMessageDate with the FieldValue.serverTimestamp()
I also have a listener which is listening for changes, and it immediately returns any update to me (wnether that is a new Chat of an update to an existing one). However if it is my own user that has created this new chat, it will be returned to me with a null timestamp.
From the docs I see this is intentional behaviour. It suggests that I change replace the nulls with estimated timestamps values (perfect!) however, I can't work out how to combine this with my custom objects.
To get the estimated timestamps, I need to do this:
diff.document.data(with: .estimate)
which returns a dictionary of fields.
But for my Codable custom objects to work, I have to use:
let messageDO = try diff.document.data(as: ChatFirebaseDO.self)
which uses a document (not a dictionary of data).
Is there a way I can (1) replace the nulls with estimated timestamps but (2) still have a document object I can use for my custom object transformation.
Perhaps its a global setting I can make to use estimates, or locally within a single listener request. Or perhaps it is a way to use custom objects from a data dictionary and not just from the FIRDocument.
Thank you in advance!
If you're not encoding these chats for disk storage then why are they even Codable is a question to ask yourself. This particular method is made for that purpose so I'd argue you're using the wrong tool for the job—a tool that also doesn't work because of the timestamp conflict, which I imagine will be addressed in a future update to Firestore.
That said, the timestamps (which are tokens) only return nil when they haven't reached the server which means only from latency-compensated snapshots generated by the client (or only when the signed-in user posts). Therefore, you can provide your own estimate when the value is nil (which would be the current date and time), which would not only be accurate but would be overwritten by the subsequent snapshot anyway when it has a real value. It's not a pleasant workaround but it accomplishes exactly what the token does with its own estimate.
If you don't want to ditch Codable then you can ditch Firestore's timestamp, which I've personally done. I'm not a fan of the token system and I've replaced it with a basic Unix Timestamp (an integer) that makes things much simpler. I don't have to worry about nil times, latency-compensated returns, or configuring snapshot data just to handle the value of a single field. If I had to guess, I would imagine Firestore will eventually allow a global setting of timestamp behavior in addition to expanding the API to allow the Codable method to also account for timestamp behavior. The TLDR of it is that what you want doesn't yet exist natively in the Firestore SDK, unfortunately, and I'd consider making it a feature request on the Firestore-iOS git repo.
I have the following route with cars as a collection resource.
/api/v4/cars
/api/v4/cars/{carId}
Now I want to introduce a "Price per car", but this price is dependent on the input, not fixed. So when the user calls the pricing endpoint, it should send some data ex. color, enginse size etc. which then would determine the price for a car X.
My question now is, how this route should look like?
Does one of those make sense, what is the general approach one should take in such cases:
/api/v4/cars/{carId}/price
/api/v4/cars/{carId}/calculatePrice
/api/v4/cars/{carId}/getPrice
So when the user calls the pricing endpoint, it should send some data ex. color, engines size etc. which then would determine the price for a car X.
Sounds like submitting a web form; on the web, you would end up with the data appearing as encoded key value pairs in the URI.
GET /2c5d1cd4-0259-4c2b-9ca3-6215426732b8?color=red&transmission=automatic
Aside from the fact that browsers already know how to encode form values into a query string, there's no particular advantage to using a query; you could do path segments instead if you wanted to
GET /2c5d1cd4-0259-4c2b-9ca3-6215426732b8/color/red/transmission/automatic
Clients that understand how URI templates work can handle just about any layout of information you are interested in. HTML processing on the web isn't quite sophisticated enough to handle arbitrary uri templates; encoded key value pairs is a nice answer if you care about those use cases.
/api/v4/cars/{carId}/price
/api/v4/cars/{carId}/calculatePrice
/api/v4/cars/{carId}/getPrice
These are all "fine"; consumer code really doesn't care. A key idea to keep in mind is that a URI is an identifier; which is to say it is the name of the document (resource) that it fetches. If you have a clear understanding of your domain, it should be relatively straight forward to work out what the name of the document is, and choose an identifier spelling that makes understanding/remembering/guessing easier for human beings.
I'm looking at the posibility of porting a lot of our REST API services to a gRPC schema, but here is the thing.
We currently make heavy use of one method of the API, that makes calls to multiple PostgreSQL functions based on the name of the function received as a parameter and the input as the body of the request, ie: api.com/functions/exec/{name}, the functions defined in the DB recieves and returns JSON.
So, if I understood well, a gRPC method can only have a static data structure both for receiving and returning types. How can i make it flexible?, because depends on the DB function to be called the data structure to be returned and sent as input
The structure returned by the API is something like
{
"code": 200,
"data": {
"some": "value"
},
"status": "Correct..blabla"
}
The structure of the data sent to the API depends on the mode to be used if it's encrypted the request body will be a binary string
a37163b25ed49d6f04249681b9145f63f64d84a486e234fa397f134f8b25fd62f1e755e40c09da09f9900beea4b51fc638e7db8730945bd319600943e01d10f2512fa6ab335fb65de32fc2ee0a2150f7987ae0999ea5d8d09e1125c533e7803ba9118ee5aff124282149792a33dce992385969b9df2417613cd2b039bf6056998469dfb015eade9585cb160275ec83de06d027180818652c60c09ada1c98d6e9ed11df9da737408e14161ae00aaf9d4568a015dc6b6d267f1ee04638dd60e4007dc543524b83ca6b2752c5f21e9dfff3b15e6e55db8b9be9e8c07d64ccd1b3d44ce48cc3e49daee5ae1da5186d9ef6994ccf41dc86a4e289fdbab8ca4a397f929445c42f40268ebb2c3d8bcb80f9e844dba55020da665bce887bd237ae2699876e12cc0043b91578f9df2d76391d50fbf8d19b6969
if it's not encrypted then it's just common JSON
{
"one": "parameter"
}
One possible solution that I can think of, is to use always a type byte, both on the request and the response types, the only thing that I have to do is convert JSON to a binary string and vice-versa right?
I'm open to suggestions.
Depending on your needs and performance requirements, going the raw bytes route might be sensible, if you really don't have any other uses for protobuf fields. If you do, you might want to define a message type that supports encrypted and unencrypted message fields like: https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto#L77
I'm writing a REST service which is dealing with SomeKindOfResource stored in a database.
Don't ask me why (don't!) but for some reasons, the corresponding underlying table has a variable number of columns. That's the way it is and I can't change it.
Therefore, when I issue a GET /SomeKindOfResources/{id}, my DTO (later on serialized to JSON) might then contain a variable number of "fields". I know how to handle the dynamic object / serialization parts. My question is more on the philosophy side of things.
Let's say my client wants to know what will be the list of fields returned by a call to GET /SomeKindOfResources/{id} because, for example, that list determines what can be used, later-on, to filter out a list of SomeKindOfResources. Basically, I need something resembling a "GetCapability".
How would you deal with such a scenario in a RESTful way?
If I understand your requirement correctly, you want to return a metadata like response for a specific object (i.e. by Id) that has dynamic fields, so your client knows the field types it will receive when requesting that object.
Just a word of caution: A dynamic DTO isn't RESTful. The point of a DTO is that it is an agreed contract. It shouldn't change and as such there isn't a RESTful rule to handle your use case.
If you were to implement this, these are three possible approaches.
Metadata Route:
Create a new route, in your service, as this scenario isn't covered by the standard ServiceStack MetadataFeature, as it only works with static DTOs. So create something like this:
[Route("/SomeKindOfResources/{Id}/metadata", "GET"]
Then you would want the response to that route to describe the fields to your client. This is where it gets cloudy. The MetaDataFeature uses XSD to describe your standard DTOs, you could write your action to produce an XSD response which would describe your fields, based on your database lookup of available fields. But then will your client know how to parse XSD? As your use isn't standard, and the client can't be expected to handle it in a RESTful way, so you may just want to use a simple response type, like a Dictionary<string,Type>() essentially just returning field name, and underlying type. This will work fine for simple built in types, like string, int, bool etc, but custom class scenarios will be harder to handle, such as List<MySpecialType>.
Pseudo client code:
var fieldMetaData = client.get("/SomeKindOfResources/123/metadata");
var result = client.get("/SomeKingOfResources/123");
Example XSD Metadata Response.
OPTIONS header:
However you may wish to consider using the OPTIONS verb instead of a GET request to another prepended with /metadata, as recommended by RFC2616 §9.
This method allows the client to determine the options and/or requirements associated with a resource ... without implying a resource action or initiating a resource retrieval.
Pseudo client code:
var fieldMetaData = client.options("/SomeKindOfResources/123");
var result = client.get("/SomeKindOfResources/123");
But remember OPTIONS in REST is typically used for setting up CORS.
ServiceStack JSON __type response:
When ServiceStack returns JSON, you can tell the ServiceStack.Text serializer to include the return type information in a property call __type. Although this may not be easy for your clients to interpret, and it also applies globally to all JSON responses, so wouldn't be limited to just that action. In your configure method add:
JsConfig.IncludeTypeInfo = true;
Pseudo client code:
var result = client.get("/SomeKingOfResources/123");
var typeInformation = result.__type;
We are creating a service to perform conversions from one format to another. Examples of conversions are currencies, distances, times, languages, etc. In our case it is geographic points (for example from decimal degrees latitude/longitude to degrees-minutes-seconds latitude/longitude).
Typically a RESTful resource has an analogous OO concept that is persistent on the server side that can be CRUDed (I know this is only part of what makes something RESTful), but in the case of a simple service that converts things, that doesn't necessarily exist. How would one make this RESTful? Currently we have some like this:
To get the list of supported formats one can do this:
GET /coordinates/formats
Which would return a list of formats, including, for example DD and DMS (decimal degrees and degrees-minutes-seconds).
One can then turn around and perform a conversion like so:
POST /coordinates/DD/as/DMS
In this example one would pass a representation of decimal degrees (as JSON or some other format) in the request body, and receive a representation of degrees-minutes-seconds in the response body.
This of course works, but feels unRESTful, in particular because the same URI is used over and over for different inputs (different decimal degrees). The trick is probably to really concentrate on what the resource being manipulated it. Perhaps its a "Conversion":
POST /coordinate/conversions
The body might take in the a value, its format, and the desired output. However, the URI is still the same for all resources...
Thoughts?
I would suggest using parameters and GET. I also would switch path elements and make /conversions your root-resource, as conversion is your "domain-core".
Main reasons are:
From api-client perspective above is easier to use (no POST payload, very easy to test/try-out). Client friendliness is one of the highest priorities for api-design.
GET fits better because you don't "change" anything on the server side but rather convert things.
GET /conversions/coordinate?input=xxx&format=yyy
I like your approach to give back metadata with /conversions/formats. It makes formats easy to lookup and your api more self-explainable. The respective data then forms the possible value for 'format'-parameter from above call.
Or are you storing conversion (which would favor state-changing POST method)?